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

2D图形编程

开发平台:

Delphi

  1. unit AsphyreCanvas;
  2. //---------------------------------------------------------------------------
  3. // AsphyreCanvas.pas                                    Modified: 21-Feb-2007
  4. // Hardware-accelerated 2D implementation                         Version 2.1
  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 AsphyreCanvas.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, Types, Vectors2, Vectors2px, AsphyreColors,
  41.  AsphyreTypes, AsphyreUtils, AsphyreEvents, AsphyreEffects, AsphyreTextures,
  42.  AsphyreImages, AsphyrePalettes;
  43. //---------------------------------------------------------------------------
  44. // The following options control the way how primitives are rendered.
  45. // Generally, there are two ways to render a single primitive:
  46. //   a) Using lists of triangles that are cached together
  47. //   b) Using triangle strips or fans individually
  48. //
  49. // Although the second option reduces the bandwidth usage by producing
  50. // considerably less vertices (and may not need indexes at all), it is
  51. // generally much slower because of Direct3D overhead.
  52. //
  53. // Therefore, the ideal would be using option a) and drawing everything in
  54. // groups of similar primitives, e.g.: first draw all rectangles, then all
  55. // images with the same index/pattern, then all text, etc.
  56. //
  57. // However, grouping similar primitives may not be possible in some cases,
  58. // such as when drawing GUI that need to be "layered".
  59. //
  60. // The options below specify how individual primitive is rendered. Enable
  61. // each one of the option to use the option b) for rendering primitives, by
  62. // removing the dot before "$DEFINE". If you want to use option a) for
  63. // rendering, then disable the declaration by adding dot to the define,
  64. // thus effectively disabling it, e.g.:
  65. //  {.$DEFINE FillTriUncached} -> use option a) for drawing filled triangles.
  66. //  {$DEFINE FillTriUncached}  -> use option b) for drawing filled triangles.
  67. //---------------------------------------------------------------------------
  68. {.$DEFINE FillTriUncached}
  69. {.$DEFINE FillQuadUncached}
  70. {.$DEFINE FillQuadExUncached}
  71. {.$DEFINE FillArcUncached}
  72. {.$DEFINE FillRibbonUncached}
  73. {.$DEFINE FrameRibbonUncached}
  74. {.$DEFINE TexMapUncached}
  75. {.$DEFINE TexTriUncached}
  76. //---------------------------------------------------------------------------
  77. const
  78.  // The following parameters highly affect the rendering performance. The
  79.  // higher values means that more primitives will fit in cache, but it will
  80.  // also occupy more bandwidth, even when few primitives are rendered.
  81.  //
  82.  // These parameters can be fine-tuned in a finished product to improve the
  83.  // overall performance. 
  84.  MaxCachedPrimitives = 2048;
  85.  MaxCachedIndexes    = 4096;
  86.  MaxCachedVertices   = 4096;
  87. //---------------------------------------------------------------------------
  88. type
  89.  TDrawingMode = (dmUnspecified, dmPointList, dmLineList, dmLineStrip,
  90.   dmTriangleList, dmTriangleStrip, dmTriangleFan);
  91. //---------------------------------------------------------------------------
  92.  TAsphyreCanvas = class
  93.  private
  94.   FDevice: TObject;
  95.   VertexBuffer: IDirect3DVertexBuffer9;
  96.   IndexBuffer : IDirect3DIndexBuffer9;
  97.   DXLine      : ID3DXLine;
  98.   VertexArray : Pointer;
  99.   IndexArray  : Pointer;
  100.   FDrawingMode: TDrawingMode;
  101.   FIndexedMode: Boolean;
  102.   FVertexCache: Integer;
  103.   FIndexCache : Integer;
  104.   FVertexCount: Integer;
  105.   FIndexCount : Integer;
  106.   FPrimitives   : Integer;
  107.   FMaxPrimitives: Integer;
  108.   FCacheStall : Integer;
  109.   FDithering  : Boolean;
  110.   FAntialias  : TAntialiasType;
  111.   FAlphaTest  : Boolean;
  112.   CachedDrawFx: Integer;
  113.   CachedTex   : TAsphyreCustomTexture;
  114.   ActiveTex   : TAsphyreCustomTexture;
  115.   QuadMapping : TPoint4;
  116.   FClipRect   : TRect;
  117.   FMipMapping: TMipmappingType;
  118.   procedure InitCacheSpec();
  119.   function CreateStaticObjects(): Boolean;
  120.   procedure DestroyStaticObjects();
  121.   procedure PrepareVertexArray();
  122.   procedure OnDeviceCreate(Sender: TObject; EventParam: Pointer;
  123.    var Success: Boolean);
  124.   procedure OnDeviceDestroy(Sender: TObject; EventParam: Pointer;
  125.    var Success: Boolean);
  126.   function CreateDynamicBuffers(): Boolean;
  127.   procedure DestroyDynamicBuffers();
  128.   procedure ResetDeviceStates();
  129.   procedure OnDeviceReset(Sender: TObject; EventParam: Pointer;
  130.    var Success: Boolean);
  131.   procedure OnDeviceLost(Sender: TObject; EventParam: Pointer;
  132.    var Success: Boolean);
  133.   procedure SetAntialias(const Value: TAntialiasType);
  134.   procedure SetMipmapping(const Value: TMipmappingType);
  135.   procedure SetDithering(const Value: Boolean);
  136.   function GetLineAntialias(): Boolean;
  137.   function GetLineWidth(): Real;
  138.   procedure SetLineAntialias(const Value: Boolean);
  139.   procedure SetLineWidth(const Value: Real);
  140.   function GetClipRect(): TRect;
  141.   procedure SetClipRect(const Value: TRect);
  142.   procedure OnEndScene(Sender: TObject; EventParam: Pointer;
  143.    var Success: Boolean);
  144.  protected
  145.   AfterFlush: Boolean;
  146.   function UploadVertexBuffer(): Boolean; virtual;
  147.   function UploadIndexBuffer(): Boolean; virtual;
  148.   function PrepareDraw(): Boolean; virtual;
  149.   function BufferDraw(): Boolean; virtual;
  150.   procedure ResetCache(); virtual;
  151.   function NextVertexEntry(): Pointer;
  152.   procedure AddIndexEntry(Index: Integer);
  153.   procedure RequestCache(Mode: TDrawingMode; Indexed: Boolean; Vertices,
  154.    Indices, DrawFx: Integer; ReqTex: TAsphyreCustomTexture); virtual;
  155.  public
  156.   // This property should always point to a valid and active TAsphyreDevice.
  157.   property Device: TObject read FDevice;
  158.   // The following properties indicate the current type of buffer cache.
  159.   property DrawingMode: TDrawingMode read FDrawingMode;
  160.   property IndexedMode: Boolean read FIndexedMode;
  161.   //-------------------------------------------------------------------------
  162.   // The following parameters indicate the cache characteristics.
  163.   //-------------------------------------------------------------------------
  164.   property VertexCache: Integer read FVertexCache;
  165.   property IndexCache : Integer read FIndexCache;
  166.   property VertexCount: Integer read FVertexCount;
  167.   property IndexCount : Integer read FIndexCount;
  168.   property Primitives   : Integer read FPrimitives;
  169.   property MaxPrimitives: Integer read FMaxPrimitives;
  170.   // Whether the image should be antialiased while rendering.
  171.   property Antialias : TAntialiasType read FAntialias write SetAntialias;
  172.   property MipMapping: TMipmappingType read FMipMapping write SetMipmapping;
  173.   // Whether the image should be dithered, when rendered on lower-quality
  174.   // surface.
  175.   property Dithering: Boolean read FDithering write SetDithering;
  176.   // Enable this option to discard the pixels with alpha = 0. This can
  177.   // improve the performance slightly when drawing many transparent sprites.
  178.   property AlphaTest: Boolean read FAlphaTest write FAlphaTest;
  179.   // The clipping rectangle used for rendering. Nothing will be visible
  180.   // outside of this rectangle.
  181.   property ClipRect: TRect read GetClipRect write SetClipRect;
  182.   // Parameters that indicate the appearance of lines when drawing them
  183.   // using methods ending with "Ex", e.g. LineEx().
  184.   property LineWidth    : Real read GetLineWidth write SetLineWidth;
  185.   property LineAntialias: Boolean read GetLineAntialias write SetLineAntialias;
  186.   // Indicates how many times the buffer has been flushed out inside current
  187.   // scene block.
  188.   property CacheStall: Integer read FCacheStall;
  189.   // Flushes the buffer cache.
  190.   procedure Flush(); virtual;
  191.   // Pixel drawing routines.
  192.   procedure PutPixel(const Point: TPoint2; Color: Cardinal;
  193.    DrawFx: Integer); overload;
  194.   procedure PutPixel(x, y: Single; Color: Cardinal; DrawFx: Integer); overload;
  195.   // Line drawing routines which support antialiased lines with custom width.
  196.   procedure LineEx(const Src, Dest: TPoint2; Color: Cardinal); overload;
  197.   procedure LineEx(x1, y1, x2, y2: Single; Color: Cardinal); overload;
  198.   procedure LineEx(const Src, Dest: TPoint; Color: Cardinal); overload;
  199.   // Hardware line drawing routines. These are much faster than LineEx,
  200.   // but they are not always antialiased and you can't change their width.
  201.   procedure LineHw(const Src, Dest: TPoint2; Color0, Color1: Cardinal;
  202.    DrawFx: Integer); overload;
  203.   procedure LineHw(x1, y1, x2, y2: Single; Color0, Color1: Cardinal;
  204.    DrawFx: Integer); overload;
  205.   procedure LineHw(const Src, Dest: TPoint; Color0, Color1: Cardinal;
  206.    DrawFx: Integer); overload;
  207.   // These routines render filled triangles.
  208.   procedure FillTri(const p1, p2, p3: TPoint2; c1, c2, c3: Cardinal;
  209.    DrawFx: Integer); overload;
  210.   procedure FillTri(x1, y1, x2, y2, x3, y3: Single; c1, c2, c3: Cardinal;
  211.    DrawFx: Integer); overload;
  212.   // This routine renders filled quad.
  213.   procedure FillQuad(const Points: TPoint4; const Colors: TColor4;
  214.    DrawFx: Integer);
  215.   // This does the same job as FillQuad(), but uses subdivision to provide
  216.   // better gradient-filling precision. It draws 6 triangles instead of 2.
  217.   procedure FillQuadEx(const Points: TPoint4; const Colors: TColor4;
  218.    DrawFx: Integer);
  219.   // Draws lines along the specified 4 corners to complete a rectangle.
  220.   // This uses hardware lines (e.g. LineHw). 
  221.   procedure WireQuadHw(const Points: TPoint4; const Colors: TColor4;
  222.    DrawFx: Integer);
  223.   // Draws lines across four specified points using LineEx() approach. 
  224.   procedure WireQuadEx(const Points: TPoint4; Color: Cardinal);
  225.   // Draw a triangle frame using LineEx() method.
  226.   procedure WireTriEx(const p1, p2, p3: TPoint2; Color: Cardinal);
  227.   // The following functions call FillQuad() to render filled rectangles. 
  228.   procedure FillRect(const Rect: TRect; const Colors: TColor4;
  229.    DrawFx: Integer); overload;
  230.   procedure FillRect(const Rect: TRect; Color: Cardinal;
  231.    DrawFx: Integer); overload;
  232.   procedure FillRect(Left, Top, Width, Height: Integer; Color: Cardinal;
  233.    DrawFx: Integer); overload;
  234.   // The following routines draw rectangles using WireQuadHw.
  235.   procedure FrameRect(const Rect: TRect; const Colors: TColor4;
  236.    DrawFx: Integer); overload;
  237.   procedure FrameRect(const Rect: TRect; Color: Cardinal;
  238.    DrawFx: Integer); overload;
  239.   procedure FrameRect(Left, Top, Width, Height: Integer; Color: Cardinal;
  240.    DrawFx: Integer); overload;
  241.   // Draws a filled arc.
  242.   procedure FillArc(x, y, RadiusX, RadiusY, InitPhi, EndPhi: Single;
  243.    Steps: Integer; const Colors: TColor4; DrawFx: Integer);
  244.   // The following routines draw filled ellipses and circles.
  245.   procedure FillEllipse(x, y, RadiusX, RadiusY: Single; Steps: Integer;
  246.    const Colors: TColor4; DrawFx: Integer);
  247.   procedure FillCircle(x, y, Radius: Single; Steps: Integer;
  248.    const Colors: TColor4; DrawFx: Integer); overload;
  249.   // The following routines draw ellipses and circles using LineEx routines.
  250.   procedure Ellipse(x, y, RadiusX, RadiusY: Single; Steps: Integer;
  251.    Color: Cardinal);
  252.   procedure Circle(x, y, Radius: Single; Steps: Integer; Color: Cardinal);
  253.   // The following routines draw a filled-ribbon, which is an arc with a
  254.   // hole inside it.
  255.   procedure FillRibbon(x, y, InRadiusX, InRadiusY, OutRadiusX, OutRadiusY,
  256.    InitPhi, EndPhi: single; Steps: Integer; const Colors: TColor4;
  257.    DrawFx: Integer); overload;
  258.   procedure FillRibbon(x, y, InRadiusX, InRadiusY, OutRadiusX, OutRadiusY,
  259.    InitPhi, EndPhi: Single; Steps: Integer; Palette: TAsphyrePalette;
  260.    DrawFx: Integer); overload;
  261.   // The following routines draw a border made of lines for the ribbon,
  262.   // which is drawn with the above FillRibbon routines.
  263.   procedure FrameRibbonHw(x, y, InRadiusX, InRadiusY, OutRadiusX, OutRadiusY,
  264.    InitPhi, EndPhi: Single; Steps: Integer; Color: Cardinal;
  265.    DrawFx: Integer);
  266.   procedure FrameRibbonEx(x, y, InRadiusX, InRadiusY, OutRadiusX, OutRadiusY,
  267.    InitPhi, EndPhi: Single; Steps: Integer; Color: Cardinal);
  268.   // Specify texture coordinates for rendering textured quads.
  269.   procedure UseImage(Image: TAsphyreCustomImage;
  270.    const Mapping: TPoint4; TexNum: Integer = 0); overload;
  271.   procedure UseImage(Image: TAsphyreCustomImage;
  272.    const Mapping: TPoint4px; TexNum: Integer = 0); overload;
  273.   procedure UseImage(Image: TAsphyreCustomImage; Pattern: Integer); overload;
  274.   procedure UseImage(Image: TAsphyreCustomImage; Pattern: Integer;
  275.    const SrcRect: TRect; Mirror: Boolean = False;
  276.    Flip: Boolean = False); overload;
  277.   // Renders the textured quad.
  278.   procedure TexMap(const Points: TPoint4; const Colors: TColor4;
  279.    DrawFx: Integer);
  280.   // Specify texture coordinates for rendering textured triangles.
  281.   procedure UseImageTri(Image: TAsphyreCustomImage; const tx0, tx1,
  282.    tx2: TPoint2; TexNum: Integer = 0); overload;
  283.   procedure UseImageTri(Image: TAsphyreCustomImage; const tx0, tx1,
  284.    tx2: TPoint2px; TexNum: Integer = 0); overload;
  285.   // Renders the textured triangle.
  286.   procedure TexTri(const p1, p2, p3: TPoint2; c1, c2, c3: Cardinal;
  287.    DrawFx: Integer);
  288.   constructor Create(ADevice: TObject);
  289.   destructor Destroy(); override;
  290.  end;
  291. //---------------------------------------------------------------------------
  292. implementation
  293. //---------------------------------------------------------------------------
  294. uses
  295.  AsphyreDevices;
  296. //--------------------------------------------------------------------------
  297. const
  298.  VertexType = D3DFVF_XYZRHW or D3DFVF_DIFFUSE or D3DFVF_TEX1;
  299. //--------------------------------------------------------------------------
  300. type
  301.  PVertexRecord = ^TVertexRecord;
  302.  TVertexRecord = record
  303.   Vertex: TD3DVector;
  304.   rhw   : Single;
  305.   Color : Longword;
  306.   u, v  : Single;
  307.  end;
  308. //--------------------------------------------------------------------------
  309. constructor TAsphyreCanvas.Create(ADevice: TObject);
  310. begin
  311.  inherited Create();
  312.  FDevice:= ADevice;
  313.  EventDeviceCreate.Subscribe(OnDeviceCreate, FDevice);
  314.  EventDeviceDestroy.Subscribe(OnDeviceDestroy, FDevice);
  315.  EventDeviceReset.Subscribe(OnDeviceReset, FDevice);
  316.  EventDeviceLost.Subscribe(OnDeviceLost, FDevice);
  317.  EventEndScene.Subscribe(OnEndScene, FDevice);
  318.  VertexArray := nil;
  319.  IndexArray  := nil;
  320.  VertexBuffer:= nil;
  321.  IndexBuffer := nil;
  322.  FAntialias  := atBest;
  323.  FMipMapping := mtNone;
  324.  FDithering  := False;
  325.  FAlphaTest  := True;
  326. end;
  327. //--------------------------------------------------------------------------
  328. destructor TAsphyreCanvas.Destroy();
  329. begin
  330.  DestroyDynamicBuffers();
  331.  DestroyStaticObjects();
  332.  EventEndScene.Unsubscribe(OnEndScene);
  333.  EventDeviceLost.Unsubscribe(OnDeviceLost);
  334.  EventDeviceReset.Unsubscribe(OnDeviceReset);
  335.  EventDeviceDestroy.Unsubscribe(OnDeviceDestroy);
  336.  EventDeviceCreate.Unsubscribe(OnDeviceCreate);
  337.  inherited;
  338. end;
  339. //---------------------------------------------------------------------------
  340. procedure TAsphyreCanvas.InitCacheSpec();
  341. begin
  342.  with TAsphyreDevice(FDevice).Caps9 do
  343.   begin
  344.    FMaxPrimitives:= Min2(MaxPrimitiveCount, MaxCachedPrimitives);
  345.    FVertexCache:= Min2(MaxVertexIndex, MaxCachedVertices);
  346.    FIndexCache:= Min2(MaxVertexIndex, MaxCachedIndexes);
  347.   end;
  348. end;
  349. //---------------------------------------------------------------------------
  350. procedure TAsphyreCanvas.PrepareVertexArray();
  351. var
  352.  Entry: PVertexRecord;
  353.  Index: Integer;
  354. begin
  355.  Entry:= VertexArray;
  356.  for Index:= 0 to FVertexCache - 1 do
  357.   begin
  358.    FillChar(Entry^, SizeOf(TVertexRecord), 0);
  359.    Entry.Vertex.z:= 0.0;
  360.    Entry.rhw     := 1.0;
  361.    Inc(Entry);
  362.   end;
  363. end;
  364. //---------------------------------------------------------------------------
  365. function TAsphyreCanvas.CreateStaticObjects(): Boolean;
  366. begin
  367.  // -> D3DXLine object
  368.  Result:= Succeeded(D3DXCreateLine(TAsphyreDevice(FDevice).Dev9,
  369.   DXLine));
  370.  if (not Result) then Exit;
  371.  // -> Enable DX3DXLine Antialiasing by default
  372.  Result:= Succeeded(DXLine.SetAntialias(True));
  373.  if (not Result) then Exit;
  374.  
  375.  // -> Static Arrays
  376.  ReallocMem(VertexArray, FVertexCache * SizeOf(TVertexRecord));
  377.  FillChar(VertexArray^, FVertexCache * SizeOf(TVertexRecord), 0);
  378.  ReallocMem(IndexArray, FIndexCache * SizeOf(Word));
  379.  FillChar(IndexArray^, FIndexCache * SizeOf(Word), 0);
  380.  PrepareVertexArray();
  381. end;
  382. //---------------------------------------------------------------------------
  383. procedure TAsphyreCanvas.DestroyStaticObjects();
  384. begin
  385.  if (IndexArray <> nil) then
  386.   begin
  387.    FreeMem(IndexArray);
  388.    IndexArray:= nil;
  389.   end;
  390.  if (VertexArray <> nil) then
  391.   begin
  392.    FreeMem(VertexArray);
  393.    VertexArray:= nil;
  394.   end;
  395.  if (DXLine <> nil) then DXLine:= nil;
  396. end;
  397. //---------------------------------------------------------------------------
  398. procedure TAsphyreCanvas.OnDeviceCreate(Sender: TObject; EventParam: Pointer;
  399.  var Success: Boolean);
  400. begin
  401.  Success:= (FDevice <> nil)and(FDevice is TAsphyreDevice);
  402.  if (Success) then
  403.   begin
  404.    InitCacheSpec();
  405.    CreateStaticObjects();
  406.   end;
  407. end;
  408. //---------------------------------------------------------------------------
  409. procedure TAsphyreCanvas.OnDeviceDestroy(Sender: TObject; EventParam: Pointer;
  410.  var Success: Boolean);
  411. begin
  412.  DestroyStaticObjects();
  413. end;
  414. //--------------------------------------------------------------------------
  415. function TAsphyreCanvas.CreateDynamicBuffers(): Boolean;
  416. begin
  417.  // -> Dynamic Vertex Buffer
  418.  Result:= Succeeded(TAsphyreDevice(FDevice).Dev9.CreateVertexBuffer(FVertexCache *
  419.   SizeOf(TVertexRecord), D3DUSAGE_WRITEONLY or D3DUSAGE_DYNAMIC, VertexType,
  420.   D3DPOOL_DEFAULT, VertexBuffer, nil));
  421.  if (not Result) then Exit;
  422.  // -> Dynamic Index Buffer
  423.  Result:= Succeeded(TAsphyreDevice(FDevice).Dev9.CreateIndexBuffer(FIndexCache *
  424.   SizeOf(Word), D3DUSAGE_WRITEONLY or D3DUSAGE_DYNAMIC, D3DFMT_INDEX16,
  425.   D3DPOOL_DEFAULT, IndexBuffer, nil));
  426. end;
  427. //---------------------------------------------------------------------------
  428. procedure TAsphyreCanvas.DestroyDynamicBuffers();
  429. begin
  430.  if (IndexBuffer <> nil) then IndexBuffer:= nil;
  431.  if (VertexBuffer <> nil) then VertexBuffer:= nil;
  432. end;
  433. //---------------------------------------------------------------------------
  434. procedure TAsphyreCanvas.ResetDeviceStates();
  435. begin
  436.  FVertexCount:= 0;
  437.  FIndexCount := 0;
  438.  FPrimitives := 0;
  439.  FDrawingMode:= dmUnspecified;
  440.  CachedDrawFx:= fxUndefined;
  441.  CachedTex   := nil;
  442.  ActiveTex   := nil;
  443.  with TAsphyreDevice(FDevice).Dev9 do
  444.   begin
  445.    //========================================================================
  446.    // In the following code, we try to disable any Direct3D states that might
  447.    // affect or disrupt our behavior.
  448.    //========================================================================
  449.    SetRenderState(D3DRS_LIGHTING,  iFalse);
  450.    SetRenderState(D3DRS_CULLMODE,  D3DCULL_NONE);
  451.    SetRenderState(D3DRS_ZENABLE,   D3DZB_FALSE);
  452.    SetRenderState(D3DRS_FOGENABLE, iFalse);
  453.    SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, iTrue);
  454.    SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
  455.    SetRenderState(D3DRS_ALPHAREF, $00000001);
  456.    SetRenderState(D3DRS_ALPHATESTENABLE, iFalse);
  457.    SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
  458.    SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
  459.    SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  460.    SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
  461.    SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
  462.    SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
  463.    SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT);
  464.    SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
  465.    SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
  466.    SetTexture(0, nil);
  467.    SetTexture(1, nil);
  468.    //==========================================================================
  469.    // Update user-specified states.
  470.    //==========================================================================
  471.    SetDithering(FDithering);
  472.    SetAntialias(FAntialias);
  473.    SetMipMapping(FMipMapping);
  474.   end;
  475.  AfterFlush := False;
  476.  FCacheStall:= 0;
  477. end;
  478. //---------------------------------------------------------------------------
  479. procedure TAsphyreCanvas.OnDeviceReset(Sender: TObject; EventParam: Pointer;
  480.  var Success: Boolean);
  481. begin
  482.  Success:= CreateDynamicBuffers();
  483.  if (Success) then ResetDeviceStates();
  484.  if (Success)and(DXLine <> nil) then
  485.   Success:= Succeeded(DXLine.OnResetDevice());
  486. end;
  487. //---------------------------------------------------------------------------
  488. procedure TAsphyreCanvas.OnDeviceLost(Sender: TObject; EventParam: Pointer;
  489.  var Success: Boolean);
  490. begin
  491.  DXLine.OnLostDevice();
  492.  DestroyDynamicBuffers();
  493. end;
  494. //---------------------------------------------------------------------------
  495. procedure TAsphyreCanvas.SetAntialias(const Value: TAntialiasType);
  496. begin
  497.  FAntialias:= Value;
  498.  if (FDevice = nil)or(not (FDevice is TAsphyreDevice))or
  499.   (TAsphyreDevice(FDevice).Dev9 = nil) then Exit;
  500.  ResetCache();
  501.  with TAsphyreDevice(FDevice).Dev9 do
  502.   case FAntialias of
  503.    atNone:
  504.     begin
  505.      SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
  506.      SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
  507.     end;
  508.    atNormal:
  509.     begin
  510.      SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
  511.      SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
  512.     end;
  513.    atBest:
  514.     begin
  515.      SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
  516.      SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
  517.     end;
  518.   end;
  519. end;
  520. //--------------------------------------------------------------------------
  521. procedure TAsphyreCanvas.SetMipmapping(const Value: TMipmappingType);
  522. begin
  523.  FMipMapping:= Value;
  524.  if (FDevice = nil)or(not (FDevice is TAsphyreDevice))or
  525.   (TAsphyreDevice(FDevice).Dev9 = nil) then Exit;
  526.  ResetCache();
  527.  with TAsphyreDevice(FDevice).Dev9 do
  528.   case FMipMapping of
  529.    mtNone:
  530.     SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
  531.    mtSingle:
  532.     SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
  533.    mtSmooth:
  534.     SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
  535.   end;
  536. end;
  537. //---------------------------------------------------------------------------
  538. procedure TAsphyreCanvas.SetDithering(const Value: Boolean);
  539. begin
  540.  FDithering:= Value;
  541.  if (FDevice = nil)or(not (FDevice is TAsphyreDevice))or
  542.   (TAsphyreDevice(FDevice).Dev9 = nil) then Exit;
  543.  ResetCache();
  544.  TAsphyreDevice(FDevice).Dev9.SetRenderState(D3DRS_DITHERENABLE,
  545.   Cardinal(FDithering));
  546. end;
  547. //---------------------------------------------------------------------------
  548. function TAsphyreCanvas.GetLineAntialias(): Boolean;
  549. begin
  550.  if (DXLine <> nil) then Result:= DXLine.GetAntialias()
  551.   else Result:= True;
  552. end;
  553. //---------------------------------------------------------------------------
  554. procedure TAsphyreCanvas.SetLineAntialias(const Value: Boolean);
  555. begin
  556.  if (DXLine <> nil) then DXLine.SetAntialias(Value);
  557. end;
  558. //---------------------------------------------------------------------------
  559. function TAsphyreCanvas.GetLineWidth(): Real;
  560. begin
  561.  if (DXLine <> nil) then Result:= DXLine.GetWidth() else Result:= 1.0;
  562. end;
  563. //---------------------------------------------------------------------------
  564. procedure TAsphyreCanvas.SetLineWidth(const Value: Real);
  565. begin
  566.  if (DXLine <> nil) then DXLine.SetWidth(Value);
  567. end;
  568. //---------------------------------------------------------------------------
  569. function TAsphyreCanvas.UploadVertexBuffer(): Boolean;
  570. var
  571.  MemAddr: Pointer;
  572.  BufSize: Integer;
  573. begin
  574.  BufSize:= FVertexCount * SizeOf(TVertexRecord);
  575.  Result:= Succeeded(VertexBuffer.Lock(0, BufSize, MemAddr, D3DLOCK_DISCARD));
  576.  if (Result) then
  577.   begin
  578.    Move(VertexArray^, MemAddr^, BufSize);
  579.    Result:= Succeeded(VertexBuffer.Unlock());
  580.   end;
  581. end;
  582. //---------------------------------------------------------------------------
  583. function TAsphyreCanvas.UploadIndexBuffer(): Boolean;
  584. var
  585.  MemAddr: Pointer;
  586.  BufSize: Integer;
  587. begin
  588.  BufSize:= FIndexCount * SizeOf(Word);
  589.  Result:= Succeeded(IndexBuffer.Lock(0, BufSize, MemAddr, D3DLOCK_DISCARD));
  590.  if (Result) then
  591.   begin
  592.    Move(IndexArray^, MemAddr^, BufSize);
  593.    Result:= Succeeded(IndexBuffer.Unlock());
  594.   end;
  595. end;
  596. //---------------------------------------------------------------------------
  597. function TAsphyreCanvas.PrepareDraw(): Boolean;
  598. begin
  599.  with TAsphyreDevice(FDevice).Dev9 do
  600.   begin
  601.    // (1) Use our vertex buffer for displaying primitives.
  602.    Result:= Succeeded(SetStreamSource(0, VertexBuffer, 0,
  603.     SizeOf(TVertexRecord)));
  604.    // (2) Use our index buffer to indicate the vertices of our primitives.
  605.    if (FIndexedMode)and(Result) then
  606.     Result:= Succeeded(SetIndices(IndexBuffer));
  607.    // (3) Disable vertex shader.
  608.    if (Result) then
  609.     Result:= Succeeded(SetVertexShader(nil));
  610.    // (4) Set the flexible vertex format of our vertex buffer.
  611.    if (Result) then
  612.     Result:= Succeeded(SetFVF(VertexType));
  613.   end;
  614. end;
  615. //---------------------------------------------------------------------------
  616. function TAsphyreCanvas.BufferDraw(): Boolean;
  617. var
  618.  Primitive: TD3DPrimitiveType;
  619. begin
  620.  // (1) Determine primitive type.
  621.  Primitive:= D3DPT_TRIANGLELIST;
  622.  case FDrawingMode of
  623.   dmPointList    : Primitive:= D3DPT_POINTLIST;
  624.   dmLineList     : Primitive:= D3DPT_LINELIST;
  625.   dmLineStrip    : Primitive:= D3DPT_LINESTRIP;
  626.   dmTriangleStrip: Primitive:= D3DPT_TRIANGLESTRIP;
  627.   dmTriangleFan  : Primitive:= D3DPT_TRIANGLEFAN;
  628.  end;
  629.  // (2) Render uploaded primitives.
  630.  with TAsphyreDevice(FDevice).Dev9 do
  631.   if (FIndexedMode) then
  632.    begin
  633.     Result:= Succeeded(DrawIndexedPrimitive(Primitive, 0, 0, FVertexCount, 0,
  634.      FPrimitives));
  635.    end else
  636.    begin
  637.     Result:= Succeeded(DrawPrimitive(Primitive, 0, FPrimitives));
  638.    end;
  639. end;
  640. //---------------------------------------------------------------------------
  641. procedure TAsphyreCanvas.ResetCache();
  642. begin
  643.  // (1) Flush the cache, if needed.
  644.  if (FVertexCount > 0)and(FPrimitives > 0) then
  645.   begin
  646.    if (UploadVertexBuffer())and(UploadIndexBuffer())and(PrepareDraw()) then
  647.     BufferDraw();
  648.    Inc(FCacheStall);
  649.   end;
  650.  // (2) Reset buffer info.
  651.  FVertexCount:= 0;
  652.  FIndexCount := 0;
  653.  FPrimitives := 0;
  654.  FDrawingMode:= dmUnspecified;
  655. end;
  656. //---------------------------------------------------------------------------
  657. procedure TAsphyreCanvas.OnEndScene(Sender: TObject; EventParam: Pointer;
  658.  var Success: Boolean);
  659. begin
  660.  Flush();
  661. end;
  662. //---------------------------------------------------------------------------
  663. procedure TAsphyreCanvas.Flush();
  664. begin
  665.  ResetCache();
  666.  AfterFlush:= True;
  667. end;
  668. //---------------------------------------------------------------------------
  669. function TAsphyreCanvas.GetClipRect(): TRect;
  670. var
  671.  vp: TD3DViewport9;
  672. begin
  673.  if (FDevice = nil)or(not (FDevice is TAsphyreDevice))or
  674.   (TAsphyreDevice(FDevice).Dev9 = nil) then
  675.   begin
  676.    Result:= Rect(0, 0, 0, 0);
  677.    Exit;
  678.   end;
  679.  FillChar(vp, SizeOf(vp), 0);
  680.  TAsphyreDevice(FDevice).Dev9.GetViewport(vp);
  681.  Result.Left  := vp.X;
  682.  Result.Top   := vp.Y;
  683.  Result.Right := vp.X + vp.Width;
  684.  Result.Bottom:= vp.Y + vp.Height;
  685.  FClipRect:= Result;
  686. end;
  687. //---------------------------------------------------------------------------
  688. procedure TAsphyreCanvas.SetClipRect(const Value: TRect);
  689. var
  690.  vp: TD3DViewport9;
  691. begin
  692.  if (FDevice = nil)or(not (FDevice is TAsphyreDevice))or
  693.   (TAsphyreDevice(FDevice).Dev9 = nil) then Exit;
  694.  ResetCache();
  695.  vp.X:= Value.Left;
  696.  vp.Y:= Value.Top;
  697.  vp.Width := (Value.Right - Value.Left);
  698.  vp.Height:= (Value.Bottom - Value.Top);
  699.  vp.MinZ:= 0.0;
  700.  vp.MaxZ:= 1.0;
  701.  TAsphyreDevice(FDevice).Dev9.SetViewport(vp);
  702.  FClipRect:= Value;
  703. end;
  704. //---------------------------------------------------------------------------
  705. procedure TAsphyreCanvas.RequestCache(Mode: TDrawingMode; Indexed: Boolean;
  706.  Vertices, Indices, DrawFx: Integer; ReqTex: TAsphyreCustomTexture);
  707. var
  708.  NeedReset: Boolean;
  709. begin
  710.  // (1) Reset device, if needed.
  711.  if (AfterFlush) then ResetDeviceStates();
  712.  // (2) Check whether reset should be applied
  713.  NeedReset:= (FVertexCount + Vertices > FVertexCache);
  714.  NeedReset:= NeedReset or ((Indexed)and(FIndexCount + Indices > FIndexCache));
  715.  NeedReset:= NeedReset or (FDrawingMode = dmUnspecified) or
  716.   (FDrawingMode <> Mode) or (FIndexedMode <> Indexed);
  717.  NeedReset:= NeedReset or (CachedDrawFx <> DrawFx) or (CachedTex <> ReqTex);
  718.  // (3) Apply reset, if needed.
  719.  if (NeedReset) then
  720.   begin
  721.    ResetCache();
  722.    // Update currently active texture.
  723.    if (FDrawingMode = dmUnspecified)or(CachedTex <> ReqTex) then
  724.     with TAsphyreDevice(FDevice).Dev9 do
  725.      begin
  726.       if (ReqTex <> nil) then ReqTex.Activate(0) else SetTexture(0, nil);
  727.      CachedTex:= ReqTex;
  728.     end;
  729.    // Update currently active effect.
  730.    if (CachedDrawFx = fxUndefined)or(CachedDrawFx <> DrawFx) then
  731.     EffectManager.HandleCode(Self, TAsphyreDevice(FDevice).Dev9, DrawFx);
  732.    FIndexedMode:= Indexed;
  733.    FDrawingMode:= Mode;
  734.    CachedDrawFx:= DrawFx;
  735.   end;
  736. end;
  737. //---------------------------------------------------------------------------
  738. function TAsphyreCanvas.NextVertexEntry(): Pointer;
  739. begin
  740.  Result:= Pointer(Integer(VertexArray) + (FVertexCount * SizeOf(TVertexRecord)));
  741. end;
  742. //---------------------------------------------------------------------------
  743. procedure TAsphyreCanvas.PutPixel(const Point: TPoint2; Color: Cardinal;
  744.  DrawFx: Integer);
  745. var
  746.  Entry: PVertexRecord;
  747. begin
  748.  RequestCache(dmPointList, False, 1, 0, DrawFx, nil);
  749.  Entry:= NextVertexEntry();
  750.  Entry.Vertex.x:= Point.x;
  751.  Entry.Vertex.y:= Point.y;
  752.  Entry.Color   := Color;
  753.  Inc(FVertexCount);
  754.  Inc(FPrimitives);
  755. end;
  756. //---------------------------------------------------------------------------
  757. procedure TAsphyreCanvas.PutPixel(x, y: Single; Color: Cardinal; DrawFx: Integer);
  758. begin
  759.  PutPixel(Point2(x, y), Color, DrawFx);
  760. end;
  761. //---------------------------------------------------------------------------
  762. procedure TAsphyreCanvas.LineHw(const Src, Dest: TPoint2; Color0, Color1: Cardinal;
  763.  DrawFx: Integer);
  764. var
  765.  Entry: PVertexRecord;
  766. begin
  767.  RequestCache(dmLineList, False, 2, 0, DrawFx, nil);
  768.  // -> 1st point
  769.  Entry:= NextVertexEntry();
  770.  Entry.Vertex.x:= Src.x;
  771.  Entry.Vertex.y:= Src.y;
  772.  Entry.Color   := Color0;
  773.  Inc(FVertexCount);
  774.  // -> 2nd point
  775.  Entry:= NextVertexEntry();
  776.  Entry.Vertex.x:= Dest.x;
  777.  Entry.Vertex.y:= Dest.y;
  778.  Entry.Color   := Color1;
  779.  Inc(FVertexCount);
  780.  Inc(FPrimitives);
  781. end;
  782. //---------------------------------------------------------------------------
  783. procedure TAsphyreCanvas.LineHw(x1, y1, x2, y2: Single; Color0, Color1: Cardinal;
  784.  DrawFx: Integer);
  785. begin
  786.  LineHw(Point2(x1, y1), Point2(x2, y2), Color0, Color1, DrawFx);
  787. end;
  788. //---------------------------------------------------------------------------
  789. procedure TAsphyreCanvas.LineHw(const Src, Dest: TPoint; Color0, Color1: Cardinal;
  790.  DrawFx: Integer);
  791. begin
  792.  LineHw(Point2(Src.X, Src.Y), Point2(Dest.X, Dest.Y), Color0, Color1, DrawFx);
  793. end;
  794. //---------------------------------------------------------------------------
  795. procedure TAsphyreCanvas.LineEx(const Src, Dest: TPoint2; Color: Cardinal);
  796. var
  797.  Vertices: array[0..1] of TD3DXVector2;
  798. begin
  799.  Flush();
  800.  Vertices[0]:= TD3DXVector2(Src);
  801.  Vertices[1]:= TD3DXVector2(Dest);
  802.  DXLine.Draw(@Vertices[0], 2, Color);
  803. end;
  804. //---------------------------------------------------------------------------
  805. procedure TAsphyreCanvas.LineEx(x1, y1, x2, y2: Single;
  806.  Color: Cardinal);
  807. var
  808.  Vertices: array[0..1] of TD3DXVector2;
  809. begin
  810.  Flush();
  811.  Vertices[0].x:= x1 - FClipRect.Left;
  812.  Vertices[0].y:= y1 - FClipRect.Top;
  813.  Vertices[1].x:= x2 - FClipRect.Left;
  814.  Vertices[1].y:= y2 - FClipRect.Top;
  815.  DXLine.Draw(@Vertices[0], 2, Color);
  816. end;
  817. //---------------------------------------------------------------------------
  818. procedure TAsphyreCanvas.LineEx(const Src, Dest: TPoint;
  819.  Color: Cardinal);
  820. var
  821.  Vertices: array[0..1] of TD3DXVector2;
  822. begin
  823.  Flush();
  824.  Vertices[0].x:= Src.X - FClipRect.Left;
  825.  Vertices[0].y:= Src.Y - FClipRect.Top;
  826.  Vertices[1].x:= Dest.X - FClipRect.Left;
  827.  Vertices[1].y:= Dest.Y - FClipRect.Top;
  828.  DXLine.Draw(@Vertices[0], 2, Color);
  829. end;
  830. //---------------------------------------------------------------------------
  831. procedure TAsphyreCanvas.WireQuadEx(const Points: TPoint4;
  832.  Color: Cardinal);
  833. var
  834.  Vertices: array[0..4] of TD3DXVector2;
  835. begin
  836.  Flush();
  837.  Vertices[0]:= TD3DXVector2(Points[0] - TPoint2(FClipRect.TopLeft));
  838.  Vertices[1]:= TD3DXVector2(Points[1] - TPoint2(FClipRect.TopLeft));
  839.  Vertices[2]:= TD3DXVector2(Points[2] - TPoint2(FClipRect.TopLeft));
  840.  Vertices[3]:= TD3DXVector2(Points[3] - TPoint2(FClipRect.TopLeft));
  841.  Vertices[4]:= TD3DXVector2(Points[0] - TPoint2(FClipRect.TopLeft));
  842.  DXLine.Draw(@Vertices[0], 5, Color);
  843. end;
  844. //---------------------------------------------------------------------------
  845. procedure TAsphyreCanvas.WireTriEx(const p1, p2, p3: TPoint2; Color: Cardinal);
  846. var
  847.  Vertices: array[0..3] of TD3DXVector2;
  848. begin
  849.  Flush();
  850.  Vertices[0]:= TD3DXVector2(p1 - TPoint2(FClipRect.TopLeft));
  851.  Vertices[1]:= TD3DXVector2(p2 - TPoint2(FClipRect.TopLeft));
  852.  Vertices[2]:= TD3DXVector2(p3 - TPoint2(FClipRect.TopLeft));
  853.  Vertices[3]:= TD3DXVector2(p1 - TPoint2(FClipRect.TopLeft));
  854.  DXLine.Draw(@Vertices[0], 4, Color);
  855. end;
  856. //---------------------------------------------------------------------------
  857. procedure TAsphyreCanvas.WireQuadHw(const Points: TPoint4;
  858.  const Colors: TColor4; DrawFx: Integer);
  859. var
  860.  MyPts: TPoint4;
  861. begin
  862.  MyPts:= Points;
  863.  // last pixel fix -> not very good implementation :(
  864.  if (MyPts[0].y = MyPts[1].y)and(MyPts[2].y = MyPts[3].y)and
  865.   (MyPts[0].x = MyPts[3].x)and(MyPts[1].x = MyPts[2].x) then
  866.   begin
  867.    MyPts[1].x:= MyPts[1].x - 1.0;
  868.    MyPts[2].x:= MyPts[2].x - 1.0;
  869.    MyPts[2].y:= MyPts[2].y - 1.0;
  870.    MyPts[3].y:= MyPts[3].y - 1.0;
  871.   end;
  872.  LineHw(MyPts[0], MyPts[1], Colors[0], Colors[1], DrawFx);
  873.  LineHw(MyPts[1], MyPts[2], Colors[1], Colors[2], DrawFx);
  874.  LineHw(MyPts[2], MyPts[3], Colors[2], Colors[3], DrawFx);
  875.  LineHw(MyPts[3], MyPts[0], Colors[3], Colors[0], DrawFx);
  876. end;
  877. //---------------------------------------------------------------------------
  878. procedure TAsphyreCanvas.AddIndexEntry(Index: Integer);
  879. var
  880.  Entry: PWord;
  881. begin
  882.  Entry:= Pointer(Integer(IndexArray) + (FIndexCount * SizeOf(Word)));
  883.  Entry^:= Index;
  884.  Inc(FIndexCount);
  885. end;
  886. //---------------------------------------------------------------------------
  887. procedure TAsphyreCanvas.FillTri(const p1, p2, p3: TPoint2; c1, c2, c3: Cardinal;
  888.  DrawFx: Integer);
  889. var
  890.  Entry: PVertexRecord;
  891. begin
  892.  {$IFDEF FillTriUncached}
  893.  // request non-indexed triangle list to reduce bandwidth
  894.  RequestCache(dmTriangleList, False, 3, 0, DrawFx, nil);
  895.  {$ELSE}
  896.  // request indexed triangle list to improve cache performance
  897.  RequestCache(dmTriangleList, True, 3, 3, DrawFx, nil);
  898.  {$ENDIF}
  899.  {$IFNDEF FillTriUncached}
  900.  // insert index entries, if using index buffers
  901.  AddIndexEntry(FVertexCount);
  902.  AddIndexEntry(FVertexCount + 1);
  903.  AddIndexEntry(FVertexCount + 2);
  904.  {$ENDIF}
  905.  // insert vertices
  906.  Entry:= NextVertexEntry();
  907.  Entry.Vertex.x:= p1.x;
  908.  Entry.Vertex.y:= p1.y;
  909.  Entry.Color   := c1;
  910.  Inc(FVertexCount);
  911.  Entry:= NextVertexEntry();
  912.  Entry.Vertex.x:= p2.x;
  913.  Entry.Vertex.y:= p2.y;
  914.  Entry.Color   := c2;
  915.  Inc(FVertexCount);
  916.  Entry:= NextVertexEntry();
  917.  Entry.Vertex.x:= p3.x;
  918.  Entry.Vertex.y:= p3.y;
  919.  Entry.Color   := c3;
  920.  Inc(FVertexCount);
  921.  Inc(FPrimitives);
  922. end;
  923. //---------------------------------------------------------------------------
  924. procedure TAsphyreCanvas.FillTri(x1, y1, x2, y2, x3, y3: Single; c1, c2,
  925.  c3: Cardinal; DrawFx: Integer);
  926. begin
  927.  FillTri(Point2(x1, y1), Point2(x2, y2), Point2(x3, y3), c1, c2, c3, DrawFx);
  928. end;
  929. //---------------------------------------------------------------------------
  930. procedure TAsphyreCanvas.FillQuad(const Points: TPoint4; const Colors: TColor4;
  931.  DrawFx: Integer);
  932. var
  933.  Entry: PVertexRecord;
  934. begin
  935.  {$IFDEF FillQuadUncached}
  936.  // request non-indexed triangle strip to reduce bandwidth
  937.  RequestCache(dmTriangleStrip, False, 4, 0, DrawFx, nil);
  938.  {$ELSE}
  939.  // request indexed triangle list to improve cache performance
  940.  RequestCache(dmTriangleList, True, 4, 6, DrawFx, nil);
  941.  {$ENDIF}
  942.  {$IFNDEF FillQuadUncached}
  943.  // insert index entries, if using index buffers
  944.  AddIndexEntry(FVertexCount + 2);
  945.  AddIndexEntry(FVertexCount);
  946.  AddIndexEntry(FVertexCount + 1);
  947.  AddIndexEntry(FVertexCount + 3);
  948.  AddIndexEntry(FVertexCount + 2);
  949.  AddIndexEntry(FVertexCount + 1);
  950.  {$ENDIF}
  951.  // insert vertices
  952.  Entry:= NextVertexEntry();
  953.  Entry.Vertex.x:= Points[0].x;
  954.  Entry.Vertex.y:= Points[0].y;
  955.  Entry.Color   := Colors[0];
  956.  Inc(FVertexCount);
  957.  Entry:= NextVertexEntry();
  958.  Entry.Vertex.x:= Points[1].x;
  959.  Entry.Vertex.y:= Points[1].y;
  960.  Entry.Color   := Colors[1];
  961.  Inc(FVertexCount);
  962.  Entry:= NextVertexEntry();
  963.  Entry.Vertex.x:= Points[3].x;
  964.  Entry.Vertex.y:= Points[3].y;
  965.  Entry.Color   := Colors[3];
  966.  Inc(FVertexCount);
  967.  Entry:= NextVertexEntry();
  968.  Entry.Vertex.x:= Points[2].x;
  969.  Entry.Vertex.y:= Points[2].y;
  970.  Entry.Color   := Colors[2];
  971.  Inc(FVertexCount);
  972.  Inc(FPrimitives, 2);
  973.  {$IFDEF FillQuadUncached}
  974.  ResetCache();
  975.  {$ENDIF}
  976. end;
  977. //---------------------------------------------------------------------------
  978. procedure TAsphyreCanvas.FillQuadEx(const Points: TPoint4;
  979.  const Colors: TColor4; DrawFx: Integer);
  980. var
  981.  i: Integer;
  982.  Entry: PVertexRecord;
  983. begin
  984.  RequestCache(dmTriangleList, True, 8, 18, DrawFx, nil);
  985.  // Insert indexes.
  986.  AddIndexEntry(FVertexCount + 0);
  987.  AddIndexEntry(FVertexCount + 4);
  988.  AddIndexEntry(FVertexCount + 7);
  989.  AddIndexEntry(FVertexCount + 4);
  990.  AddIndexEntry(FVertexCount + 1);
  991.  AddIndexEntry(FVertexCount + 5);
  992.  AddIndexEntry(FVertexCount + 4);
  993.  AddIndexEntry(FVertexCount + 6);
  994.  AddIndexEntry(FVertexCount + 7);
  995.  AddIndexEntry(FVertexCount + 4);
  996.  AddIndexEntry(FVertexCount + 5);
  997.  AddIndexEntry(FVertexCount + 6);
  998.  AddIndexEntry(FVertexCount + 7);
  999.  AddIndexEntry(FVertexCount + 6);
  1000.  AddIndexEntry(FVertexCount + 3);
  1001.  AddIndexEntry(FVertexCount + 5);
  1002.  AddIndexEntry(FVertexCount + 2);
  1003.  AddIndexEntry(FVertexCount + 6);
  1004.  // Insert first four vertices.
  1005.  for i:= 0 to 3 do
  1006.   begin
  1007.    Entry:= NextVertexEntry();
  1008.    Entry.Vertex.x:= Points[i].x;
  1009.    Entry.Vertex.y:= Points[i].y;
  1010.    Entry.Color   := Colors[i];
  1011.    Inc(FVertexCount);
  1012.   end;
  1013.  // Insert subdivision vertices.
  1014.  Entry:= NextVertexEntry();
  1015.  Entry.Vertex.x:= (Points[0].x + Points[1].x) * 0.5;
  1016.  Entry.Vertex.y:= (Points[0].y + Points[1].y) * 0.5;
  1017.  Entry.Color   := (TAsphyreColor(Colors[0]) + TAsphyreColor(Colors[1])) / 2;
  1018.  Inc(FVertexCount);
  1019.  Entry:= NextVertexEntry();
  1020.  Entry.Vertex.x:= (Points[1].x + Points[2].x) * 0.5;
  1021.  Entry.Vertex.y:= (Points[1].y + Points[2].y) * 0.5;
  1022.  Entry.Color   := (TAsphyreColor(Colors[1]) + TAsphyreColor(Colors[2])) / 2;
  1023.  Inc(FVertexCount);
  1024.  Entry:= NextVertexEntry();
  1025.  Entry.Vertex.x:= (Points[2].x + Points[3].x) * 0.5;
  1026.  Entry.Vertex.y:= (Points[2].y + Points[3].y) * 0.5;
  1027.  Entry.Color   := (TAsphyreColor(Colors[2]) + TAsphyreColor(Colors[3])) / 2;
  1028.  Inc(FVertexCount);
  1029.  Entry:= NextVertexEntry();
  1030.  Entry.Vertex.x:= (Points[3].x + Points[0].x) * 0.5;
  1031.  Entry.Vertex.y:= (Points[3].y + Points[0].y) * 0.5;
  1032.  Entry.Color   := (TAsphyreColor(Colors[3]) + TAsphyreColor(Colors[0])) / 2;
  1033.  Inc(FVertexCount);
  1034.  Inc(FPrimitives, 6);
  1035. end;
  1036. //---------------------------------------------------------------------------
  1037. procedure TAsphyreCanvas.FillRect(const Rect: TRect; const Colors: TColor4;
  1038.  DrawFx: Integer);
  1039. begin
  1040.  FillQuad(pRect4(Rect), Colors, DrawFx);
  1041. end;
  1042. //---------------------------------------------------------------------------
  1043. procedure TAsphyreCanvas.FillRect(const Rect: TRect; Color: Cardinal;
  1044.  DrawFx: Integer);
  1045. begin
  1046.  FillRect(Rect, cColor4(Color), DrawFx);
  1047. end;
  1048. //---------------------------------------------------------------------------
  1049. procedure TAsphyreCanvas.FillRect(Left, Top, Width, Height: Integer;
  1050.  Color: Cardinal; DrawFx: Integer);
  1051. begin
  1052.  FillRect(Bounds(Left, Top, Width, Height), Color, DrawFx);
  1053. end;
  1054. //---------------------------------------------------------------------------
  1055. procedure TAsphyreCanvas.FrameRect(const Rect: TRect; const Colors: TColor4;
  1056.  DrawFx: Integer);
  1057. begin
  1058.  WireQuadHw(pRect4(Rect), Colors, DrawFx);
  1059. end;
  1060. //---------------------------------------------------------------------------
  1061. procedure TAsphyreCanvas.FrameRect(const Rect: TRect; Color: Cardinal;
  1062.  DrawFx: Integer);
  1063. begin
  1064.  FrameRect(Rect, cColor4(Color), DrawFx);
  1065. end;
  1066. //---------------------------------------------------------------------------
  1067. procedure TAsphyreCanvas.FrameRect(Left, Top, Width, Height: Integer;
  1068.  Color: Cardinal; DrawFx: Integer);
  1069. begin
  1070.  FrameRect(Bounds(Left, Top, Width, Height), Color, DrawFx);
  1071. end;
  1072. //---------------------------------------------------------------------------
  1073. procedure TAsphyreCanvas.FillArc(x, y, RadiusX, RadiusY, InitPhi,
  1074.  EndPhi: Single; Steps: Integer; const Colors: TColor4; DrawFx: Integer);
  1075. var
  1076.  x1, y1, x2, y2: Real;
  1077.  cs: TAsphyreColor4;
  1078.  i: Integer;
  1079.  Alpha: Real;
  1080.  xAlpha, yAlpha: Integer;
  1081.  CurPt: TPoint2;
  1082.  Entry: PVertexRecord;
  1083.  {$IFNDEF FillArcUncached}VertexZero: Integer;{$ENDIF}
  1084. begin
  1085.  if (Steps < 1) then Exit;
  1086.  // (1) Convert 32-bit RGBA colors to fixed-point color set.
  1087.  cs:= ColorToFixed4(Colors);
  1088.  // (2) Find (x, y) margins for color interpolation.
  1089.  x1:= x - RadiusX;
  1090.  x2:= x + RadiusX;
  1091.  y1:= y - RadiusY;
  1092.  y2:= y + RadiusY;
  1093.  // (3) Before doing anything else, check cache availability.
  1094.  {$IFDEF FillArcUncached}
  1095.  // request non-indexed triangle fan to reduce bandwidth
  1096.  RequestCache(dmTriangleFan, False, Steps + 2, 0, DrawFx, nil);
  1097.  {$ELSE}
  1098.  // request indexed triangle list to improve cache performance
  1099.  RequestCache(dmTriangleList, True, Steps + 2, Steps * 3, DrawFx, nil);
  1100.  {$ENDIF}
  1101.  {$IFNDEF FillArcUncached}
  1102.  VertexZero:= FVertexCount;
  1103.  {$ENDIF}
  1104.  // (4) Insert initial vertex placed at the arc's center
  1105.  Entry:= NextVertexEntry();
  1106.  Entry.Vertex.x:= x;
  1107.  Entry.Vertex.y:= y;
  1108.  Entry.Color   := (cs[0] + cs[1] + cs[2] + cs[3]) * 0.25;
  1109.  Inc(FVertexCount);
  1110.  // (5) Insert the rest of vertices
  1111.  for i:= 0 to Steps - 1 do
  1112.   begin
  1113.    // initial and final angles for this vertex
  1114.    Alpha:= (i * (EndPhi - InitPhi) / Steps) + InitPhi;
  1115.    // determine second and third points of the processed vertex
  1116.    CurPt.x:= x + Cos(Alpha) * RadiusX;
  1117.    CurPt.y:= y - Sin(Alpha) * RadiusY;
  1118.    // find color interpolation values
  1119.    xAlpha:= Round((CurPt.x - x1) * 255.0 / (x2 - x1));
  1120.    yAlpha:= Round((CurPt.y - y1) * 255.0 / (y2 - y1));
  1121.    {$IFNDEF FillArcUncached}
  1122.    // insert new index buffer entry
  1123.    AddIndexEntry(VertexZero);
  1124.    AddIndexEntry(FVertexCount);
  1125.    AddIndexEntry(FVertexCount + 1);
  1126.    {$ENDIF}
  1127.    // insert the entry into vertex array
  1128.    Entry:= NextVertexEntry();
  1129.    Entry.Vertex.x:= CurPt.x;
  1130.    Entry.Vertex.y:= CurPt.y;
  1131.    Entry.Color:= cBlend(cBlend(cs[0], cs[1], xAlpha), cBlend(cs[3], cs[2],
  1132.     xAlpha), yAlpha);
  1133.    Inc(FVertexCount);
  1134.   end;
  1135.  // find the latest vertex to finish the arc
  1136.  CurPt.x:= x + Cos(EndPhi) * RadiusX;
  1137.  CurPt.y:= y - Sin(EndPhi) * RadiusY;
  1138.  // find color interpolation values
  1139.  xAlpha:= Round((CurPt.x - x1) * 255.0 / (x2 - x1));
  1140.  yAlpha:= Round((CurPt.y - y1) * 255.0 / (y2 - y1));
  1141.  // insert the entry into vertex array
  1142.  Entry:= NextVertexEntry();
  1143.  Entry.Vertex.x:= CurPt.x;
  1144.  Entry.Vertex.y:= CurPt.y;
  1145.  Entry.Color:= cBlend(cBlend(cs[0], cs[1], xAlpha), cBlend(cs[3], cs[2],
  1146.   xAlpha), yAlpha);
  1147.  Inc(FVertexCount);
  1148.  Inc(FPrimitives, Steps);
  1149.  {$IFDEF FillArcUncached}
  1150.  ResetCache();
  1151.  {$ENDIF}
  1152. end;
  1153. //---------------------------------------------------------------------------
  1154. procedure TAsphyreCanvas.FillEllipse(x, y, RadiusX, RadiusY: Single;
  1155.  Steps: Integer; const Colors: TColor4; DrawFx: Integer);
  1156. begin
  1157.  FillArc(x, y, RadiusX, RadiusY, 0, Pi * 2.0, Steps, Colors, DrawFx);
  1158. end;
  1159. //---------------------------------------------------------------------------
  1160. procedure TAsphyreCanvas.FillCircle(x, y, Radius: Single;
  1161.  Steps: Integer; const Colors: TColor4; DrawFx: Integer);
  1162. begin
  1163.  FillArc(x, y, Radius, Radius, 0, Pi * 2.0, Steps, Colors, DrawFx);
  1164. end;
  1165. //---------------------------------------------------------------------------
  1166. procedure TAsphyreCanvas.Ellipse(x, y, RadiusX, RadiusY: Single;
  1167.  Steps: Integer; Color: Cardinal);
  1168. const
  1169.  Pi2 = Pi * 2.0;
  1170. var
  1171.  Vertices: array of TD3DXVector2;
  1172.  i: Integer;
  1173.  Alpha: Real;
  1174. begin
  1175.  SetLength(Vertices, Steps + 1);
  1176.  for i:= 0 to Steps do
  1177.   begin
  1178.    Alpha:= i * Pi2 / Steps;
  1179.    Vertices[i].x:= x + Cos(Alpha) * RadiusX;
  1180.    Vertices[i].y:= y - Sin(Alpha) * RadiusY;
  1181.    // 1-pixel gap bug fix
  1182.    if (i = Steps) then Vertices[i].y:=  Vertices[i].y - 1;
  1183.   end;
  1184.  DXLine.Draw(@Vertices[0], Steps + 1, Color);
  1185. end;
  1186. //--------------------------------------------------------------------------
  1187. procedure TAsphyreCanvas.Circle(x, y, Radius: Single; Steps: Integer;
  1188.  Color: Cardinal);
  1189. begin
  1190.  Ellipse(x, y, Radius, Radius, Steps, Color);
  1191. end;
  1192. //---------------------------------------------------------------------------
  1193. procedure TAsphyreCanvas.FillRibbon(x, y, InRadiusX, InRadiusY, OutRadiusX,
  1194.  OutRadiusY, InitPhi, EndPhi: single; Steps: Integer; const Colors: TColor4;
  1195.  DrawFx: Integer);
  1196. var
  1197.  x1, y1, x2, y2: Single;
  1198.  cs: TAsphyreColor4;
  1199.  i: Integer;
  1200.  Alpha: Real;
  1201.  xAlpha, yAlpha: Integer;
  1202.  CurPt: TPoint2;
  1203.  Entry: PVertexRecord;
  1204.  {$IFNDEF FillRibbonUncached}PreVtx: Integer;{$ENDIF}
  1205. begin
  1206.  if (Steps < 1) then Exit;
  1207.  // (1) Convert 32-bit RGBA colors to fixed-point color set.
  1208.  cs:= ColorToFixed4(Colors);
  1209.  // (2) Find (x, y) margins for color interpolation.
  1210.  x1:= x - OutRadiusX;
  1211.  x2:= x + OutRadiusX;
  1212.  y1:= y - OutRadiusY;
  1213.  y2:= y + OutRadiusY;
  1214.  // (3) Check cache availability first.
  1215.  {$IFDEF FillRibbonUncached}
  1216.  // request non-indexed triangle strip to reduce bandwidth
  1217.  RequestCache(dmTriangleStrip, False, (Steps * 2) + 2, 0, DrawFx, nil);
  1218.  {$ELSE}
  1219.  // request indexed triangle list to improve cache performance
  1220.  RequestCache(dmTriangleList, True, (Steps * 2) + 2, Steps * 6, DrawFx, nil);
  1221.  {$ENDIF}
  1222.  {$IFNDEF FillRibbonUncached}
  1223.  PreVtx:= FVertexCount;
  1224.  {$ENDIF}
  1225.  // (4) Create first inner vertex
  1226.  CurPt.x:= x + Cos(InitPhi) * InRadiusX;
  1227.  CurPt.y:= y - Sin(InitPhi) * InRadiusY;
  1228.  // -> color interpolation values
  1229.  xAlpha:= Round((CurPt.x - x1) * 255.0 / (x2 - x1));
  1230.  yAlpha:= Round((CurPt.y - y1) * 255.0 / (y2 - y1));
  1231.  // -> insert the vertex
  1232.  Entry:= NextVertexEntry();
  1233.  Entry.Vertex.x:= CurPt.x;
  1234.  Entry.Vertex.y:= CurPt.y;
  1235.  Entry.Color   := cBlend(cBlend(cs[0], cs[1], xAlpha), cBlend(cs[3], cs[2],
  1236.   xAlpha), yAlpha);
  1237.  Inc(FVertexCount);
  1238.  // (5) Create first outer vertex
  1239.  CurPt.x:= x + Cos(InitPhi) * OutRadiusX;
  1240.  CurPt.y:= y - Sin(InitPhi) * OutRadiusY;
  1241.  // -> color interpolation values
  1242.  xAlpha:= Round((CurPt.x - x1) * 255.0 / (x2 - x1));
  1243.  yAlpha:= Round((CurPt.y - y1) * 255.0 / (y2 - y1));
  1244.  // -> insert the vertex
  1245.  Entry:= NextVertexEntry();
  1246.  Entry.Vertex.x:= CurPt.x;
  1247.  Entry.Vertex.y:= CurPt.y;
  1248.  Entry.Color   := cBlend(cBlend(cs[0], cs[1], xAlpha), cBlend(cs[3], cs[2],
  1249.   xAlpha), yAlpha);
  1250.  Inc(FVertexCount);
  1251.  // (6) Insert the rest of vertices
  1252.  for i:= 1 to Steps do
  1253.   begin
  1254.    // 6a. Insert inner vertex
  1255.    // -> angular position
  1256.    Alpha:= (i * (EndPhi - InitPhi) / Steps) + InitPhi;
  1257.    // -> vertex position
  1258.    CurPt.x:= x + Cos(Alpha) * InRadiusX;
  1259.    CurPt.y:= y - Sin(Alpha) * InRadiusY;
  1260.    // -> color interpolation values
  1261.    xAlpha:= Round((CurPt.x - x1) * 255.0 / (x2 - x1));
  1262.    yAlpha:= Round((CurPt.y - y1) * 255.0 / (y2 - y1));
  1263.    // -> insert the vertex
  1264.    Entry:= NextVertexEntry();
  1265.    Entry.Vertex.x:= CurPt.x;
  1266.    Entry.Vertex.y:= CurPt.y;
  1267.    Entry.Color:= cBlend(cBlend(cs[0], cs[1], xAlpha), cBlend(cs[3], cs[2],
  1268.     xAlpha), yAlpha);
  1269.    Inc(FVertexCount);
  1270.    // 6b. Insert outer vertex
  1271.    // -> angular position
  1272.    Alpha:= (i * (EndPhi - InitPhi) / Steps) + InitPhi;
  1273.    // -> vertex position
  1274.    CurPt.x:= x + Cos(Alpha) * OutRadiusX;
  1275.    CurPt.y:= y - Sin(Alpha) * OutRadiusY;
  1276.    // -> color interpolation values
  1277.    xAlpha:= Round((CurPt.x - x1) * 255.0 / (x2 - x1));
  1278.    yAlpha:= Round((CurPt.y - y1) * 255.0 / (y2 - y1));
  1279.    // -> insert the vertex
  1280.    Entry:= NextVertexEntry();
  1281.    Entry.Vertex.x:= CurPt.x;
  1282.    Entry.Vertex.y:= CurPt.y;
  1283.    Entry.Color:= cBlend(cBlend(cs[0], cs[1], xAlpha), cBlend(cs[3], cs[2],
  1284.     xAlpha), yAlpha);
  1285.   end;
  1286.  {$IFNDEF FillRibbonUncached}
  1287.  // (7) Insert indexes
  1288.  for i:= 0 to Steps - 1 do
  1289.   begin
  1290.    AddIndexEntry(PreVtx);
  1291.    AddIndexEntry(PreVtx + 1);
  1292.    AddIndexEntry(PreVtx + 2);
  1293.    AddIndexEntry(PreVtx + 1);
  1294.    AddIndexEntry(PreVtx + 3);
  1295.    AddIndexEntry(PreVtx + 2);
  1296.    Inc(PreVtx, 2);
  1297.   end;
  1298.  {$ENDIF}
  1299.  Inc(FPrimitives, Steps * 2);
  1300.  {$IFDEF FillRibbonUncached}
  1301.  ResetCache();
  1302.  {$ENDIF}
  1303. end;
  1304. //---------------------------------------------------------------------------
  1305. procedure TAsphyreCanvas.FillRibbon(x, y, InRadiusX, InRadiusY, OutRadiusX,
  1306.  OutRadiusY, InitPhi, EndPhi: single; Steps: Integer; Palette: TAsphyrePalette;
  1307.  DrawFx: Integer);
  1308. var
  1309.  i: Integer;
  1310.  Alpha: Single;
  1311.  CurPt: TPoint2;
  1312.  Color: Cardinal;
  1313.  Entry: PVertexRecord;
  1314.  {$IFNDEF FillRibbonUncached}PreVtx: Integer;{$ENDIF}
  1315. begin
  1316.  if (Steps < 1) then Exit;
  1317.  // (1) Check cache availability.
  1318.  {$IFDEF FillRibbonUncached}
  1319.  // request non-indexed triangle strip to reduce bandwidth
  1320.  RequestCache(dmTriangleStrip, False, (Steps * 2) + 2, 0, DrawFx, nil);
  1321.  {$ELSE}
  1322.  // request indexed triangle list to improve cache performance
  1323.  RequestCache(dmTriangleList, True, (Steps * 2) + 2, Steps * 6, DrawFx, nil);
  1324.  {$ENDIF}
  1325.  {$IFNDEF FillRibbonUncached}
  1326.  PreVtx:= FVertexCount;
  1327.  {$ENDIF}
  1328.  // (2) Retreive first color from the palette.
  1329.  Color:= Palette.Color[0.0];
  1330.  // (3) Create first inner vertex
  1331.  CurPt.x:= x + Cos(InitPhi) * InRadiusX;
  1332.  CurPt.y:= y - Sin(InitPhi) * InRadiusY;
  1333.  // -> insert the vertex
  1334.  Entry:= NextVertexEntry();
  1335.  Entry.Vertex.x:= CurPt.x;
  1336.  Entry.Vertex.y:= CurPt.y;
  1337.  Entry.Color   := Color;
  1338.  Inc(FVertexCount);
  1339.  // (4) Create first outer vertex
  1340.  CurPt.x:= x + Cos(InitPhi) * OutRadiusX;
  1341.  CurPt.y:= y - Sin(InitPhi) * OutRadiusY;
  1342.  // -> insert the vertex
  1343.  Entry:= NextVertexEntry();
  1344.  Entry.Vertex.x:= CurPt.x;
  1345.  Entry.Vertex.y:= CurPt.y;
  1346.  Entry.Color   := Color;
  1347.  Inc(FVertexCount);
  1348.  // (5) Insert the rest of vertices
  1349.  for i:= 1 to Steps do
  1350.   begin
  1351.    // 5a. Retreive next color from palette
  1352.    Color:= Palette.Color[i / Steps];
  1353.    // 5b. Insert inner vertex
  1354.    // -> angular position
  1355.    Alpha:= (i * (EndPhi - InitPhi) / Steps) + InitPhi;
  1356.    // -> vertex position
  1357.    CurPt.x:= x + Cos(Alpha) * InRadiusX;
  1358.    CurPt.y:= y - Sin(Alpha) * InRadiusY;
  1359.    // -> insert the vertex
  1360.    Entry:= NextVertexEntry();
  1361.    Entry.Vertex.x:= CurPt.x;
  1362.    Entry.Vertex.y:= CurPt.y;
  1363.    Entry.Color:= Color;
  1364.    Inc(FVertexCount);
  1365.    // 5c. Insert outer vertex
  1366.    // -> angular position
  1367.    Alpha:= (i * (EndPhi - InitPhi) / Steps) + InitPhi;
  1368.    // -> vertex position
  1369.    CurPt.x:= x + Cos(Alpha) * OutRadiusX;
  1370.    CurPt.y:= y - Sin(Alpha) * OutRadiusY;
  1371.    // -> insert the vertex
  1372.    Entry:= NextVertexEntry();
  1373.    Entry.Vertex.x:= CurPt.x;
  1374.    Entry.Vertex.y:= CurPt.y;
  1375.    Entry.Color:= Color;
  1376.    Inc(FVertexCount);
  1377.   end;
  1378.  {$IFNDEF FillRibbonUncached}
  1379.  // (6) Insert indexes
  1380.  for i:= 0 to Steps - 1 do
  1381.   begin
  1382.    AddIndexEntry(PreVtx);
  1383.    AddIndexEntry(PreVtx + 1);
  1384.    AddIndexEntry(PreVtx + 2);
  1385.    AddIndexEntry(PreVtx + 1);
  1386.    AddIndexEntry(PreVtx + 3);
  1387.    AddIndexEntry(PreVtx + 2);
  1388.    Inc(PreVtx, 2);
  1389.   end;
  1390.  {$ENDIF}
  1391.  Inc(FPrimitives, Steps * 2);
  1392.  {$IFDEF FillRibbonUncached}
  1393.  ResetCache();
  1394.  {$ENDIF}
  1395. end;
  1396. //---------------------------------------------------------------------------
  1397. procedure TAsphyreCanvas.FrameRibbonHw(x, y, InRadiusX, InRadiusY,
  1398.  OutRadiusX, OutRadiusY, InitPhi, EndPhi: Single; Steps: Integer;
  1399.  Color: Cardinal; DrawFx: Integer);
  1400. var
  1401.  i: Integer;
  1402.  Alpha: Single;
  1403.  CurPt: TPoint2;
  1404.  Entry: PVertexRecord;
  1405.  {$IFNDEF FrameRibbonUncached}PreVtx: Integer;{$ENDIF}
  1406. begin
  1407.  if (Steps < 1) then Exit;
  1408.  // (1) Check cache availability.
  1409.  {$IFDEF FrameRibbonUncached}
  1410.  // request non-indexed line strip to reduce bandwidth
  1411.  RequestCache(dmLineStrip, False, (Steps * 2) + 3, 0, DrawFx, nil);
  1412.  {$ELSE}
  1413.  // request indexed line list to improve cache performance
  1414.  RequestCache(dmLineList, True, (Steps * 2) + 2, (Steps * 2) + 3, DrawFx, nil);
  1415.  {$ENDIF}
  1416.  {$IFNDEF FrameRibbonUncached}
  1417.  PreVtx:= FVertexCount;
  1418.  {$ENDIF}
  1419.  // (2) Create first inner vertex
  1420.  CurPt.x:= x + Cos(InitPhi) * InRadiusX;
  1421.  CurPt.y:= y - Sin(InitPhi) * InRadiusY;
  1422.  // -> insert the vertex
  1423.  Entry:= NextVertexEntry();
  1424.  Entry.Vertex.x:= CurPt.x;
  1425.  Entry.Vertex.y:= CurPt.y;
  1426.  Entry.Color   := Color;
  1427.  Inc(FVertexCount);
  1428.  // (3) Create first outer vertex
  1429.  CurPt.x:= x + Cos(InitPhi) * OutRadiusX;
  1430.  CurPt.y:= y - Sin(InitPhi) * OutRadiusY;
  1431.  // -> insert the vertex
  1432.  Entry:= NextVertexEntry();
  1433.  Entry.Vertex.x:= CurPt.x;
  1434.  Entry.Vertex.y:= CurPt.y;
  1435.  Entry.Color   := Color;
  1436.  Inc(FVertexCount);
  1437.  // (4) Insert outer vertices.
  1438.  for i:= 1 to Steps do
  1439.   begin
  1440.    // -> angular position
  1441.    Alpha:= (i * (EndPhi - InitPhi) / Steps) + InitPhi;
  1442.    // -> vertex position
  1443.    CurPt.x:= x + Cos(Alpha) * OutRadiusX;
  1444.    CurPt.y:= y - Sin(Alpha) * OutRadiusY;
  1445.    // -> insert the vertex
  1446.    Entry:= NextVertexEntry();
  1447.    Entry.Vertex.x:= CurPt.x;
  1448.    Entry.Vertex.y:= CurPt.y;
  1449.    Entry.Color:= Color;
  1450.    Inc(FVertexCount);
  1451.   end;
  1452.  // (5) Insert inner vertices.
  1453.  {$IFDEF FrameRibbonUncached}
  1454.  for i:= Steps downto 0 do
  1455.  {$ELSE}
  1456.  for i:= Steps downto 1 do
  1457.  {$ENDIF}
  1458.   begin
  1459.    // -> angular position
  1460.    Alpha:= (i * (EndPhi - InitPhi) / Steps) + InitPhi;
  1461.    // -> vertex position
  1462.    CurPt.x:= x + Cos(Alpha) * InRadiusX;
  1463.    CurPt.y:= y - Sin(Alpha) * InRadiusY;
  1464.    // -> insert the vertex
  1465.    Entry:= NextVertexEntry();
  1466.    Entry.Vertex.x:= CurPt.x;
  1467.    Entry.Vertex.y:= CurPt.y;
  1468.    Entry.Color:= Color;
  1469.    Inc(FVertexCount);
  1470.   end;
  1471.  {$IFNDEF FrameRibbonUncached}
  1472.  AddIndexEntry(PreVtx);
  1473.  AddIndexEntry(PreVtx + 1);
  1474.  // (6) Insert indexes.
  1475.  for i:= 0 to (Steps * 2) - 1 do
  1476.   begin
  1477.    AddIndexEntry(PreVtx + 1 + i);
  1478.    AddIndexEntry(PreVtx + 2 + i);
  1479.   end;
  1480.  AddIndexEntry(PreVtx + (Steps * 2) + 1);
  1481.  AddIndexEntry(PreVtx);
  1482.  {$ENDIF}
  1483.  Inc(FPrimitives, 2 + Steps * 2);
  1484.  {$IFDEF FrameRibbonUncached}
  1485.  ResetCache();
  1486.  {$ENDIF}
  1487. end;
  1488. //---------------------------------------------------------------------------
  1489. procedure TAsphyreCanvas.FrameRibbonEx(x, y, InRadiusX, InRadiusY,
  1490.  OutRadiusX, OutRadiusY, InitPhi, EndPhi: Single; Steps: Integer;
  1491.  Color: Cardinal);
  1492. var
  1493.  Vertices: array of TD3DXVector2;
  1494.  vIndex  : Integer;
  1495.  i: Integer;
  1496.  Alpha: Single;
  1497. begin
  1498.  if (Steps < 1) then Exit;
  1499.  Flush();
  1500.  SetLength(Vertices, (Steps * 2) + 3);
  1501.  // (1) Create first inner vertex
  1502.  Vertices[0].x:= x + Cos(InitPhi) * InRadiusX;
  1503.  Vertices[0].y:= y - Sin(InitPhi) * InRadiusY;
  1504.  // (2) Create first outer vertex
  1505.  Vertices[1].x:= x + Cos(InitPhi) * OutRadiusX;
  1506.  Vertices[1].y:= y - Sin(InitPhi) * OutRadiusY;
  1507.  // (3) Insert outer vertices.
  1508.  vIndex:= 2;
  1509.  for i:= 1 to Steps do
  1510.   begin
  1511.    // -> angular position
  1512.    Alpha:= (i * (EndPhi - InitPhi) / Steps) + InitPhi;
  1513.    // -> vertex position
  1514.    Vertices[vIndex].x:= x + Cos(Alpha) * OutRadiusX;
  1515.    Vertices[vIndex].y:= y - Sin(Alpha) * OutRadiusY;
  1516.    Inc(vIndex);
  1517.   end;
  1518.  for i:= Steps downto 0 do
  1519.   begin
  1520.    // -> angular position
  1521.    Alpha:= (i * (EndPhi - InitPhi) / Steps) + InitPhi;
  1522.    // -> vertex position
  1523.    Vertices[vIndex].x:= x + Cos(Alpha) * InRadiusX - FClipRect.Left;
  1524.    Vertices[vIndex].y:= y - (Sin(Alpha) * InRadiusY + FClipRect.Top);
  1525.    Inc(vIndex);
  1526.   end;
  1527.  DXLine.Draw(@Vertices[0], (Steps * 2) + 3, Color);
  1528. end;
  1529. //---------------------------------------------------------------------------
  1530. procedure TAsphyreCanvas.UseImage(Image: TAsphyreCustomImage;
  1531.  const Mapping: TPoint4; TexNum: Integer = 0);
  1532. begin
  1533.  if (Image <> nil) then ActiveTex:= Image.Texture[TexNum]
  1534.   else ActiveTex:= nil;
  1535.  QuadMapping:= Mapping;
  1536. end;
  1537. //---------------------------------------------------------------------------
  1538. procedure TAsphyreCanvas.UseImage(Image: TAsphyreCustomImage;
  1539.  const Mapping: TPoint4px; TexNum: Integer = 0);
  1540. begin
  1541.  if (Image <> nil) then ActiveTex:= Image.Texture[TexNum]
  1542.   else ActiveTex:= nil;
  1543.  if (ActiveTex <> nil) then
  1544.   begin
  1545.    QuadMapping[0]:= ActiveTex.CoordToLogical(Mapping[0]);
  1546.    QuadMapping[1]:= ActiveTex.CoordToLogical(Mapping[1]);
  1547.    QuadMapping[2]:= ActiveTex.CoordToLogical(Mapping[2]);
  1548.    QuadMapping[3]:= ActiveTex.CoordToLogical(Mapping[3]);
  1549.   end else QuadMapping:= TexFull4;
  1550. end;
  1551. //---------------------------------------------------------------------------
  1552. procedure TAsphyreCanvas.UseImage(Image: TAsphyreCustomImage; Pattern: Integer);
  1553. begin
  1554.  if (Image <> nil) then
  1555.   begin
  1556.    if (Image is TAsphyreImage) then
  1557.     begin // Mapping using Pattern information
  1558.      ActiveTex:= TAsphyreImage(Image).RetreiveTex(Pattern, @QuadMapping);
  1559.     end else
  1560.     begin // Default mapping
  1561.      ActiveTex  := Image.Texture[0];
  1562.      QuadMapping:= TexFull4;
  1563.     end;
  1564.   end else ActiveTex:= nil;
  1565. end;
  1566. //---------------------------------------------------------------------------
  1567. procedure TAsphyreCanvas.UseImage(Image: TAsphyreCustomImage; Pattern: Integer;
  1568.  const SrcRect: TRect; Mirror: Boolean = False; Flip: Boolean = False);
  1569. begin
  1570.  if (Image <> nil) then
  1571.   begin
  1572.    if (Image is TAsphyreImage) then
  1573.     begin // Mapping using Pattern information
  1574.      ActiveTex:= TAsphyreImage(Image).RetreiveTex(Pattern, SrcRect, Mirror,
  1575.       Flip, @QuadMapping);
  1576.     end else UseImage(Image, pxRect4(SrcRect));
  1577.   end else
  1578.   begin
  1579.    ActiveTex  := nil;
  1580.    QuadMapping:= TexFull4;
  1581.   end;
  1582. end;
  1583. //---------------------------------------------------------------------------
  1584. procedure TAsphyreCanvas.UseImageTri(Image: TAsphyreCustomImage; const tx0,
  1585.  tx1, tx2: TPoint2; TexNum: Integer = 0);
  1586. begin
  1587.  if (Image <> nil) then ActiveTex:= Image.Texture[TexNum]
  1588.   else ActiveTex:= nil;
  1589.  QuadMapping[0]:= tx0;
  1590.  QuadMapping[1]:= tx1;
  1591.  QuadMapping[2]:= tx2;
  1592. end;
  1593. //---------------------------------------------------------------------------
  1594. procedure TAsphyreCanvas.UseImageTri(Image: TAsphyreCustomImage; const tx0,
  1595.  tx1, tx2: TPoint2px; TexNum: Integer = 0);
  1596. begin
  1597.  if (Image <> nil) then ActiveTex:= Image.Texture[TexNum]
  1598.   else ActiveTex:= nil;
  1599.  if (ActiveTex <> nil) then
  1600.   begin
  1601.    QuadMapping[0]:= ActiveTex.CoordToLogical(tx0);
  1602.    QuadMapping[1]:= ActiveTex.CoordToLogical(tx1);
  1603.    QuadMapping[2]:= ActiveTex.CoordToLogical(tx2);
  1604.   end;
  1605. end;
  1606. //---------------------------------------------------------------------------
  1607. procedure TAsphyreCanvas.TexMap(const Points: TPoint4; const Colors: TColor4;
  1608.  DrawFx: Integer);
  1609. var
  1610.  Entry: PVertexRecord;
  1611. begin
  1612.  {$IFDEF TexMapUncached}
  1613.  // request non-indexed triangle strip to reduce bandwidth
  1614.  RequestCache(dmTriangleStrip, False, 4, 0, DrawFx, ActiveTex);
  1615.  {$ELSE}
  1616.  // request indexed triangle list to improve cache performance
  1617.  RequestCache(dmTriangleList, True, 4, 6, DrawFx, ActiveTex);
  1618.  {$ENDIF}
  1619.  {$IFNDEF TexMapUncached}
  1620.  // insert index entries, if using index buffers
  1621.  AddIndexEntry(FVertexCount + 2);
  1622.  AddIndexEntry(FVertexCount);
  1623.  AddIndexEntry(FVertexCount + 1);
  1624.  AddIndexEntry(FVertexCount + 3);
  1625.  AddIndexEntry(FVertexCount + 2);
  1626.  AddIndexEntry(FVertexCount + 1);
  1627.  {$ENDIF}
  1628.  // insert vertices
  1629.  Entry:= NextVertexEntry();
  1630.  Entry.Vertex.x:= Points[0].x - 0.5;
  1631.  Entry.Vertex.y:= Points[0].y - 0.5;
  1632.  Entry.Color   := Colors[0];
  1633.  Entry.u:= QuadMapping[0].x;
  1634.  Entry.v:= QuadMapping[0].y;
  1635.  Inc(FVertexCount);
  1636.  Entry:= NextVertexEntry();
  1637.  Entry.Vertex.x:= Points[1].x - 0.5;
  1638.  Entry.Vertex.y:= Points[1].y - 0.5;
  1639.  Entry.Color   := Colors[1];
  1640.  Entry.u:= QuadMapping[1].x;
  1641.  Entry.v:= QuadMapping[1].y;
  1642.  Inc(FVertexCount);
  1643.  Entry:= NextVertexEntry();
  1644.  Entry.Vertex.x:= Points[3].x - 0.5;
  1645.  Entry.Vertex.y:= Points[3].y - 0.5;
  1646.  Entry.Color   := Colors[3];
  1647.  Entry.u:= QuadMapping[3].x;
  1648.  Entry.v:= QuadMapping[3].y;
  1649.  Inc(FVertexCount);
  1650.  Entry:= NextVertexEntry();
  1651.  Entry.Vertex.x:= Points[2].x - 0.5;
  1652.  Entry.Vertex.y:= Points[2].y - 0.5;
  1653.  Entry.Color   := Colors[2];
  1654.  Entry.u:= QuadMapping[2].x;
  1655.  Entry.v:= QuadMapping[2].y;
  1656.  Inc(FVertexCount);
  1657.  Inc(FPrimitives, 2);
  1658.  {$IFDEF TexMapUncached}
  1659.  ResetCache();
  1660.  {$ENDIF}
  1661. end;
  1662. //---------------------------------------------------------------------------
  1663. procedure TAsphyreCanvas.TexTri(const p1, p2, p3: TPoint2; c1, c2,
  1664.  c3: Cardinal; DrawFx: Integer);
  1665. var
  1666.  Entry: PVertexRecord;
  1667. begin
  1668.  {$IFDEF TexTriUncached}
  1669.  // request non-indexed triangle strip to reduce bandwidth
  1670.  RequestCache(dmTriangleStrip, False, 3, 0, DrawFx, ActiveTex);
  1671.  {$ELSE}
  1672.  // request indexed triangle list to improve cache performance
  1673.  RequestCache(dmTriangleList, True, 3, 3, DrawFx, ActiveTex);
  1674.  {$ENDIF}
  1675.  {$IFNDEF TexTriUncached}
  1676.  // insert index entries, if using index buffers
  1677.  AddIndexEntry(FVertexCount);
  1678.  AddIndexEntry(FVertexCount + 1);
  1679.  AddIndexEntry(FVertexCount + 2);
  1680.  {$ENDIF}
  1681.  // insert vertices
  1682.  Entry:= NextVertexEntry();
  1683.  Entry.Vertex.x:= p1.x - 0.5;
  1684.  Entry.Vertex.y:= p1.y - 0.5;
  1685.  Entry.Color   := c1;
  1686.  Entry.u:= QuadMapping[0].x;
  1687.  Entry.v:= QuadMapping[0].y;
  1688.  Inc(FVertexCount);
  1689.  Entry:= NextVertexEntry();
  1690.  Entry.Vertex.x:= p2.x - 0.5;
  1691.  Entry.Vertex.y:= p2.y - 0.5;
  1692.  Entry.Color   := c2;
  1693.  Entry.u:= QuadMapping[1].x;
  1694.  Entry.v:= QuadMapping[1].y;
  1695.  Inc(FVertexCount);
  1696.  Entry:= NextVertexEntry();
  1697.  Entry.Vertex.x:= p3.x - 0.5;
  1698.  Entry.Vertex.y:= p3.y - 0.5;
  1699.  Entry.Color   := c3;
  1700.  Entry.u:= QuadMapping[3].x;
  1701.  Entry.v:= QuadMapping[3].y;
  1702.  Inc(FVertexCount);
  1703.  Inc(FPrimitives);
  1704.  {$IFDEF TexTriUncached}
  1705.  ResetCache();
  1706.  {$ENDIF}
  1707. end;
  1708. //---------------------------------------------------------------------------
  1709. end.