AsphyreWireframe.pas
上传用户:ctlcnc
上传日期:2021-12-10
资源大小:4933k
文件大小:15k
源码类别:

2D图形编程

开发平台:

Delphi

  1. unit AsphyreWireframe;
  2. //---------------------------------------------------------------------------
  3. // AsphyreBillboards.pas                                Modified: 10-Mar-2007
  4. // Asphyre billboards                                             Version 1.0
  5. //---------------------------------------------------------------------------
  6. // Important Notice:
  7. //
  8. // If you modify/use this code or one of its parts either in original or
  9. // modified form, you must comply with Mozilla Public License v1.1,
  10. // specifically section 3, "Distribution Obligations". Failure to do so will
  11. // result in the license breach, which will be resolved in the court.
  12. // Remember that violating author's rights is considered a serious crime in
  13. // many countries. Thank you!
  14. //
  15. // !! Please *read* Mozilla Public License 1.1 document located at:
  16. //  http://www.mozilla.org/MPL/
  17. //
  18. // If you require any clarifications about the license, feel free to contact
  19. // us or post your question on our forums at: http://www.afterwarp.net
  20. //---------------------------------------------------------------------------
  21. // The contents of this file are subject to the Mozilla Public License
  22. // Version 1.1 (the "License"); you may not use this file except in
  23. // compliance with the License. You may obtain a copy of the License at
  24. // http://www.mozilla.org/MPL/
  25. //
  26. // Software distributed under the License is distributed on an "AS IS"
  27. // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  28. // License for the specific language governing rights and limitations
  29. // under the License.
  30. //
  31. // The Original Code is AsphyreBillboards.pas.
  32. //
  33. // The Initial Developer of the Original Code is M. Sc. Yuriy Kotsarenko.
  34. // Portions created by M. Sc. Yuriy Kotsarenko are Copyright (C) 2007,
  35. // Afterwarp Interactive. All Rights Reserved.
  36. //---------------------------------------------------------------------------
  37. interface
  38. //---------------------------------------------------------------------------
  39. uses
  40.  Windows, Direct3D9, D3DX9, Vectors3, Matrices4, AsphyreTypes, AsphyreUtils,
  41.  AsphyreDevices, AsphyreEvents;
  42. //---------------------------------------------------------------------------
  43. const
  44.  // The following parameters highly affect the rendering performance. The
  45.  // higher values means that more primitives will fit in cache, but it will
  46.  // also occupy more bandwidth, even when few primitives are rendered.
  47.  //
  48.  // These parameters can be fine-tuned in a finished product to improve the
  49.  // overall performance.
  50.  MaxCachedPrimitives = 4096;
  51.  MaxCachedIndexes    = 8192;
  52.  MaxCachedVertices   = 8192;
  53. //---------------------------------------------------------------------------
  54. type
  55.  TWireframeMode = (wmUnspecified, wmLineList, wmTriangleList);
  56. //---------------------------------------------------------------------------
  57.  TAsphyreWireframe = class
  58.  private
  59.   FDevice     : TAsphyreDevice;
  60.   VertexBuffer: IDirect3DVertexBuffer9;
  61.   IndexBuffer : IDirect3DIndexBuffer9;
  62.   VertexArray : Pointer;
  63.   IndexArray  : Pointer;
  64.   FVertexCache: Integer;
  65.   FIndexCache : Integer;
  66.   FVertexCount: Integer;
  67.   FIndexCount : Integer;
  68.   FCacheStall : Integer;
  69.   FPrimitives   : Integer;
  70.   FMaxPrimitives: Integer;
  71.   FWireframeMode: TWireframeMode;
  72.   procedure InitCacheSpec();
  73.   procedure CreateStaticObjects();
  74.   procedure DestroyStaticObjects();
  75.   procedure OnDeviceCreate(Sender: TObject; EventParam: Pointer;
  76.    var Success: Boolean); virtual;
  77.   procedure OnDeviceDestroy(Sender: TObject; EventParam: Pointer;
  78.    var Success: Boolean); virtual;
  79.   function CreateDynamicBuffers(): Boolean;
  80.   procedure DestroyDynamicBuffers();
  81.   procedure OnDeviceReset(Sender: TObject; EventParam: Pointer;
  82.    var Success: Boolean); virtual;
  83.   procedure OnDeviceLost(Sender: TObject; EventParam: Pointer;
  84.    var Success: Boolean); virtual;
  85.   function UploadVertexBuffer(): Boolean;
  86.   function UploadIndexBuffer(): Boolean;
  87.   function PrepareDraw(): Boolean;
  88.   function BufferDraw(): Boolean;
  89.   procedure RequestCache(Mode: TWireframeMode; Vertices, Indices: Integer);
  90.   function NextVertexEntry(): Pointer;
  91.   procedure AddIndexEntry(Index: Integer);
  92.  public
  93.   property Device: TAsphyreDevice read FDevice;
  94.   property WireframeMode: TWireframeMode read FWireframeMode;
  95.   property CacheStall: Integer read FCacheStall;
  96.   procedure DrawRect(const Pos, Vec1, Vec2: TVector3; const Colors: TColor4);
  97.   procedure DrawWire(const Pos, Vec1, Vec2: TVector3; const Colors: TColor4);
  98.   procedure DrawLine(const v0, v1: TVector3; Color: Cardinal);
  99.   procedure FlushCache();
  100.   constructor Create(ADevice: TAsphyreDevice);
  101.   destructor Destroy(); override;
  102.  end;
  103. //---------------------------------------------------------------------------
  104. implementation
  105. //----------------------------------------------------------------------------
  106. const
  107.  VertexType = D3DFVF_XYZ or D3DFVF_DIFFUSE;
  108. //--------------------------------------------------------------------------
  109. type
  110. //--------------------------------------------------------------------------
  111.  PVertexRecord = ^TVertexRecord;
  112.  TVertexRecord = record
  113.   Vertex : TVector3;
  114.   Diffuse: Longword;
  115.  end;
  116. //---------------------------------------------------------------------------
  117. constructor TAsphyreWireframe.Create(ADevice: TAsphyreDevice);
  118. begin
  119.  inherited Create();
  120.  FDevice:= ADevice;
  121.  EventDeviceCreate.Subscribe(OnDeviceCreate, FDevice);
  122.  EventDeviceDestroy.Subscribe(OnDeviceDestroy, FDevice);
  123.  EventDeviceReset.Subscribe(OnDeviceReset, FDevice);
  124.  EventDeviceLost.Subscribe(OnDeviceLost, FDevice);
  125.  VertexArray := nil;
  126.  IndexArray  := nil;
  127.  VertexBuffer:= nil;
  128.  IndexBuffer := nil;
  129. end;
  130. //---------------------------------------------------------------------------
  131. destructor TAsphyreWireframe.Destroy();
  132. begin
  133.  DestroyDynamicBuffers();
  134.  DestroyStaticObjects();
  135.  EventDeviceLost.Unsubscribe(OnDeviceLost);
  136.  EventDeviceReset.Unsubscribe(OnDeviceReset);
  137.  EventDeviceDestroy.Unsubscribe(OnDeviceDestroy);
  138.  EventDeviceCreate.Unsubscribe(OnDeviceCreate);
  139.  inherited;
  140. end;
  141. //---------------------------------------------------------------------------
  142. procedure TAsphyreWireframe.InitCacheSpec();
  143. begin
  144.  with FDevice.Caps9 do
  145.   begin
  146.    FMaxPrimitives:= Min2(MaxPrimitiveCount, MaxCachedPrimitives);
  147.    FVertexCache:= Min2(MaxVertexIndex, MaxCachedVertices);
  148.    FIndexCache:= Min2(MaxVertexIndex, MaxCachedIndexes);
  149.   end;
  150. end;
  151. //---------------------------------------------------------------------------
  152. procedure TAsphyreWireframe.CreateStaticObjects();
  153. begin
  154.  ReallocMem(VertexArray, FVertexCache * SizeOf(TVertexRecord));
  155.  FillChar(VertexArray^, FVertexCache * SizeOf(TVertexRecord), 0);
  156.  ReallocMem(IndexArray, FIndexCache * SizeOf(Word));
  157.  FillChar(IndexArray^, FIndexCache * SizeOf(Word), 0);
  158. end;
  159. //---------------------------------------------------------------------------
  160. procedure TAsphyreWireframe.DestroyStaticObjects();
  161. begin
  162.  if (IndexArray <> nil) then
  163.   begin
  164.    FreeMem(IndexArray);
  165.    IndexArray:= nil;
  166.   end;
  167.  if (VertexArray <> nil) then
  168.   begin
  169.    FreeMem(VertexArray);
  170.    VertexArray:= nil;
  171.   end;
  172. end;
  173. //---------------------------------------------------------------------------
  174. procedure TAsphyreWireframe.OnDeviceCreate(Sender: TObject; EventParam: Pointer;
  175.  var Success: Boolean);
  176. begin
  177.  Success:= (FDevice <> nil)and(FDevice is TAsphyreDevice);
  178.  if (Success) then
  179.   begin
  180.    InitCacheSpec();
  181.    CreateStaticObjects();
  182.   end;
  183. end;
  184. //--------------------------------------------------------------------------
  185. function TAsphyreWireframe.CreateDynamicBuffers(): Boolean;
  186. begin
  187.  // -> Dynamic Vertex Buffer
  188.  Result:= Succeeded(TAsphyreDevice(FDevice).Dev9.CreateVertexBuffer(FVertexCache *
  189.   SizeOf(TVertexRecord), D3DUSAGE_WRITEONLY or D3DUSAGE_DYNAMIC, VertexType,
  190.   D3DPOOL_DEFAULT, VertexBuffer, nil));
  191.  if (not Result) then Exit;
  192.  // -> Dynamic Index Buffer
  193.  Result:= Succeeded(TAsphyreDevice(FDevice).Dev9.CreateIndexBuffer(FIndexCache *
  194.   SizeOf(Word), D3DUSAGE_WRITEONLY or D3DUSAGE_DYNAMIC, D3DFMT_INDEX16,
  195.   D3DPOOL_DEFAULT, IndexBuffer, nil));
  196. end;
  197. //---------------------------------------------------------------------------
  198. procedure TAsphyreWireframe.DestroyDynamicBuffers();
  199. begin
  200.  if (IndexBuffer <> nil) then IndexBuffer:= nil;
  201.  if (VertexBuffer <> nil) then VertexBuffer:= nil;
  202. end;
  203. //---------------------------------------------------------------------------
  204. procedure TAsphyreWireframe.OnDeviceDestroy(Sender: TObject; EventParam: Pointer;
  205.  var Success: Boolean);
  206. begin
  207.  DestroyStaticObjects();
  208. end;
  209. //---------------------------------------------------------------------------
  210. procedure TAsphyreWireframe.OnDeviceReset(Sender: TObject; EventParam: Pointer;
  211.  var Success: Boolean);
  212. begin
  213.  Success:= CreateDynamicBuffers();
  214. end;
  215. //---------------------------------------------------------------------------
  216. procedure TAsphyreWireframe.OnDeviceLost(Sender: TObject; EventParam: Pointer;
  217.  var Success: Boolean);
  218. begin
  219.  DestroyDynamicBuffers();
  220. end;
  221. //---------------------------------------------------------------------------
  222. function TAsphyreWireframe.UploadVertexBuffer(): Boolean;
  223. var
  224.  MemAddr: Pointer;
  225.  BufSize: Integer;
  226. begin
  227.  BufSize:= FVertexCount * SizeOf(TVertexRecord);
  228.  Result:= Succeeded(VertexBuffer.Lock(0, BufSize, MemAddr, D3DLOCK_DISCARD));
  229.  if (Result) then
  230.   begin
  231.    Move(VertexArray^, MemAddr^, BufSize);
  232.    Result:= Succeeded(VertexBuffer.Unlock());
  233.   end;
  234. end;
  235. //---------------------------------------------------------------------------
  236. function TAsphyreWireframe.UploadIndexBuffer(): Boolean;
  237. var
  238.  MemAddr: Pointer;
  239.  BufSize: Integer;
  240. begin
  241.  BufSize:= FIndexCount * SizeOf(Word);
  242.  Result:= Succeeded(IndexBuffer.Lock(0, BufSize, MemAddr, D3DLOCK_DISCARD));
  243.  if (Result) then
  244.   begin
  245.    Move(IndexArray^, MemAddr^, BufSize);
  246.    Result:= Succeeded(IndexBuffer.Unlock());
  247.   end;
  248. end;
  249. //---------------------------------------------------------------------------
  250. function TAsphyreWireframe.PrepareDraw(): Boolean;
  251. begin
  252.  with TAsphyreDevice(FDevice).Dev9 do
  253.   begin
  254.    // (1) Use our vertex buffer for displaying primitives.
  255.    Result:= Succeeded(SetStreamSource(0, VertexBuffer, 0,
  256.     SizeOf(TVertexRecord)));
  257.    // (2) Use our index buffer to indicate the vertices of our primitives.
  258.    if (Result) then
  259.     Result:= Succeeded(SetIndices(IndexBuffer));
  260.    // (3) Disable vertex shader.
  261.    if (Result) then
  262.     Result:= Succeeded(SetVertexShader(nil));
  263.    // (4) Set the flexible vertex format of our vertex buffer.
  264.    if (Result) then
  265.     Result:= Succeeded(SetFVF(VertexType));
  266.   end;
  267. end;
  268. //---------------------------------------------------------------------------
  269. function TAsphyreWireframe.BufferDraw(): Boolean;
  270. var
  271.  Primitive: TD3DPrimitiveType;
  272. begin
  273.  Primitive:= D3DPT_TRIANGLELIST;
  274.  if (FWireframeMode = wmLineList) then Primitive:= D3DPT_LINELIST;
  275.  with FDevice.Dev9 do
  276.   begin
  277.    Result:= Succeeded(DrawIndexedPrimitive(Primitive, 0, 0, FVertexCount, 0,
  278.     FPrimitives));
  279.   end;
  280. end;
  281. //---------------------------------------------------------------------------
  282. procedure TAsphyreWireframe.FlushCache();
  283. begin
  284.  if (FVertexCount > 0)and(FPrimitives > 0) then
  285.   begin
  286.    if (UploadVertexBuffer())and(UploadIndexBuffer())and(PrepareDraw()) then
  287.     BufferDraw();
  288.    Inc(FCacheStall);
  289.   end;
  290.  FVertexCount:= 0;
  291.  FIndexCount := 0;
  292.  FPrimitives := 0;
  293.  FCacheStall := 0;
  294.  FWireframeMode:= wmUnspecified;
  295. end;
  296. //---------------------------------------------------------------------------
  297. procedure TAsphyreWireframe.RequestCache(Mode: TWireframeMode; Vertices,
  298.  Indices: Integer);
  299. var
  300.  NeedReset: Boolean;
  301. begin
  302.  NeedReset:= (FVertexCount + Vertices > FVertexCache);
  303.  NeedReset:= NeedReset or (FIndexCount + Indices > FIndexCache);
  304.  NeedReset:= NeedReset or (FWireframeMode = wmUnspecified) or
  305.   (FWireframeMode <> Mode);
  306.  if (NeedReset) then
  307.   begin
  308.    FlushCache();
  309.    FWireframeMode:= Mode;
  310.   end;
  311. end;
  312. //---------------------------------------------------------------------------
  313. function TAsphyreWireframe.NextVertexEntry(): Pointer;
  314. begin
  315.  Result:= Pointer(Integer(VertexArray) + (FVertexCount * SizeOf(TVertexRecord)));
  316. end;
  317. //---------------------------------------------------------------------------
  318. procedure TAsphyreWireframe.AddIndexEntry(Index: Integer);
  319. var
  320.  Entry: PWord;
  321. begin
  322.  Entry:= Pointer(Integer(IndexArray) + (FIndexCount * SizeOf(Word)));
  323.  Entry^:= Index;
  324.  Inc(FIndexCount);
  325. end;
  326. //---------------------------------------------------------------------------
  327. procedure TAsphyreWireframe.DrawRect(const Pos, Vec1, Vec2: TVector3;
  328.  const Colors: TColor4);
  329. var
  330.  Entry: PVertexRecord;
  331. begin
  332.  RequestCache(wmTriangleList, 4, 6);
  333.  AddIndexEntry(FVertexCount + 0);
  334.  AddIndexEntry(FVertexCount + 1);
  335.  AddIndexEntry(FVertexCount + 2);
  336.  AddIndexEntry(FVertexCount + 3);
  337.  AddIndexEntry(FVertexCount + 0);
  338.  AddIndexEntry(FVertexCount + 2);
  339.  Entry:= NextVertexEntry();
  340.  Entry.Vertex := Pos - (Vec1 + Vec2);
  341.  Entry.Diffuse:= Colors[3];
  342.  Inc(FVertexCount);
  343.  Entry:= NextVertexEntry();
  344.  Entry.Vertex := Pos + Vec1 - Vec2;
  345.  Entry.Diffuse:= Colors[0];
  346.  Inc(FVertexCount);
  347.  Entry:= NextVertexEntry();
  348.  Entry.Vertex := Pos + Vec1 + Vec2;
  349.  Entry.Diffuse:= Colors[1];
  350.  Inc(FVertexCount);
  351.  Entry:= NextVertexEntry();
  352.  Entry.Vertex := Pos + Vec2 - Vec1;
  353.  Entry.Diffuse:= Colors[2];
  354.  Inc(FVertexCount);
  355.  Inc(FPrimitives, 2);
  356. end;
  357. //---------------------------------------------------------------------------
  358. procedure TAsphyreWireframe.DrawWire(const Pos, Vec1, Vec2: TVector3;
  359.  const Colors: TColor4);
  360. var
  361.  Entry: PVertexRecord;
  362. begin
  363.  RequestCache(wmLineList, 4, 8);
  364.  AddIndexEntry(FVertexCount + 0);
  365.  AddIndexEntry(FVertexCount + 1);
  366.  AddIndexEntry(FVertexCount + 1);
  367.  AddIndexEntry(FVertexCount + 2);
  368.  AddIndexEntry(FVertexCount + 2);
  369.  AddIndexEntry(FVertexCount + 3);
  370.  AddIndexEntry(FVertexCount + 3);
  371.  AddIndexEntry(FVertexCount + 0);
  372.  Entry:= NextVertexEntry();
  373.  Entry.Vertex := Pos - (Vec1 + Vec2);
  374.  Entry.Diffuse:= Colors[3];
  375.  Inc(FVertexCount);
  376.  Entry:= NextVertexEntry();
  377.  Entry.Vertex := Pos + Vec1 - Vec2;
  378.  Entry.Diffuse:= Colors[0];
  379.  Inc(FVertexCount);
  380.  Entry:= NextVertexEntry();
  381.  Entry.Vertex := Pos + Vec1 + Vec2;
  382.  Entry.Diffuse:= Colors[1];
  383.  Inc(FVertexCount);
  384.  Entry:= NextVertexEntry();
  385.  Entry.Vertex := Pos + Vec2 - Vec1;
  386.  Entry.Diffuse:= Colors[2];
  387.  Inc(FVertexCount);
  388.  Inc(FPrimitives, 4);
  389. end;
  390. //---------------------------------------------------------------------------
  391. procedure TAsphyreWireframe.DrawLine(const v0, v1: TVector3; Color: Cardinal);
  392. var
  393.  Entry: PVertexRecord;
  394. begin
  395.  RequestCache(wmLineList, 2, 2);
  396.  AddIndexEntry(FVertexCount + 0);
  397.  AddIndexEntry(FVertexCount + 1);
  398.  Entry:= NextVertexEntry();
  399.  Entry.Vertex := v0;
  400.  Entry.Diffuse:= Color;
  401.  Inc(FVertexCount);
  402.  Entry:= NextVertexEntry();
  403.  Entry.Vertex := v1;
  404.  Entry.Diffuse:= Color;
  405.  Inc(FVertexCount);
  406.  Inc(FPrimitives);
  407. end;
  408. //---------------------------------------------------------------------------
  409. end.