UOpenGLCanvas.pas
上传用户:zkjn0718
上传日期:2021-01-01
资源大小:776k
文件大小:71k
源码类别:

Delphi/CppBuilder

开发平台:

Delphi

  1. unit UOpenGLCanvas;
  2. { This unit is written by Qianyuan Wang. One version is contributed to CnPack(www.cnpack.org) and this version
  3.    doens't require you install the component. 
  4.   http://hi.baidu.com/wqyfavor
  5.   wqyfavor@163.com
  6.   QQ: 466798985}
  7. interface
  8. {$I OpenGLCanvas.inc}
  9. uses
  10.    Math,
  11.    Windows,
  12.    Classes,
  13.    Controls,
  14.    Graphics,
  15.    OpenGL,
  16.    ExtCtrls;
  17. const
  18.    TransformStackTop = 10;
  19.    ListNestLevel = 9;
  20.    MaxChar = 128;
  21. type
  22.    ARGB = type Cardinal;
  23.    // Use TARGB(ARGB) to quick access elements of an ARGB color
  24.    TARGB = packed record
  25.       blue, green, red, alpha: Byte;
  26.    end;
  27.    PSingleArray = ^TSingleArray;
  28.    TSingleArray = array of Single;
  29.    TColorVector = array[0..3] of Single;
  30.    TVector4f = array[0..3] of Single;
  31.    PMatrix4f = ^TMatrix4f;
  32.    TMatrix4f = array[0..3] of TVector4f;
  33.    PGLPointF = ^TGLPointF;
  34.    TGLPointF = packed record
  35.       X: Single;
  36.       Y: Single;
  37.    end;
  38.    PGLPointsF = ^TGLPointsF;
  39.    TGLPointsF = array of TGLPointF;
  40.    PGLPointI = ^TGLPointI;
  41.    TGLPointI = TPoint;
  42.    PGLPointsI = ^TGLPointsI;
  43.    TGLPointsI = array of TGLPointI;
  44.    TTransformType = (ttScale, ttTranslate, ttRotate);
  45.    TTransformData = record
  46.       TransformType: TTransformType;
  47.       var1, var2: Single;
  48.    end;
  49.    TLineStippleStyle = (lssSolid, lssDash, lssDashDot, lssDashDotDot, lssDot);
  50.    TGLCanvas = class;
  51.    TAfterRendering = procedure(Sender: TGLCanvas) of object;
  52.    TGetDCFunction = function: HDC of object;
  53.    TGLFontNotify = procedure of object;
  54.    TGLFont = class
  55.    private
  56.       FHFont: HFONT;
  57.       FName: WideString;
  58.       FSize: Integer;
  59.       FStyles: TFontStyles;
  60.       FCharSet: Integer;
  61.       FColor: ARGB;
  62.       FColorVector: TColorVector;
  63.       FNotifyChange: TGLFontNotify;
  64.       function FGetWinColor: TColor;
  65.       procedure FSetWinColor(value: TColor);
  66.       procedure FSetColor(value: ARGB);
  67.    public
  68.       constructor Create(Name: WideString; Size: Integer; Styles: TFontStyles = [];
  69.          CharSet: Integer = DEFAULT_CHARSET; Notify: TGLFontNotify = nil);
  70.       destructor Destroy; override;
  71.       procedure Update; // call Update after modifying Name, Size ...
  72.       property HFont: HFONT read FHFont write FHFont;
  73.       property Name: WideString read FName write FName;
  74.       property Size: Integer read FSize write FSize;
  75.       property Styles: TFontStyles read FStyles write FStyles;
  76.       property CharSet: Integer read FCharSet write FCharSet;
  77.       property Color: ARGB read FColor write FSetColor; // do not need to call Update
  78.       property WinColor: TColor read FGetWinColor write FSetWinColor; // do not need to call Update
  79.       property NotifyChange: TGLFontNotify read FNotifyChange write FNotifyChange;
  80.    end;
  81.    TGLCanvas = class
  82.    private
  83.       FHRC: HGLRC;
  84.       FControl: TControl;
  85.       FAfterRendering: TAfterRendering;
  86.       FGetDCFunction: TGetDCFunction;
  87.       FRenderToBmp: Boolean;
  88.       FBufferHDC: HDC;
  89.       FBufferBitmap: HBITMAP;
  90.       FBufferObject: HGDIOBJ;
  91.       FBufferWidth, FBufferHeight: Integer;
  92.       FInvertY: Boolean;
  93.       FRendering: Boolean;
  94.       FBlend: Boolean;
  95.       FAntialiasing: Boolean;
  96.       FIgnorePenWidthFactor: Boolean;
  97.       FListLevel: Integer;
  98.       FIgnoreColor: Boolean;
  99.       FIgnoreColorStack: array[1..ListNestLevel] of Boolean;
  100.       FPenWidthFactor: Single; // Actually the total scale
  101.       FPenWidth: Single;
  102.       FPenColorARGB, FBrushColorARGB: ARGB;
  103.       FPenColor, FBrushColor: TColorVector;
  104.       FMatrix: TMatrix4f; // For backup
  105.       FTransformationUpdateCount: Integer;
  106.       FUseTransformStack: Boolean;
  107.       FTransformStack: array[0..TransformStackTop] of TTransformData;
  108.       FStackTop: Integer;
  109.       FScaleX, FScaleY: Single;
  110.       FTranslateX, FTranslateY: Single;
  111.       FRotation: Single;
  112.       FDefaultFont: TGLFont;
  113.       FASCIICharList: GLuint;
  114.       FASCIICharListCreated: Boolean;
  115.       procedure InitOpenGL;
  116.       procedure ActivateSelf;
  117.       procedure CreateBufferBMP;
  118.       procedure FreeBufferBMP;
  119.       procedure PresentBufferBMP(DC: HDC);
  120.       procedure ApplyTransformation;
  121.       procedure DefaultFontNotify;
  122.       procedure FSetAntialiasing(value: Boolean);
  123.       procedure FSetScaleX(value: Single);
  124.       procedure FSetScaleY(value: Single);
  125.       procedure FSetTranslateX(value: Single);
  126.       procedure FSetTranslateY(value: Single);
  127.       procedure FSetRotation(value: Single);
  128.       procedure FSetPenColor(Value: ARGB);
  129.       procedure FSetBrushColor(Value: ARGB);
  130.       procedure FSetPenWidth(Value: Single);
  131.       procedure EllipseVertices(const x, y, xRadius, yRadius: Single);
  132.    public
  133.       constructor Create(AControl: TControl; RenderToBmp: Boolean = True;
  134.          Antialiasing: Boolean = True; UseTransformStack: Boolean = False;
  135.          IgnorePenWidthFactor: Boolean = False; InvertY: Boolean = True);
  136.       destructor Destroy; override;
  137.       function RenderingBegin(BackgroundColor: TColor = clWhite): TGLCanvas;
  138.       procedure RenderingEnd;
  139.       { You can either build draw lists in Rendering process or not.
  140.         An example:
  141.            GLCanvas.CreateList(List1, 1).ListBegin(List1).Line(0, 0, 50, 50).ListEnd;
  142.            GLCanvas.RenderingBegin.ListExecute(List1).SetTranslateX(50).ListExecute(box).RenderingEnd;
  143.         If IgnoreColor is true, all color definition in fill-shape processes are
  144.         ignored. When the list is built, you can specify color for all vertices of
  145.         the list.  }
  146.       function CreateList(var ListID: GLuint; Range: GLuint = 1): TGLCanvas;
  147.       function DeleteList(ListID: GLuint; Range: GLuint = 1): TGLCanvas;
  148.       function ListBegin(ListID: GLuint; Offset: GLuint = 0; Execute: Boolean = False;
  149.          IgnoreColor: Boolean = True): TGLCanvas;
  150.       function ListEnd: TGLCanvas;
  151.       function ListExecute(ListID: GLuint; Offset: GLuint = 0): TGLCanvas; overload;
  152.       function ListExecute(ListID: GLuint; Offset: GLuint; Color: ARGB;
  153.          PenWidth: Single): TGLCanvas; overload; // PenWidth <= 0 for no change
  154.       { Call Recreate if you want to manually recreate opengl. Normally if Control
  155.         is resized, GLCanvas will detect this change at the beginning of next
  156.         rendering process. }
  157.       procedure Recreate;
  158.       procedure OnControlPaint;
  159.       procedure DrawTo(DC: HDC);
  160.       procedure StretchDrawTo(DC: HDC; X, Y, W, H: Integer);
  161.       ///////////////////////////////////////////////
  162.       function BeginUpdateTransformation: TGLCanvas;
  163.       function EndUpdateTransformation: TGLCanvas;
  164.       // Use transformation for rendering. Not effective for TextOut.
  165.       function SetTransformation(sx, sy, tx, ty, r: Single): TGLCanvas; // Scale, Translate, Rotation
  166.       function SetMatrix(const m11, m12, m13, m21, m22, m23, m31, m32, m33,
  167.          dx, dy: Single; Backup: Boolean = True): TGLCanvas;
  168.       function ResetBackupMatrix: TGLCanvas;
  169.       function ResetTransformation: TGLCanvas;
  170.       function PopMatrix: TGLCanvas; // Cancel last transformation
  171.       function SetEqualScale(value: Single): TGLCanvas;
  172.       function ScaleMatrix(x, y: Single): TGLCanvas;
  173.       function TranslateMatrix(x, y: Single): TGLCanvas;
  174.       function RotateMatrix(angle: Single): TGLCanvas;
  175.       function SetScaleX(value: Single): TGLCanvas;
  176.       function SetScaleY(value: Single): TGLCanvas;
  177.       function SetTranslateX(value: Single): TGLCanvas;
  178.       function SetTranslateY(value: Single): TGLCanvas;
  179.       function SetRotation(value: Single): TGLCanvas;
  180.       function ConvertScreenToWorld(x, y: Integer): TGLPointF; // GDI coordinate where (0, 0) is Left-Top
  181.       function UpdateTransformation: TGLCanvas; // You can maually force update transformation
  182.       ///////////////////////////////////////////////
  183.       function SetBlendState(value: Boolean): TGLCanvas; // Use this to enable or disable GL_BLEND, GL_BLEND is enabled by default.
  184.       ///////////////////////////////////////////////
  185.       function SetPenColorWin(value: TColor; alpha: Byte = 255; Sync: Boolean = True): TGLCanvas;
  186.       function SetBrushColorWin(value: TColor; alpha: Byte = 255; Sync: Boolean = True): TGLCanvas;
  187.       function SetPenColor(value: ARGB): TGLCanvas; overload; // for linked process
  188.       function SetBrushColor(value: ARGB): TGLCanvas; overload; // for linked process
  189.       // For quick OpenGL color assignment. Sync = True, update FPenColorARGB or FBrushColorARGB
  190.       function SetPenColor(const value: TColorVector; Sync: Boolean = False): TGLCanvas; overload;
  191.       function SetBrushColor(const value: TColorVector; Sync: Boolean = False): TGLCanvas; overload;
  192.       function SetPenWidth(value: Single): TGLCanvas; // for linked process
  193.       function LineStipple(factor: Integer; pattern: word): TGLCanvas; overload;
  194.       function LineStipple(style: TLineStippleStyle; enlarge: Byte = 2): TGLCanvas; overload;
  195.       function LineStippleEnd: TGLCanvas;
  196.       function Line(const x1, y1, x2, y2: Integer): TGLCanvas; overload;
  197.       function Line(const x1, y1, x2, y2: Single): TGLCanvas; overload;
  198.       function BeginLines: TGLCanvas; // Remember to call EndLines
  199.       function Lines(const x1, y1, x2, y2: Integer): TGLCanvas; overload;
  200.       function Lines(const x1, y1, x2, y2: Single): TGLCanvas; overload;
  201.       function EndLines: TGLCanvas;
  202.       function Lines(const points: TGLPointsF; count: Integer): TGLCanvas; overload;
  203.       function Lines(const points: TGLPointsI; count: Integer): TGLCanvas; overload;
  204.       function Polyline(const points: TGLPointsF; count: Integer): TGLCanvas; overload;
  205.       function Polyline(const points: TGLPointsI; count: Integer): TGLCanvas; overload;
  206.       function Polygon(const points: TGLPointsF; count: Integer): TGLCanvas; overload;
  207.       function Polygon(const points: TGLPointsI; count: Integer): TGLCanvas; overload;
  208.       function FillPolygon(const points: TGLPointsF; count: Integer; Border: Boolean = False): TGLCanvas; overload;
  209.       function FillPolygon(const points: TGLPointsI; count: Integer; Border: Boolean = False): TGLCanvas; overload;
  210.       function Curve(const points: TGLPointsF; count: Integer; tension: Single = 0.5): TGLCanvas; overload;
  211.       function Curve(const points: TGLPointsI; count: Integer; tension: Single = 0.5): TGLCanvas; overload;
  212.       function ClosedCurve(const points: TGLPointsF; count: Integer; tension: Single = 0.5): TGLCanvas; overload;
  213.       function ClosedCurve(const points: TGLPointsI; count: Integer; tension: Single = 0.5): TGLCanvas; overload;
  214.       function FillClosedCurve(const points: TGLPointsF; count: Integer;
  215.          Border: Boolean = False; tension: Single = 0.5): TGLCanvas; overload;
  216.       function FillClosedCurve(const points: TGLPointsI; count: Integer;
  217.          Border: Boolean = False; tension: Single = 0.5): TGLCanvas; overload;
  218.       function Bezier(const x1, y1, x2, y2, x3, y3, x4, y4: Integer): TGLCanvas; overload;
  219.       function Bezier(const x1, y1, x2, y2, x3, y3, x4, y4: Single): TGLCanvas; overload;
  220.       function PolyBezier(const points: TGLPointsI; count: Integer): TGLCanvas; overload;
  221.       function PolyBezier(const points: TGLPointsF; count: Integer): TGLCanvas; overload;
  222.       // x, y, xRadius, yRadius specify an ellipse. startAngle and sweepAngle specify the range of curve.
  223.       function Arc(const x, y, xRadius, yRadius: Single; startAngle, sweepAngle: Single): TGLCanvas;
  224.       function FillPie(const x, y, xRadius, yRadius: Single;
  225.          startAngle, sweepAngle: Single; Border: Boolean = False): TGLCanvas;
  226.       // Plots a pixel at given coordinate
  227.       function PlotPixel(const x, y: Integer): TGLCanvas; overload;
  228.       function PlotPixel(const x, y: Single): TGLCanvas; overload;
  229.       function BeginPixels: TGLCanvas; // Remember to call EndLines
  230.       function Pixels(const x, y: Integer): TGLCanvas; overload;
  231.       function Pixels(const x, y: Single): TGLCanvas; overload;
  232.       function EndPixels: TGLCanvas;
  233.       // Draw the (x1,y1)-(x2, y2) rectangle's frame (border). }
  234.       function FrameRect(const x1, y1, x2, y2: Integer): TGLCanvas; overload;
  235.       function FrameRect(const x1, y1, x2, y2: Single): TGLCanvas; overload;
  236.       // Draw the (x1,y1)-(x2, y2) rectangle (filled with BrushColor)
  237.       function FillRect(const x1, y1, x2, y2: Integer; Border: Boolean = False): TGLCanvas; overload;
  238.       function FillRect(const x1, y1, x2, y2: Single; Border: Boolean = False): TGLCanvas; overload;
  239.       function Triangle(const x1, y1, x2, y2, x3, y3: Integer): TGLCanvas; overload;
  240.       function Triangle(const x1, y1, x2, y2, x3, y3: Single): TGLCanvas; overload;
  241.       function FillTriangle(const x1, y1, x2, y2, x3, y3: Integer; Border: Boolean = False): TGLCanvas; overload;
  242.       function FillTriangle(const x1, y1, x2, y2, x3, y3: Single; Border: Boolean = False): TGLCanvas; overload;
  243.       // Draws an ellipse with (x1,y1)-(x2, y2) bounding rectangle.
  244.       function EllipseRect(const x1, y1, x2, y2 : Single): TGLCanvas; overload;
  245.       // Draws and ellipse centered at (x, y) with given radiuses.
  246.       function Ellipse(const x, y, xRadius, yRadius: Single): TGLCanvas; overload;
  247.       function FillEllipseRect(const x1, y1, x2, y2: Single; Border: Boolean = False): TGLCanvas; overload;
  248.       function FillEllipse(const x, y, xRadius, yRadius: Single; Border: Boolean = False): TGLCanvas; overload;
  249.       procedure RecreateDefaultFont;
  250.       // Output only ASCII chars, other chars will be ignored automatically
  251.       function TextOutASCII(const text: string; x, y: Integer; Font: TGLFont = nil): TGLCanvas; // Use this for ASCII chars for efficiency
  252.       // Output any string but slow
  253.       function TextOut(const text: WideString; x, y: Integer; Font: TGLFont = nil): TGLCanvas;
  254.       function BuildTexture(bmp: TBitmap; var texId: GLuint): TGLCanvas;
  255.       function DeleteTexture(texId: GLuint): TGLCanvas;
  256.       //The difference between DrawBitmap and DrawBitmapTex is that DrawBitmapTex supports transformation}
  257.       function DrawBitmap(bmp: TBitmap; x, y: Integer; xZoom: Single = 1.0; yZoom: Single = 1.0): TGLCanvas; overload;
  258.       function DrawBitmapTex(bmp: TBitmap; x, y, w, h: Integer): TGLCanvas; overload;
  259.       function DrawBitmapTex(texId: GLuint; x, y, w, h: Integer): TGLCanvas; overload;
  260.       // Transformation
  261.       property UseTransformStack: Boolean read FUseTransformStack write FUseTransformStack;
  262.       property AfterRendering: TAfterRendering read FAfterRendering write FAfterRendering;
  263.       property GetDCFunction: TGetDCFunction read FGetDCFunction write FGetDCFunction;
  264.       // Turn off UseTransformStack to use these parameters
  265.       property ScaleX: Single read FScaleX write FSetScaleX;
  266.       property ScaleY: Single read FScaleY write FSetScaleY;
  267.       property TranslateX: Single read FTranslateX write FSetTranslateX;
  268.       property TranslateY: Single read FTranslateY write FSetTranslateY;
  269.       property Rotation: Single read FRotation write FSetRotation;
  270.       property RenderToBMP: Boolean read FRenderToBmp;
  271.       property BufferHDC: HDC read FBufferHDC write FBufferHDC;
  272.       property Rendering: Boolean read FRendering;
  273.       property PenColor: ARGB read FPenColorARGB write FSetPenColor;
  274.       property BrushColor: ARGB read FBrushColorARGB write FSetBrushColor;
  275.       property Control: TControl read FControl;
  276.       property InvertY: Boolean read FInvertY;
  277.       property Antialiasing: Boolean read FAntialiasing write FSetAntialiasing;
  278.       property PenWidth: Single read FPenWidth write FSetPenWidth;
  279.       property DefaultFont: TGLFont read FDefaultFont;
  280.    end;
  281. const
  282.    IdentityHmgMatrix: TMatrix4f = ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1));
  283.    AlphaShift = 24;
  284.    RedShift = 16;
  285.    GreenShift = 8;
  286.    BlueShift = 0;
  287. function MakeColor(r, g, b: Byte): ARGB; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
  288. function MakeColor(a, r, g, b: Byte): ARGB; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
  289. function GetAlpha(color: ARGB): BYTE; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
  290. function GetRed(color: ARGB): BYTE; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
  291. function GetGreen(color: ARGB): BYTE; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
  292. function GetBlue(color: ARGB): BYTE; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
  293. // TColor = COLORREF
  294. function TColorToARGB(rgb: TColor; alpha: Byte = 255): ARGB; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
  295. function ARGBToTColor(Color: ARGB): TColor; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
  296. function GLColorToARGB(const glcolor: TColorVector): ARGB;  {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
  297. function ARGBToGLColor(color: ARGB): TColorVector; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
  298. function GLColorToTColor(const glcolor: TColorVector): TColor; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
  299. function TColorToGLColor(color: TColor; alpha: Byte = 255): TColorVector; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
  300. implementation
  301. var
  302.    GLOBAL_ANTIALIASING_STATE: Boolean;
  303. const
  304.    // Almost all video cards now support these extensions. Even not, no error will be raised.
  305.    GL_TEXTURE_3D = $806F;
  306.    GL_TEXTURE_CUBE_MAP_ARB = $8513;
  307.    GL_BGR = $80E0;
  308.    cNoPrimitive = MaxInt;
  309.    PiDiv180 = Pi / 180;
  310.    _2Pi = Pi * 2;
  311.    PiDiv2 = Pi / 2;
  312.    opengl32 = 'OpenGL32.dll';
  313. procedure glGenTextures(n: GLsizei; textures: PGLuint); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF UNIX} cdecl; {$ENDIF} external opengl32;
  314. procedure glBindTexture(target: GLEnum; texture: GLuint); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF UNIX} cdecl; {$ENDIF} external opengl32;
  315. procedure glDeleteTextures(n: GLsizei; textures: PGLuint); {$IFDEF MSWINDOWS} stdcall; {$ENDIF} {$IFDEF UNIX} cdecl; {$ENDIF} external opengl32;
  316. procedure SinCos(const Theta: Single; var Sin, Cos: Single);
  317. asm
  318.    FLD  Theta
  319.    FSINCOS
  320.    FSTP DWORD PTR [EDX]    // cosine
  321.    FSTP DWORD PTR [EAX]    // sine
  322. end;
  323. function MakeColor(r, g, b: Byte): ARGB; overload;
  324. begin
  325.    with TARGB(Result) do
  326.    begin
  327.       alpha := 255;
  328.       red := r;
  329.       green := g;
  330.       blue := b;
  331.    end;
  332. end;
  333. function MakeColor(a, r, g, b: Byte): ARGB; overload;
  334. begin
  335.    with TARGB(Result) do
  336.    begin
  337.       alpha := a;
  338.       red := r;
  339.       green := g;
  340.       blue := b;
  341.    end;
  342. end;
  343. function GetAlpha(color: ARGB): BYTE;
  344. begin
  345.    Result := BYTE(color shr AlphaShift);
  346. end;
  347. function GetRed(color: ARGB): BYTE;
  348. begin
  349.    Result := BYTE(color shr RedShift);
  350. end;
  351. function GetGreen(color: ARGB): BYTE;
  352. begin
  353.    Result := BYTE(color shr GreenShift);
  354. end;
  355. function GetBlue(color: ARGB): BYTE;
  356. begin
  357.    Result := BYTE(color shr BlueShift);
  358. end;
  359. function TColorToARGB(rgb: TColor; alpha: Byte = 255): ARGB;
  360. begin
  361.    Result := MakeColor(alpha, GetRValue(rgb), GetGValue(rgb), GetBValue(rgb));
  362. end;
  363. function ARGBToTColor(Color: ARGB): TColor;
  364. begin
  365.    with TARGB(Color) do
  366.       Result := RGB(red, green, blue);
  367. end;
  368. function GLColorToARGB(const glcolor: TColorVector): ARGB;
  369. begin
  370.    Result := MakeColor(Trunc(255 * glcolor[3]), Trunc(255 * glcolor[0]),
  371.       Trunc(255 * glcolor[1]), Trunc(255 * glcolor[2]));
  372. end;
  373. function ARGBToGLColor(color: ARGB): TColorVector;
  374. begin
  375.    with TARGB(color) do
  376.    begin
  377.       Result[0] := red / 255;
  378.       Result[1] := green / 255;
  379.       Result[2] := blue / 255;
  380.       Result[3] := alpha / 255;
  381.    end;
  382. end;
  383. function GLColorToTColor(const glcolor: TColorVector): TColor;
  384. begin
  385.    Result := RGB(Trunc(255 * glcolor[0]), Trunc(255 * glcolor[1]), Trunc(255 * glcolor[2]));
  386. end;
  387. function TColorToGLColor(color: TColor; alpha: Byte = 255): TColorVector;
  388. begin
  389.    Result[0] := GetRValue(color) / 255;
  390.    Result[1] := GetGValue(color) / 255;
  391.    Result[2] := GetBValue(color) / 255;
  392.    Result[3] := alpha / 255;
  393. end;
  394. { TGLFont }
  395. constructor TGLFont.Create(Name: WideString; Size: Integer; Styles: TFontStyles = [];
  396.    CharSet: Integer = DEFAULT_CHARSET; Notify: TGLFontNotify = nil);
  397. begin
  398.    FHFont := 0;
  399.    FName := Name;
  400.    FSize := Size;
  401.    FStyles := Styles;
  402.    FCharSet := CharSet;
  403.    FColor := TColorToARGB(clBlack);
  404.    FNotifyChange := Notify;
  405.    Update;
  406. end;
  407. destructor TGLFont.Destroy;
  408. begin
  409.    DeleteObject(FHFont);
  410.    inherited;
  411. end;
  412. function TGLFont.FGetWinColor: TColor;
  413. begin
  414.    Result := ARGBToTColor(FColor);
  415. end;
  416. procedure TGLFont.FSetWinColor(value: TColor);
  417. begin
  418.    Color := TColorToARGB(value);
  419. end;
  420. procedure TGLFont.FSetColor(value: ARGB);
  421. begin
  422.    FColor := value;
  423.    FColorVector := ARGBToGLColor(FColor);
  424. end;
  425. procedure TGLFont.Update;
  426. var
  427.    bold, italic, underline, strikeout: Integer;
  428. begin
  429.    if FHFont <> 0 then
  430.       DeleteObject(FHFont);
  431.    if fsBold in FStyles then
  432.       bold := FW_BOLD
  433.    else
  434.       bold := FW_NORMAL;
  435.    if fsItalic in FStyles then
  436.       italic := 1
  437.    else
  438.       italic := 0;
  439.    if fsUnderline in FStyles then
  440.       underline := 1
  441.    else
  442.       underline := 0;
  443.    if fsStrikeOut in FStyles then
  444.       strikeout := 1
  445.    else
  446.       strikeout := 0;
  447.    FHFont := CreateFontW(FSize, 0, 0, 0, bold, italic, underline, strikeout,
  448.         FCharSet, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  449.         DEFAULT_QUALITY, DEFAULT_PITCH or FF_SWISS, PWideChar(FName));
  450.    FColorVector := ARGBToGLColor(FColor);
  451.    if Assigned(FNotifyChange) then
  452.       FNotifyChange;
  453. end;
  454. { TGLCanvas }
  455. constructor TGLCanvas.Create(AControl: TControl; RenderToBmp: Boolean = True;
  456.    Antialiasing: Boolean = True; UseTransformStack: Boolean = False;
  457.    IgnorePenWidthFactor: Boolean = False; InvertY: Boolean = True);
  458. begin
  459.    FControl := AControl;
  460.    FRenderToBmp := RenderToBmp;
  461.    if not FRenderToBmp then // Require that FControl is TWinControl
  462.       if not (FControl is TWinControl) then
  463.          FRenderToBmp := True;
  464.    FUseTransformStack := UseTransformStack;
  465.    FInvertY := InvertY;
  466.    FRendering := False;
  467.    FAntialiasing := Antialiasing;
  468.    FIgnorePenWidthFactor := IgnorePenWidthFactor;
  469.    FListLevel := 0;
  470.    FIgnoreColor := False;
  471.    FPenWidth := 1.0;
  472.    FStackTop := -1;
  473.    FTranslateX := 0.0;
  474.    FTranslateY := 0.0;
  475.    FScaleX := 1.0;
  476.    FScaleY := 1.0;
  477.    FRotation := 0.0;
  478.    FTransformationUpdateCount := 0;
  479.    SetPenColorWin(clBlack);
  480.    SetBrushColorWin(clRed);
  481.    FASCIICharListCreated := False;
  482.    FDefaultFont := TGLFont.Create('Tahoma', 14);
  483.    FDefaultFont.NotifyChange := DefaultFontNotify; // Mustn't assign NotifyChange by TGLFont.Create
  484.    FBufferWidth := -1;
  485.    Recreate;
  486. end;
  487. destructor TGLCanvas.Destroy;
  488. begin
  489.    FreeBufferBMP;
  490.    wglDeleteContext(FHRC);
  491.    FDefaultFont.Free;
  492.    inherited;
  493. end;
  494. procedure TGLCanvas.CreateBufferBMP;
  495. var
  496.    bmi: BITMAPINFO;
  497.    pbits: ^DWORD;
  498. begin
  499.    if FBufferWidth <> -1 then
  500.       FreeBufferBMP;
  501.    FBufferWidth := FControl.ClientWidth;
  502.    FBufferHeight := FControl.ClientHeight;
  503.    // Create a memory DC compatible with the screen
  504.    FBufferHDC := CreateCompatibleDC(0);
  505.    FillChar(bmi, SizeOf(bmi), 0);
  506.    with bmi.bmiHeader do
  507.    begin
  508.       biSize := SizeOf(BITMAPINFOHEADER);
  509.       biWidth := FBufferWidth;
  510.       biHeight := FBufferHeight;
  511.       biPlanes := 1;
  512.       biBitCount := 32;
  513.       biCompression := BI_RGB;
  514.    end;
  515.    FBufferBitmap := CreateDIBSection(FBufferHDC, bmi, DIB_RGB_COLORS, Pointer(pbits), 0, 0);
  516.    // Select the bitmap into the DC
  517.    FBufferObject := SelectObject(FBufferHDC, FBufferBitmap);
  518. end;
  519. procedure TGLCanvas.FreeBufferBMP;
  520. begin
  521.    SelectObject(FBufferHDC, FBufferObject); // Remove bitmap from DC
  522.    DeleteObject(FBufferBitmap); // Delete bitmap
  523.    DeleteDC(FBufferHDC); // Delete DC
  524. end;
  525. procedure TGLCanvas.PresentBufferBMP(DC: HDC);
  526. begin
  527.    StretchBlt(DC, 0, 0, FControl.ClientWidth,
  528.       FControl.ClientHeight, FBufferHDC, 0, 0, FBufferWidth,
  529.       FBufferHeight, SRCCOPY);
  530. end;
  531. procedure TGLCanvas.FSetPenColor(Value: ARGB);
  532. begin
  533.    if FPenColorARGB <> Value then
  534.    begin
  535.       FPenColorARGB := Value;
  536.       FPenColor := ARGBToGLColor(Value);
  537.    end;
  538.    glColor4fv(@FPenColor);
  539. end;
  540. procedure TGLCanvas.FSetBrushColor(Value: ARGB);
  541. begin
  542.    if FBrushColorARGB <> Value then
  543.    begin
  544.       FBrushColorARGB := Value;
  545.       FBrushColor := ARGBToGLColor(Value);
  546.    end;
  547. end;
  548. procedure TGLCanvas.FSetPenWidth(Value: Single);
  549. begin
  550.    FPenWidth := Value;
  551.    glLineWidth(Value * FPenWidthFactor);
  552.    glPointSize(Value * FPenWidthFactor);
  553. end;
  554. procedure TGLCanvas.InitOpenGL;
  555. var
  556.    pfd: TPIXELFORMATDESCRIPTOR;
  557.    pixelFormat: Integer;
  558. begin
  559.    FillChar(pfd, SizeOf(pfd), 0);
  560.    with pfd do
  561.    begin
  562.       nSize := SizeOf(TPIXELFORMATDESCRIPTOR); // 此结构尺寸
  563.       nVersion := 1;
  564.       if FRenderToBmp then
  565.          dwFlags := PFD_SUPPORT_OPENGL or PFD_DRAW_TO_BITMAP
  566.       else
  567.          dwFlags := PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER or PFD_DRAW_TO_WINDOW;
  568.       iPixelType := PFD_TYPE_RGBA; //使用RGBA颜色空间
  569.       cColorBits := 32;
  570.       cDepthBits := 16;
  571.       iLayerType := PFD_MAIN_PLANE;
  572.    end;
  573.    pixelFormat := ChoosePixelFormat(FBufferHDC, @pfd);
  574.    SetPixelFormat(FBufferHDC, pixelFormat, @pfd);
  575.    FHRC := wglCreateContext(FBufferHDC);
  576.    wglMakeCurrent(FBufferHDC, FHRC);
  577.    GdiFlush();
  578.    glPushAttrib(GL_ENABLE_BIT);
  579.    glDisable(GL_CULL_FACE);
  580.    glDisable(GL_LIGHTING);
  581.    glDisable(GL_FOG);
  582.    glDisable(GL_COLOR_MATERIAL);
  583.    glDisable(GL_DEPTH_TEST);
  584.    glDisable(GL_TEXTURE_1D);
  585.    glDisable(GL_TEXTURE_2D);
  586.    glDisable(GL_TEXTURE_3D);
  587.    glDisable(GL_TEXTURE_CUBE_MAP_ARB);
  588.    FBlend := True;
  589.    glEnable(GL_BLEND);
  590.    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  591.    Antialiasing := FAntialiasing; // Apply antialiasing mode
  592.    glViewPort(0, 0, FBufferWidth, FBufferHeight); //指定OpenGL在此区域内绘图。
  593.    glMatrixMode(GL_PROJECTION);
  594.    if FInvertY then
  595.       gluOrtho2D(0, FBufferWidth, 0, FBufferHeight)
  596.    else
  597.       gluOrtho2D(0, FBufferWidth, FBufferHeight, 0);
  598.    glMatrixMode(GL_MODELVIEW);
  599.    // Recreate ASCII char lists
  600.    DefaultFontNotify;
  601. end;
  602. procedure TGLCanvas.ActivateSelf;
  603. begin
  604.    wglMakeCurrent(FBufferHDC, FHRC);
  605.    if GLOBAL_ANTIALIASING_STATE <> FAntialiasing then
  606.       FSetAntialiasing(FAntialiasing);
  607.    if FBlend then
  608.       glEnable(GL_BLEND)
  609.    else
  610.       glDisable(GL_BLEND);
  611. end;
  612. procedure TGLCanvas.ApplyTransformation;
  613.    function ComputeCompoundPenWidthFactor(sx, sy: Single): Single;
  614.    begin
  615.       Result := Sqrt((sx * sx + sy * sy) / 2);
  616.    end;
  617. var
  618.    i: Integer;
  619.    tx, ty: Single;
  620. begin
  621.    if not FRendering then
  622.       Exit;
  623.    if FUseTransformStack then
  624.    begin
  625.       glLoadIdentity;
  626.       tx := 1.0;
  627.       ty := 1.0;
  628.       for i := 0 to FStackTop do
  629.          with FTransformStack[i] do
  630.          begin
  631.             case TransformType of
  632.                ttScale:
  633.                   begin
  634.                      glScale(var1, var2, 1.0);
  635.                      tx := tx * var1;
  636.                      ty := ty * var2;
  637.                   end;
  638.                ttTranslate: glTranslate(var1, var2, 0.0);
  639.                ttRotate: glRotatef(var1, 0.0, 0.0, 1.0);
  640.             end;
  641.          end;
  642.       if FIgnorePenWidthFactor then
  643.          FPenWidthFactor := 1
  644.       else
  645.          FPenWidthFactor := ComputeCompoundPenWidthFactor(tx, ty);
  646.    end
  647.    else
  648.    begin
  649.       glLoadIdentity;
  650.       glTranslate(FTranslateX, FTranslateY, 0.0);
  651.       glScale(FScaleX, FScaleY, 1.0);
  652.       glRotatef(FRotation, 0.0, 0.0, 1.0);
  653.       if FIgnorePenWidthFactor then
  654.          FPenWidthFactor := 1
  655.       else
  656.          FPenWidthFactor := ComputeCompoundPenWidthFactor(FScaleX, FScaleY);
  657.    end;
  658. end;
  659. procedure TGLCanvas.DefaultFontNotify;
  660. var
  661.    i: Integer;
  662. begin
  663.    for i := 0 to 1 do // very odd, must call twice
  664.    begin
  665.       if FASCIICharListCreated then
  666.          glDeleteLists(FASCIICharList, MaxChar);
  667.       SelectObject(FBufferHDC, FDefaultFont.HFont);
  668.       FASCIICharList := glGenLists(MaxChar);
  669.       wglUseFontBitmaps(FBufferHDC, 0, MaxChar, FASCIICharList);
  670.       FASCIICharListCreated := True;
  671.    end;
  672. end;
  673. procedure TGLCanvas.FSetAntialiasing(value: Boolean);
  674. begin
  675.    if value then
  676.    begin
  677.       glEnable(GL_SMOOTH);
  678.       glEnable(GL_LINE_SMOOTH);
  679.       glEnable(GL_POINT_SMOOTH);
  680.       glEnable(GL_POLYGON_SMOOTH);
  681.       glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
  682.       glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
  683.       glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
  684.    end
  685.    else
  686.    begin
  687.       glDisable(GL_SMOOTH);
  688.       glDisable(GL_LINE_SMOOTH);
  689.       glDisable(GL_POINT_SMOOTH);
  690.       glDisable(GL_POLYGON_SMOOTH);
  691.       glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST);
  692.       glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);
  693.       glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST);
  694.    end;
  695.    FAntialiasing := value;
  696.    GLOBAL_ANTIALIASING_STATE := FAntialiasing;
  697. end;
  698. procedure TGLCanvas.FSetScaleX(value: Single);
  699. begin
  700.    FScaleX := value;
  701.    if FTransformationUpdateCount = 0 then
  702.       ApplyTransformation;
  703. end;
  704. procedure TGLCanvas.FSetScaleY(value: Single);
  705. begin
  706.    FScaleY := value;
  707.    if FTransformationUpdateCount = 0 then
  708.       ApplyTransformation;
  709. end;
  710. procedure TGLCanvas.FSetTranslateX(value: Single);
  711. begin
  712.    FTranslateX := value;
  713.    if FTransformationUpdateCount = 0 then
  714.       ApplyTransformation;
  715. end;
  716. procedure TGLCanvas.FSetTranslateY(value: Single);
  717. begin
  718.    FTranslateY := value;
  719.    if FTransformationUpdateCount = 0 then
  720.       ApplyTransformation;
  721. end;
  722. procedure TGLCanvas.FSetRotation(value: Single);
  723. begin
  724.    FRotation := value;
  725.    if FTransformationUpdateCount = 0 then
  726.       ApplyTransformation;
  727. end;
  728. function TGLCanvas.RenderingBegin(BackgroundColor: TColor = clWhite): TGLCanvas;
  729. var
  730.    bkCol: TColorVector;
  731. begin
  732.    Result := Self;
  733.    if FRendering then
  734.       Exit;
  735.    FRendering := True;
  736.    if (FBufferWidth <> FControl.ClientWidth) or (FBufferHeight <> FControl.ClientHeight) then
  737.       Recreate
  738.    {$IFDEF MultiCanvases}
  739.    else
  740.       ActivateSelf{$ENDIF}; // get active
  741.    bkCol := TColorToGLColor(BackgroundColor);
  742.    glClearColor(bkCol[0], bkCol[1], bkCol[2], bkCol[3]);
  743.    glClear(GL_COLOR_BUFFER_BIT);
  744.    ApplyTransformation;
  745.    // User must keep in mind that Matrix Mode mustn't be changed during rendering.
  746.    glColor4fv(@FPenColor);
  747. end;
  748. procedure TGLCanvas.RenderingEnd;
  749. begin
  750.    if FRenderToBMP then
  751.    begin
  752.       glFinish;
  753.       // User may draw other objects using Gdi, GdiP after OpenGL process.
  754.       if Assigned(FAfterRendering) then
  755.          FAfterRendering(Self);
  756.       // Present the image
  757.       if FControl is TImage then // TImage has the ability to keep its image
  758.          PresentBufferBMP(TImage(FControl).Canvas.Handle);
  759.       FControl.Repaint; // Other controls must repaint whenever they are repainted by Windows.
  760.    end
  761.    else
  762.       SwapBuffers(FBufferHDC);
  763.    FRendering := False;
  764. end;
  765. function TGLCanvas.CreateList(var ListID: GLuint; Range: GLuint = 1): TGLCanvas;
  766. begin
  767.    if Range >= 1 then
  768.    begin
  769.       {$IFDEF MultiCanvases}
  770.       ActivateSelf;
  771.       {$ENDIF}
  772.       ListID := glGenLists(Range);
  773.    end;
  774.    Result := Self;
  775. end;
  776. function TGLCanvas.DeleteList(ListID: GLuint; Range: GLuint = 1): TGLCanvas;
  777. begin
  778.    glDeleteLists(ListID, Range);
  779.    Result := Self;
  780. end;
  781. function TGLCanvas.ListBegin(ListID: GLuint; Offset: GLuint = 0;
  782.    Execute: Boolean = False; IgnoreColor: Boolean = True): TGLCanvas;
  783. begin
  784.    Result := Self;
  785.    if FListLevel = ListNestLevel then
  786.       Exit;
  787.       
  788.    if Execute then
  789.       glNewList(ListID + Offset, GL_COMPILE_AND_EXECUTE)
  790.    else
  791.       glNewList(ListID + Offset, GL_COMPILE);
  792.    Inc(FListLevel);
  793.    FIgnoreColorStack[FListLevel] := IgnoreColor;       
  794.    FIgnoreColor := IgnoreColor;
  795. end;
  796. function TGLCanvas.ListEnd: TGLCanvas;
  797. begin
  798.    glEndList;
  799.    Dec(FListLevel);
  800.    if FListLevel > 0 then
  801.       FIgnoreColor := FIgnoreColorStack[FListLevel]
  802.    else  
  803.       FIgnoreColor := False;    
  804.    Result := Self;      
  805. end;
  806. function TGLCanvas.ListExecute(ListID: GLuint; Offset: GLuint = 0): TGLCanvas;
  807. begin
  808.    if FRendering then
  809.       glCallList(ListID + Offset);
  810.    Result := Self;
  811. end;
  812. function TGLCanvas.ListExecute(ListID: GLuint; Offset: GLuint; Color: ARGB;
  813.    PenWidth: Single): TGLCanvas;
  814. var
  815.    ColorVec: TColorVector;
  816. begin
  817.    if FRendering then
  818.    begin
  819.       ColorVec := ARGBToGLColor(Color);
  820.       glColor4fv(@ColorVec);
  821.       if PenWidth > 0 then
  822.       begin
  823.          glLineWidth(PenWidth * FPenWidthFactor);
  824.          glPointSize(PenWidth * FPenWidthFactor);
  825.       end;
  826.       glCallList(ListID + Offset);
  827.       // Restore color and pen width
  828.       glColor4fv(@FPenColor);
  829.       if PenWidth > 0 then
  830.       begin
  831.          glLineWidth(FPenWidth * FPenWidthFactor);
  832.          glPointSize(FPenWidth * FPenWidthFactor);
  833.       end;
  834.    end;
  835.    Result := Self;
  836. end;
  837. procedure TGLCanvas.Recreate;
  838. begin
  839.    // Reinitialize opengl
  840.    if FRenderToBmp then
  841.       CreateBufferBMP
  842.    else
  843.    begin
  844.       FBufferHDC := GetDC(TWinControl(FControl).Handle);
  845.       FBufferWidth := FControl.ClientWidth;
  846.       FBufferHeight := FControl.ClientHeight;
  847.    end;
  848.    wglDeleteContext(FHRC);
  849.    InitOpenGL;
  850. end;
  851. procedure TGLCanvas.OnControlPaint;
  852. var
  853.    DC: HDC;
  854. begin
  855.    if FRenderToBmp then
  856.    begin
  857.       if FControl is TWinControl then
  858.          DC := GetDC(TWinControl(FControl).Handle)
  859.       else if Assigned(FGetDCFunction) then
  860.          DC := FGetDCFunction()
  861.       else
  862.          DC := 0;
  863.       if DC <> 0 then
  864.          PresentBufferBMP(DC);
  865.    end;
  866. end;
  867. procedure TGLCanvas.DrawTo(DC: HDC);
  868. begin
  869.    if FRenderToBmp then
  870.       StretchBlt(DC, 0, 0, FBufferWidth, FBufferHeight,
  871.          FBufferHDC, 0, 0, FBufferWidth, FBufferHeight, SRCCOPY);
  872. end;
  873. procedure TGLCanvas.StretchDrawTo(DC: HDC; X, Y, W, H: Integer);
  874. begin
  875.    if FRenderToBmp then
  876.       StretchBlt(DC, X, Y, W, H, FBufferHDC, 0, 0, FBufferWidth, FBufferHeight, SRCCOPY);
  877. end;
  878. function TGLCanvas.BeginUpdateTransformation: TGLCanvas;
  879. begin
  880.    Inc(FTransformationUpdateCount);
  881.    Result := Self;
  882. end;
  883. function TGLCanvas.EndUpdateTransformation: TGLCanvas;
  884. begin
  885.    Dec(FTransformationUpdateCount);
  886.    if FTransformationUpdateCount <= 0 then
  887.    begin
  888.       UpdateTransformation;
  889.       FTransformationUpdateCount := 0;
  890.    end;
  891.    Result := Self;
  892. end;
  893. function TGLCanvas.SetTransformation(sx, sy, tx, ty, r: Single): TGLCanvas;
  894. begin
  895.    FUseTransformStack := False;
  896.    FScaleX := sx;
  897.    FScaleY := sy;
  898.    FTranslateX := tx;
  899.    FTranslateY := ty;
  900.    FRotation := r;
  901.    if FTransformationUpdateCount = 0 then
  902.       ApplyTransformation;
  903.    Result := Self;
  904. end;
  905. function TGLCanvas.SetMatrix(const m11, m12, m13, m21, m22, m23, m31, m32, m33,
  906.    dx, dy: Single; Backup: Boolean = True): TGLCanvas;
  907. var
  908.    AMatrix: TMatrix4f;
  909. begin
  910.    Result := Self;
  911.    if not Rendering then
  912.       Exit;
  913.    AMatrix := IdentityHmgMatrix;
  914.    AMatrix[0][0] := m11;
  915.    AMatrix[0][1] := m12;
  916.    AMatrix[0][2] := m13;
  917.    AMatrix[1][0] := m21;
  918.    AMatrix[1][1] := m22;
  919.    AMatrix[1][2] := m23;
  920.    AMatrix[2][0] := m31;
  921.    AMatrix[2][1] := m32;
  922.    AMatrix[2][2] := m33;
  923.    AMatrix[3][0] := dx;
  924.    AMatrix[3][1] := dy;
  925.    glLoadMatrixf(@AMatrix);
  926.    if Backup then
  927.       FMatrix := AMatrix;
  928.    // Assume that X axis and Y axis are equally scaled.
  929.    if FIgnorePenWidthFactor then
  930.       FPenWidthFactor := 1
  931.    else
  932.       FPenWidthFactor := Sqrt((m11 * m11 + m22 * m22) / 2);
  933. end;
  934. function TGLCanvas.ResetBackupMatrix: TGLCanvas;
  935. begin
  936.    Result := Self;
  937.    if not Rendering then
  938.       Exit;
  939.    glLoadMatrixf(@FMatrix);
  940.    // Assume that X axis and Y axis are equally scaled.
  941.    if FIgnorePenWidthFactor then
  942.       FPenWidthFactor := 1
  943.    else
  944.       FPenWidthFactor := Sqrt((Sqr(FMatrix[0][0]) + Sqr(FMatrix[1][1])) / 2);
  945. end;
  946. function TGLCanvas.ResetTransformation: TGLCanvas;
  947. begin
  948.    FStackTop := -1;
  949.    FScaleX := 1.0;
  950.    FScaleY := 1.0;
  951.    FTranslateX := 0.0;
  952.    FTranslateY := 0.0;
  953.    FRotation := 0.0;
  954.    if FTransformationUpdateCount = 0 then
  955.       ApplyTransformation;
  956.    Result := Self;
  957. end;
  958. function TGLCanvas.PopMatrix: TGLCanvas;
  959. begin
  960.    if FStackTop >= 0 then
  961.       Dec(FStackTop);
  962.    if FTransformationUpdateCount = 0 then
  963.       ApplyTransformation;
  964.    Result := Self;
  965. end;
  966. function TGLCanvas.SetEqualScale(value: Single): TGLCanvas;
  967. begin
  968.    if not FUseTransformStack then
  969.    begin
  970.       FScaleX := value;
  971.       FScaleY := value;
  972.    end;
  973.    if FTransformationUpdateCount = 0 then
  974.       ApplyTransformation;
  975.    Result := Self;
  976. end;
  977. function TGLCanvas.ScaleMatrix(x, y: Single): TGLCanvas;
  978. begin
  979.    if FStackTop < TransformStackTop then
  980.    begin
  981.       Inc(FStackTop);
  982.       with FTransformStack[FStackTop] do
  983.       begin
  984.          TransformType := ttScale;
  985.          var1 := x;
  986.          var2 := y;
  987.       end;
  988.    end;
  989.    if FTransformationUpdateCount = 0 then
  990.       ApplyTransformation;
  991.    Result := Self;
  992. end;
  993. function TGLCanvas.TranslateMatrix(x, y: Single): TGLCanvas;
  994. begin
  995.    if FStackTop < TransformStackTop then
  996.    begin
  997.       Inc(FStackTop);
  998.       with FTransformStack[FStackTop] do
  999.       begin
  1000.          TransformType := ttTranslate;
  1001.          var1 := x;
  1002.          var2 := y;
  1003.       end;
  1004.    end;
  1005.    if FTransformationUpdateCount = 0 then
  1006.       ApplyTransformation;
  1007.    Result := Self;
  1008. end;
  1009. function TGLCanvas.RotateMatrix(angle: Single): TGLCanvas;
  1010. begin
  1011.    if FStackTop < TransformStackTop then
  1012.    begin
  1013.       Inc(FStackTop);
  1014.       with FTransformStack[FStackTop] do
  1015.       begin
  1016.          TransformType := ttRotate;
  1017.          var1 := angle;
  1018.       end;
  1019.    end;
  1020.    if FTransformationUpdateCount = 0 then
  1021.       ApplyTransformation;
  1022.    Result := Self;
  1023. end;
  1024. function TGLCanvas.SetScaleX(value: Single): TGLCanvas;
  1025. begin
  1026.    ScaleX := value;
  1027.    Result := Self;
  1028. end;
  1029. function TGLCanvas.SetScaleY(value: Single): TGLCanvas;
  1030. begin
  1031.    ScaleY := value;
  1032.    Result := Self;
  1033. end;
  1034. function TGLCanvas.SetTranslateX(value: Single): TGLCanvas;
  1035. begin
  1036.    TranslateX := value;
  1037.    Result := Self;
  1038. end;
  1039. function TGLCanvas.SetTranslateY(value: Single): TGLCanvas;
  1040. begin
  1041.    TranslateY := value;
  1042.    Result := Self;
  1043. end;
  1044. function TGLCanvas.SetRotation(value: Single): TGLCanvas;
  1045. begin
  1046.    Rotation := value;
  1047.    Result := Self;
  1048. end;
  1049. function TGLCanvas.ConvertScreenToWorld(x, y: Integer): TGLPointF;
  1050. var
  1051.    Viewport: array[0..3] of GLuint;
  1052.    ModelMatrix: array[0..15] of GLdouble;
  1053.    ProjMatrix: array[0..15] of GLdouble;
  1054.    ox, oy, oz: GLdouble;
  1055. begin
  1056.    glGetIntegerv(GL_VIEWPORT, @Viewport[0]);
  1057.    glGetDoublev(GL_MODELVIEW_MATRIX, @ModelMatrix[0]);
  1058.    glGetDoublev(GL_PROJECTION_MATRIX, @ProjMatrix[0]);
  1059.    gluUnProject(x, Viewport[3] - y, 0, @ModelMatrix[0],
  1060.       @ProjMatrix[0], @Viewport[0], ox, oy, oz);
  1061.    Result.X := ox;
  1062.    Result.Y := oy;
  1063. end;
  1064. function TGLCanvas.UpdateTransformation: TGLCanvas;
  1065. begin
  1066.    ApplyTransformation;
  1067.    PenWidth := FPenWidth;
  1068.    Result := Self;
  1069. end;
  1070. function TGLCanvas.SetBlendState(value: Boolean): TGLCanvas;
  1071. begin
  1072.    if value then
  1073.       glEnable(GL_BLEND)
  1074.    else
  1075.       glDisable(GL_BLEND);
  1076.    FBlend := value;
  1077.    Result := Self;
  1078. end;
  1079. function TGLCanvas.SetPenColorWin(value: TColor; alpha: Byte = 255; Sync: Boolean = True): TGLCanvas;
  1080. begin
  1081.    if Sync then
  1082.       FPenColorARGB := TColorToARGB(value);
  1083.    FPenColor := TColorToGLColor(value, alpha);
  1084.    glColor4fv(@FPenColor);
  1085.    Result := Self;
  1086. end;
  1087. function TGLCanvas.SetBrushColorWin(value: TColor; alpha: Byte = 255; Sync: Boolean = True): TGLCanvas;
  1088. begin
  1089.    if Sync then
  1090.       FBrushColorARGB := TColorToARGB(value);
  1091.    FBrushColor := TColorToGLColor(value, alpha);
  1092.    Result := Self;
  1093. end;
  1094. function TGLCanvas.SetPenColor(value: ARGB): TGLCanvas;
  1095. begin
  1096.    FSetPenColor(value);
  1097.    Result := Self;
  1098. end;
  1099. function TGLCanvas.SetBrushColor(value: ARGB): TGLCanvas;
  1100. begin
  1101.    FSetBrushColor(value);
  1102.    Result := Self;
  1103. end;
  1104. function TGLCanvas.SetPenColor(const value: TColorVector; Sync: Boolean = False): TGLCanvas;
  1105. begin
  1106.    glColor4fv(@value);
  1107.    FPenColor := value;
  1108.    if Sync then
  1109.       FPenColorARGB := GLColorToARGB(value);
  1110.    Result := Self;
  1111. end;
  1112. function TGLCanvas.SetBrushColor(const value: TColorVector; Sync: Boolean = False): TGLCanvas;
  1113. begin
  1114.    FBrushColor := value;
  1115.    if Sync then
  1116.       FBrushColorARGB := GLColorToARGB(value);
  1117.    Result := Self;
  1118. end;
  1119. function TGLCanvas.SetPenWidth(value: Single): TGLCanvas; // for linked process
  1120. begin
  1121.    FSetPenWidth(value);
  1122.    Result := Self;
  1123. end;
  1124. function TGLCanvas.LineStipple(factor: Integer; pattern: word): TGLCanvas;
  1125. begin
  1126.    glEnable(GL_LINE_STIPPLE);
  1127.    glLineStipple(factor, pattern);
  1128.    Result := Self;
  1129. end;
  1130. function TGLCanvas.LineStipple(style: TLineStippleStyle; enlarge: Byte = 2): TGLCanvas;
  1131. begin
  1132.    case style of
  1133.       lssSolid: LineStippleEnd;
  1134.       lssDash: LineStipple(3 * enlarge, $AAAA);
  1135.       lssDashDot: LineStipple(1 * enlarge, $6F6F);
  1136.       lssDashDotDot: LineStipple(2 * enlarge, $EAEA);
  1137.       lssDot: LineStipple(1 * enlarge, $AAAA);
  1138.    end;
  1139.    Result := Self;
  1140. end;
  1141. function TGLCanvas.LineStippleEnd: TGLCanvas;
  1142. begin
  1143.    glDisable(GL_LINE_STIPPLE);
  1144.    Result := Self;
  1145. end;
  1146. function TGLCanvas.Line(const x1, y1, x2, y2: Integer): TGLCanvas;
  1147. begin
  1148.    glBegin(GL_LINES);
  1149.    glVertex2i(x1, y1);
  1150.    glVertex2i(x2, y2);
  1151.    glEnd;
  1152.    Result := Self;
  1153. end;
  1154. function TGLCanvas.Line(const x1, y1, x2, y2: Single): TGLCanvas;
  1155. begin
  1156.    glBegin(GL_LINES);
  1157.    glVertex2f(x1, y1);
  1158.    glVertex2f(x2, y2);
  1159.    glEnd;
  1160.    Result := Self;
  1161. end;
  1162. function TGLCanvas.BeginLines: TGLCanvas;
  1163. begin
  1164.    glBegin(GL_LINES);
  1165.    Result := Self;
  1166. end;
  1167. function TGLCanvas.Lines(const x1, y1, x2, y2: Integer): TGLCanvas;
  1168. begin
  1169.    glVertex2i(x1, y1);
  1170.    glVertex2i(x2, y2);
  1171.    Result := Self;
  1172. end;
  1173. function TGLCanvas.Lines(const x1, y1, x2, y2: Single): TGLCanvas;
  1174. begin
  1175.    glVertex2f(x1, y1);
  1176.    glVertex2f(x2, y2);
  1177.    Result := Self;
  1178. end;
  1179. function TGLCanvas.EndLines: TGLCanvas;
  1180. begin
  1181.    glEnd;
  1182.    Result := Self;
  1183. end;
  1184. function TGLCanvas.Lines(const points: TGLPointsF; count: Integer): TGLCanvas;
  1185. var
  1186.    i: Integer;
  1187. begin
  1188.    glBegin(GL_LINES);
  1189.    i := 0;
  1190.    while (i <= count - 2) do
  1191.    begin
  1192.       glVertex2f(points[i].X, points[i].Y);
  1193.       glVertex2f(points[i + 1].X, points[i + 1].Y);
  1194.       Inc(i, 2);
  1195.    end;
  1196.    glEnd;
  1197.    Result := Self;
  1198. end;
  1199. function TGLCanvas.Lines(const points: TGLPointsI; count: Integer): TGLCanvas;
  1200. var
  1201.    i: Integer;
  1202. begin
  1203.    glBegin(GL_LINES);
  1204.    i := 0;
  1205.    while (i <= count - 2) do
  1206.    begin
  1207.       glVertex2i(points[i].X, points[i].Y);
  1208.       glVertex2i(points[i + 1].X, points[i + 1].Y);
  1209.       Inc(i, 2);
  1210.    end;
  1211.    glEnd;
  1212.    Result := Self;
  1213. end;
  1214. function TGLCanvas.Polyline(const points: TGLPointsF; count: Integer): TGLCanvas;
  1215. var
  1216.    i: Integer;
  1217. begin
  1218.    if count > 1 then
  1219.    begin
  1220.       glBegin(GL_LINE_STRIP);
  1221.       for i := 0 to count - 1 do
  1222.          glVertex2f(points[i].X, points[i].Y);
  1223.       glEnd;
  1224.    end;
  1225.    Result := Self;
  1226. end;
  1227. function TGLCanvas.Polygon(const points: TGLPointsF; count: Integer): TGLCanvas;
  1228. var
  1229.    i: Integer;
  1230. begin
  1231.    if count > 1 then
  1232.    begin
  1233.       glBegin(GL_LINE_LOOP);
  1234.       for i := 0 to count - 1 do
  1235.          glVertex2f(points[i].X, points[i].Y);
  1236.       glEnd;
  1237.    end;
  1238.    Result := Self;
  1239. end;
  1240. function TGLCanvas.Polyline(const points: TGLPointsI; count: Integer): TGLCanvas;
  1241. var
  1242.    i: Integer;
  1243. begin
  1244.    if count > 1 then
  1245.    begin
  1246.       glBegin(GL_LINE_STRIP);
  1247.       for i := 0 to count - 1 do
  1248.          glVertex2i(points[i].X, points[i].Y);
  1249.       glEnd;
  1250.    end;
  1251.    Result := Self;
  1252. end;
  1253. function TGLCanvas.Polygon(const points: TGLPointsI; count: Integer): TGLCanvas;
  1254. var
  1255.    i: Integer;
  1256. begin
  1257.    if count > 1 then
  1258.    begin
  1259.       glBegin(GL_LINE_LOOP);
  1260.       for i := 0 to count - 1 do
  1261.          glVertex2i(points[i].X, points[i].Y);
  1262.       glEnd;
  1263.    end;
  1264.    Result := Self;
  1265. end;
  1266. function TGLCanvas.FillPolygon(const points: TGLPointsF; count: Integer;
  1267.    Border: Boolean = False): TGLCanvas;
  1268. var
  1269.    i: Integer;
  1270. begin
  1271.    if count > 1 then
  1272.    begin
  1273.       if not FIgnoreColor then
  1274.          glColor4fv(@FBrushColor);
  1275.       glBegin(GL_POLYGON);
  1276.       for i := 0 to count - 1 do
  1277.          glVertex2f(points[i].X, points[i].Y);
  1278.       glEnd;
  1279.       if not FIgnoreColor then 
  1280.          glColor4fv(@FPenColor);
  1281.       if Border then
  1282.          Polygon(points, count);
  1283.    end;
  1284.    Result := Self;
  1285. end;
  1286. function TGLCanvas.FillPolygon(const points: TGLPointsI; count: Integer;
  1287.    Border: Boolean = False): TGLCanvas;
  1288. var
  1289.    i: Integer;
  1290. begin
  1291.    if count > 1 then
  1292.    begin
  1293.       if not FIgnoreColor then 
  1294.          glColor4fv(@FBrushColor);
  1295.       glBegin(GL_POLYGON);
  1296.       for i := 0 to count - 1 do
  1297.          glVertex2i(points[i].X, points[i].Y);
  1298.       glEnd;   
  1299.       if not FIgnoreColor then 
  1300.          glColor4fv(@FPenColor);
  1301.       if Border then
  1302.          Polygon(points, count);
  1303.    end;
  1304.    Result := Self;
  1305. end;
  1306. { The following methods are translated into Pascal from ReactOS source.
  1307.     calc_curve_bezier_endp
  1308.     calc_curve_bezier
  1309.     BEZIERMIDDLE
  1310.     BezierCheck
  1311.     GDI_InternalBezier
  1312.     GDI_Bezier
  1313.     GenCurvePoints  }
  1314. // Calculates Bezier points from cardinal spline endpoints.
  1315. procedure calc_curve_bezier_endp(xend, yend, xadj, yadj, tension: Single;
  1316.    var x, y: Single);
  1317. begin
  1318.    // tangent at endpoints is the line from the endpoint to the adjacent point
  1319.    x := tension * (xadj - xend) + xend;
  1320.    y := tension * (yadj - yend) + yend;
  1321. end;
  1322. // Calculates Bezier points from cardinal spline points.
  1323. procedure calc_curve_bezier(const pts: TGLPointsF; tension: Single;
  1324.    var x1, y1, x2, y2: Single);
  1325. var
  1326.    xdiff, ydiff: Single;
  1327. begin
  1328.    // calculate tangent
  1329.    xdiff := pts[2].X - pts[0].X;
  1330.    ydiff := pts[2].Y - pts[0].Y;
  1331.    // apply tangent to get control points
  1332.    x1 := pts[1].X - tension * xdiff;
  1333.    y1 := pts[1].Y - tension * ydiff;
  1334.    x2 := pts[1].X + tension * xdiff;
  1335.    y2 := pts[1].Y + tension * ydiff;
  1336. end;
  1337. procedure BEZIERMIDDLE(var Mid: TGLPointF; const P1, P2: TGLPointF);
  1338. begin
  1339.    Mid.x := (P1.x + P2.x) / 2;
  1340.    Mid.y := (P1.y + P2.y) / 2;
  1341. end;
  1342. type
  1343.    TGDIBezierPoints = array[0..3] of TGLPointF;
  1344. {
  1345. * BezierCheck helper function to check
  1346. * that recursion can be terminated
  1347. *       Points[0] and Points[3] are begin and endpoint
  1348. *       Points[1] and Points[2] are control points
  1349. *       level is the recursion depth
  1350. *       returns true if the recusion can be terminated
  1351. }
  1352. function BezierCheck(level: Integer; const Points: TGDIBezierPoints): Boolean;
  1353. const
  1354.    BEZIERPIXEL = 1;
  1355. var
  1356.    dx, dy: Single;
  1357. begin
  1358.    dx := Points[3].x - Points[0].x;
  1359.    dy := Points[3].y - Points[0].y;
  1360.    if Abs(dy) <= Abs(dx) then // shallow line
  1361.    begin
  1362.       // check that control points are between begin and end
  1363.       if Points[1].x < Points[0].x then
  1364.       begin
  1365.          if Points[1].x < Points[3].x then
  1366.          begin
  1367.             Result := False;
  1368.             Exit;
  1369.          end;
  1370.       end
  1371.       else if Points[1].x > Points[3].x then
  1372.       begin
  1373.          Result := False;
  1374.          Exit;
  1375.       end;
  1376.       if Points[2].x < Points[0].x then
  1377.       begin
  1378.          if Points[2].x < Points[3].x then
  1379.          begin
  1380.             Result := False;
  1381.             Exit;
  1382.          end;
  1383.       end
  1384.       else if Points[2].x > Points[3].x then
  1385.       begin
  1386.          Result := False;
  1387.          Exit;
  1388.       end;
  1389.       if IsZero(dx) then
  1390.       begin
  1391.          Result := True;
  1392.          Exit;
  1393.       end;
  1394.       if (Abs(Points[1].y - Points[0].y - (dy / dx) * (Points[1].x - Points[0].x)) > BEZIERPIXEL) or
  1395.          (Abs(Points[2].y - Points[0].y - (dy / dx) * (Points[2].x - Points[0].x)) > BEZIERPIXEL) then
  1396.       begin
  1397.          Result := False;
  1398.          Exit;
  1399.       end
  1400.       else
  1401.       begin
  1402.          Result := True;
  1403.          Exit;
  1404.       end;
  1405.    end
  1406.    else
  1407.    begin // steep line
  1408.       // check that control points are between begin and end
  1409.       if Points[1].y < Points[0].y then
  1410.       begin
  1411.          if Points[1].y < Points[3].y then
  1412.          begin
  1413.             Result := False;
  1414.             Exit;
  1415.          end;
  1416.       end
  1417.       else if Points[1].y > Points[3].y then
  1418.       begin
  1419.          Result := False;
  1420.          Exit;
  1421.       end;
  1422.       if Points[2].y < Points[0].y then
  1423.       begin
  1424.          if Points[2].y < Points[3].y then
  1425.          begin
  1426.             Result := False;
  1427.             Exit;
  1428.          end;
  1429.       end
  1430.       else if Points[2].y > Points[3].y then
  1431.       begin
  1432.          Result := False;
  1433.          Exit;
  1434.       end;
  1435.       if IsZero(dy) then
  1436.       begin
  1437.          Result := True;
  1438.          Exit;
  1439.       end;
  1440.       if (Abs(Points[1].x - Points[0].x - (dx / dy) * (Points[1].y - Points[0].y)) > BEZIERPIXEL) or
  1441.         (Abs(Points[2].x - Points[0].x - (dx / dy) * (Points[2].y - Points[0].y)) > BEZIERPIXEL) then
  1442.       begin
  1443.          Result := False;
  1444.          Exit;
  1445.       end
  1446.       else
  1447.       begin
  1448.          Result := True;
  1449.          Exit;
  1450.       end;
  1451.    end;
  1452. end;
  1453. procedure GDI_InternalBezier(var Points: TGDIBezierPoints; var PtsOut: TGLPointsF;
  1454.    var dwOut, nPtsOut: Integer; level: Integer);
  1455. var
  1456.    Points2: TGDIBezierPoints; // for the second recursive call
  1457. begin
  1458.   if nPtsOut = dwOut then
  1459.   begin
  1460.      dwOut := dwOut * 2;
  1461.      SetLength(PtsOut, dwOut);
  1462.   end;
  1463.   if (level = 0) or BezierCheck(level, Points) then // Recursion can be terminated
  1464.   begin
  1465.      if nPtsOut = 0 then
  1466.      begin
  1467.         PtsOut[0] := Points[0];
  1468.         nPtsOut := 1;
  1469.      end;
  1470.      PtsOut[nPtsOut] := Points[3];
  1471.      Inc(nPtsOut);
  1472.   end
  1473.   else
  1474.   begin
  1475.      Points2[3] := Points[3];
  1476.      BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
  1477.      BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
  1478.      BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
  1479.      BEZIERMIDDLE(Points[1], Points[0],  Points[1]);
  1480.      BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
  1481.      BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
  1482.      Points2[0] := Points[3];
  1483.      // do the two halves
  1484.      GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level - 1);
  1485.      GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level - 1);
  1486.   end;
  1487. end;
  1488. procedure GDI_Bezier(const Points: TGLPointsF; count: Integer;
  1489.    var PtsOut: TGLPointsF; var nPtsOut:Integer);
  1490. var
  1491.    Bezier, dwOut: Integer;
  1492.    ptBuf: TGDIBezierPoints;
  1493. begin
  1494.    dwOut := 150;
  1495.    nPtsOut := 0;
  1496.    if (count - 1) mod 3 <> 0 then
  1497.       Exit;
  1498.    SetLength(PtsOut, dwOut);
  1499.    for Bezier := 0 to (count - 1) div 3 - 1 do
  1500.    begin
  1501.       Move(Points[Bezier * 3], ptBuf[0], SizeOf(ptBuf));
  1502.       GDI_InternalBezier(ptBuf, PtsOut, dwOut, nPtsOut, 8);
  1503.    end;
  1504. end;
  1505. procedure GenCurvePoints(const points: TGLPointsF; count: Integer;
  1506.    var outPoints: TGLPointsF; var outCount: Integer; tension: Single = 0.5);
  1507. var
  1508.    i, len_pt: Integer;
  1509.    x1, x2, y1, y2: Single;
  1510.    pt: TGLPointsF;
  1511. begin
  1512.    outCount := 0;
  1513.    if count <= 1 then
  1514.       Exit;
  1515.    // PolyBezier expects count*3-2 points.
  1516.    len_pt := count * 3 - 2;
  1517.    SetLength(pt, len_pt);
  1518.    tension := tension * 0.3;
  1519.    calc_curve_bezier_endp(points[0].X, points[0].Y, points[1].X, points[1].Y,
  1520.       tension, x1, y1);
  1521.    pt[0] := points[0];
  1522.    pt[1].X := x1;
  1523.    pt[1].Y := y1;
  1524.    for i := 0 to count - 3 do
  1525.    begin
  1526.       calc_curve_bezier(TGLPointsF(@(points[i])), tension, x1, y1, x2, y2);
  1527.       pt[3 * i + 2].X := x1;
  1528.       pt[3 * i + 2].Y := y1;
  1529.       pt[3 * i + 3] := points[i + 1];
  1530.       pt[3 * i + 4].X := x2;
  1531.       pt[3 * i + 4].Y := y2;
  1532.    end;
  1533.    calc_curve_bezier_endp(points[count - 1].X, points[count - 1].Y,
  1534.        points[count - 2].X, points[count - 2].Y, tension, x1, y1);
  1535.    pt[len_pt - 2].X := x1;
  1536.    pt[len_pt - 2].Y := y1;
  1537.    pt[len_pt - 1] := points[count - 1];
  1538.    GDI_Bezier(pt, len_pt, outPoints, outCount);
  1539. end;
  1540. function TGLCanvas.Curve(const points: TGLPointsF; count: Integer;
  1541.    tension: Single = 0.5): TGLCanvas;
  1542. var
  1543.    pt2: TGLPointsF;
  1544.    pt2Count: Integer;
  1545. begin
  1546.    Result := Self;
  1547.    if count <= 1 then
  1548.       Exit;
  1549.    GenCurvePoints(points, count, pt2, pt2Count, tension);
  1550.    Polyline(pt2, pt2Count);
  1551. end;
  1552. function TGLCanvas.Curve(const points: TGLPointsI; count: Integer;
  1553.    tension: Single = 0.5): TGLCanvas;
  1554. var
  1555.    i: Integer;
  1556.    pfs: TGLPointsF;
  1557. begin
  1558.    Result := Self;
  1559.    if count <= 1 then
  1560.       Exit;
  1561.    SetLength(pfs, count);
  1562.    for i := 0 to count - 1 do
  1563.    begin
  1564.       pfs[i].X := points[i].X;
  1565.       pfs[i].Y := points[i].Y;
  1566.    end;
  1567.    Curve(pfs, count, tension);
  1568. end;
  1569. function TGLCanvas.ClosedCurve(const points: TGLPointsF; count: Integer;
  1570.    tension: Single = 0.5): TGLCanvas;
  1571. var
  1572.    ps: TGLPointsF;
  1573. begin
  1574.    Result := Self;
  1575.    if count <= 2 then
  1576.       Exit;
  1577.    SetLength(ps, count + 1);
  1578.    Move(points[0], ps[0], SizeOf(TGLPointF) * count);
  1579.    ps[count] := ps[0]; // Close the curve
  1580.    Curve(ps, count + 1, tension);
  1581. end;
  1582. function TGLCanvas.ClosedCurve(const points: TGLPointsI; count: Integer;
  1583.    tension: Single = 0.5): TGLCanvas;
  1584. var
  1585.    i: Integer;
  1586.    ps: TGLPointsF;
  1587. begin
  1588.    Result := Self;
  1589.    if count <= 2 then
  1590.       Exit;
  1591.    SetLength(ps, count + 1);
  1592.    for i := 0 to count - 1 do
  1593.    begin
  1594.       ps[i].X := points[i].X;
  1595.       ps[i].Y := points[i].Y;
  1596.    end;
  1597.    ps[count] := ps[0]; // Close the curve
  1598.    Curve(ps, count + 1, tension);
  1599. end;
  1600. function TGLCanvas.FillClosedCurve(const points: TGLPointsF; count: Integer;
  1601.    Border: Boolean = False; tension: Single = 0.5): TGLCanvas;
  1602. var
  1603.    ps, pt2: TGLPointsF;
  1604.    pt2Count: Integer;
  1605. begin
  1606.    Result := Self;
  1607.    if count <= 2 then
  1608.       Exit;
  1609.    SetLength(ps, count + 1);
  1610.    Move(points[0], ps[0], SizeOf(TGLPointF) * count);
  1611.    ps[count] := ps[0]; // Close the curve
  1612.    GenCurvePoints(ps, count + 1, pt2, pt2Count, tension);
  1613.    FillPolygon(pt2, pt2Count, Border);
  1614. end;
  1615. function TGLCanvas.FillClosedCurve(const points: TGLPointsI; count: Integer;
  1616.    Border: Boolean = False; tension: Single = 0.5): TGLCanvas;
  1617. var
  1618.    i: Integer;
  1619.    ps, pt2: TGLPointsF;
  1620.    pt2Count: Integer;
  1621. begin
  1622.    Result := Self;
  1623.    if count <= 2 then
  1624.       Exit;
  1625.    SetLength(ps, count + 1);
  1626.    for i := 0 to count - 1 do
  1627.    begin
  1628.       ps[i].X := points[i].X;
  1629.       ps[i].Y := points[i].Y;
  1630.    end;
  1631.    ps[count] := ps[0]; // Close the curve
  1632.    GenCurvePoints(ps, count + 1, pt2, pt2Count, tension);
  1633.    FillPolygon(pt2, pt2Count, Border);
  1634. end;
  1635. function TGLCanvas.Bezier(const x1, y1, x2, y2, x3, y3, x4, y4: Integer): TGLCanvas;
  1636. var
  1637.    pt: TGDIBezierPoints;
  1638.    pt2: TGLPointsF;
  1639.    ptOut: Integer;
  1640. begin
  1641.    pt[0].X := x1;
  1642.    pt[0].Y := y1;
  1643.    pt[1].X := x2;
  1644.    pt[1].Y := y2;
  1645.    pt[2].X := x3;
  1646.    pt[2].Y := y3;
  1647.    pt[3].X := x4;
  1648.    pt[3].Y := y4;
  1649.    GDI_Bezier(TGLPointsF(@pt[0]), 4, pt2, ptOut);
  1650.    Polyline(pt2, ptOut);
  1651.    Result := Self;
  1652. end;
  1653. function TGLCanvas.Bezier(const x1, y1, x2, y2, x3, y3, x4, y4: Single): TGLCanvas;
  1654. var
  1655.    pt: TGDIBezierPoints;
  1656.    pt2: TGLPointsF;
  1657.    ptOut: Integer;
  1658. begin
  1659.    pt[0].X := x1;
  1660.    pt[0].Y := y1;
  1661.    pt[1].X := x2;
  1662.    pt[1].Y := y2;
  1663.    pt[2].X := x3;
  1664.    pt[2].Y := y3;
  1665.    pt[3].X := x4;
  1666.    pt[3].Y := y4;
  1667.    GDI_Bezier(TGLPointsF(@pt[0]), 4, pt2, ptOut);
  1668.    Polyline(pt2, ptOut);
  1669.    Result := Self;
  1670. end;
  1671. function TGLCanvas.PolyBezier(const points: TGLPointsI; count: Integer): TGLCanvas;
  1672. var
  1673.    i: Integer;
  1674.    ps, pt2: TGLPointsF;
  1675.    pt2Count: Integer;
  1676. begin
  1677.    SetLength(ps, count);
  1678.    for i := 0 to count - 1 do
  1679.    begin
  1680.       ps[i].X := points[i].X;
  1681.       ps[i].Y := points[i].Y;
  1682.    end;
  1683.    GDI_Bezier(ps, count, pt2, pt2Count);
  1684.    Polyline(pt2, pt2Count);
  1685.    Result := Self;
  1686. end;
  1687. function TGLCanvas.PolyBezier(const points: TGLPointsF; count: Integer): TGLCanvas;
  1688. var
  1689.    ps2Count: Integer;
  1690.    ps2: TGLPointsF;
  1691. begin
  1692.    GDI_Bezier(points, count, ps2, ps2Count);
  1693.    Polyline(ps2, ps2Count);
  1694.    Result := Self;
  1695. end;
  1696. const
  1697.    MAX_ARC_PTS = 13;
  1698. type
  1699.    TGdiArcPoints = array[0..MAX_ARC_PTS - 1] of TGLPointF;
  1700.    PGdiArcPointsSegment = ^TGdiArcPointsSegment;
  1701.    TGdiArcPointsSegment = array[0..3] of TGLPointF;
  1702. { We plot the curve as if it is on a circle then stretch the points.  This
  1703.   adjusts the angles so that when we stretch the points they will end in the
  1704.   right place. This is only complicated because atan and atan2 do not behave
  1705.   conveniently. }
  1706. procedure unstretch_angle(var angle: Single; rad_x, rad_y: Single);
  1707. var
  1708.    stretched: Single;
  1709.    revs_off: Integer;
  1710. begin
  1711.     angle := DegToRad(angle);
  1712.     if(Abs(Cos(angle)) < 0.00001) or (Abs(Sin(angle)) < 0.00001) then
  1713.        Exit;
  1714.     stretched := ArcTan2(Sin(angle) / Abs(rad_y), Cos(angle) / Abs(rad_x));
  1715.     revs_off := Round(angle / _2Pi) - Round(stretched / _2Pi);
  1716.     angle := stretched + revs_off * _2Pi;
  1717. end;
  1718. { Calculates the bezier points needed to fill in the arc portion starting at
  1719.   angle start and ending at end.  These two angles should be no more than 90
  1720.   degrees from each other.  x1, y1, x2, y2 describes the bounding box (upper
  1721.   left and width and height).  Angles must be in radians. write_first indicates
  1722.   that the first bezier point should be written out (usually this is false).
  1723.   pt is the array of GpPointFs that gets written to. }
  1724. procedure add_arc_part(pt: PGdiArcPointsSegment; const x1, y1, x2, y2: Single;
  1725.    startangle, endangle: Single; write_first: Boolean);
  1726. var
  1727.    i: Integer;
  1728.    center_x, center_y, rad_x, rad_y, cos_start, cos_end,
  1729.       sin_start, sin_end, a, half: Single;
  1730. begin
  1731.     rad_x := x2 / 2.0;
  1732.     rad_y := y2 / 2.0;
  1733.     center_x := x1 + rad_x;
  1734.     center_y := y1 + rad_y;
  1735.     SinCos(startangle, sin_start, cos_start);
  1736.     SinCos(endangle, sin_end, cos_end);
  1737.     half := (endangle - startangle) / 2.0;
  1738.     a := 4.0 / 3.0 * (1 - Cos(half)) / Sin(half);
  1739.     if write_first then
  1740.     begin
  1741.        pt^[0].X := cos_start;
  1742.        pt^[0].Y := sin_start;
  1743.     end;
  1744.     pt^[1].X := cos_start - a * sin_start;
  1745.     pt^[1].Y := sin_start + a * cos_start;
  1746.     pt^[3].X := cos_end;
  1747.     pt^[3].Y := sin_end;
  1748.     pt^[2].X := cos_end + a * sin_end;
  1749.     pt^[2].Y := sin_end - a * cos_end;
  1750.     // expand the points back from the unit circle to the ellipse
  1751.     if write_first then
  1752.     begin
  1753.        for i := 0 to 3 do
  1754.        begin
  1755.           pt^[i].X := pt^[i].X * rad_x + center_x;
  1756.           pt^[i].Y := pt^[i].Y * rad_y + center_y;
  1757.        end;
  1758.     end
  1759.     else
  1760.     begin
  1761.        for i := 1 to 3 do
  1762.        begin
  1763.           pt^[i].X := pt^[i].X * rad_x + center_x;
  1764.           pt^[i].Y := pt^[i].Y * rad_y + center_y;
  1765.        end;
  1766.     end;
  1767. end;
  1768. { Stores the bezier points that correspond to the arc in points. If points is
  1769.   null, just return the number of points needed to represent the arc. }
  1770. function arc2polybezier(var points: TGdiArcPoints; const x1, y1, x2, y2: Single;
  1771.    var startAngle, sweepAngle: Single): Integer;
  1772. var
  1773.    i, count: Integer;
  1774.    end_angle, start_angle, endAngle: Single;
  1775. begin
  1776.     endAngle := startAngle + sweepAngle;
  1777.     unstretch_angle(startAngle, x2 / 2.0, y2 / 2.0);
  1778.     unstretch_angle(endAngle, x2 / 2.0, y2 / 2.0);
  1779.     count := Ceil(Abs(endAngle - startAngle) / PiDiv2) * 3 + 1;
  1780.     count := Min(MAX_ARC_PTS, count); // don't make more than a full circle
  1781.     if count = 1 then
  1782.     begin
  1783.        Result := 0;
  1784.        Exit;
  1785.     end;
  1786.     // start_angle and end_angle are the iterative variables
  1787.     start_angle := startAngle;
  1788.     i := 0;
  1789.     while (i < count - 1) do
  1790.     begin
  1791.        // check if we've overshot the end angle
  1792.        if sweepAngle > 0.0 then
  1793.           end_angle := Min(start_angle + PiDiv2, endAngle)
  1794.        else
  1795.           end_angle := Max(start_angle - PiDiv2, endAngle);
  1796.        if SameValue(start_angle, end_angle) then
  1797.        begin
  1798.           count := i + 1;
  1799.           Break;
  1800.        end;
  1801.        add_arc_part(PGdiArcPointsSegment(@points[i]), x1, y1, x2, y2,
  1802.           start_angle, end_angle, i = 0);
  1803.        if sweepAngle < 0.0 then
  1804.           start_angle := start_angle - PiDiv2
  1805.        else
  1806.           start_angle := start_angle + PiDiv2;
  1807.        i := i + 3;
  1808.     end;
  1809.     Result := count;
  1810. end;
  1811. function TGLCanvas.Arc(const x, y, xRadius, yRadius: Single;
  1812.    startAngle, sweepAngle: Single): TGLCanvas;
  1813. var
  1814.    num_pts: Integer;
  1815.    points: TGdiArcPoints;
  1816. begin
  1817.    num_pts := arc2polybezier(points, x - xRadius, y - yRadius,
  1818.       xRadius * 2, yRadius * 2, startAngle, sweepAngle);
  1819.    PolyBezier(TGLPointsF(@points[0]), num_pts);
  1820.    Result := Self;
  1821. end;
  1822. function TGLCanvas.FillPie(const x, y, xRadius, yRadius: Single;
  1823.    startAngle, sweepAngle: Single; Border: Boolean = False): TGLCanvas;
  1824. var
  1825.    i, num_pts: Integer;
  1826.    points: TGdiArcPoints;
  1827.    ps2Count: Integer;
  1828.    ps2: TGLPointsF;
  1829. begin
  1830.    if not FIgnoreColor then
  1831.       glColor4fv(@FBrushColor);
  1832.    glBegin(GL_TRIANGLE_FAN);
  1833.    glVertex2f(x, y); // not really necessary, but may help with memory stride
  1834.    num_pts := arc2polybezier(points, x - xRadius, y - yRadius,
  1835.       xRadius * 2, yRadius * 2, startAngle, sweepAngle);
  1836.    GDI_Bezier(TGLPointsF(@points[0]), num_pts, ps2, ps2Count);
  1837.    for i := 0 to ps2Count - 1 do
  1838.       glVertex2f(ps2[i].X, ps2[i].Y);
  1839.    glEnd;
  1840.    if not FIgnoreColor then
  1841.       glColor4fv(@FPenColor);
  1842.    if Border then
  1843.    begin
  1844.       glBegin(GL_LINE_STRIP);
  1845.       glVertex2f(x, y);
  1846.       for i := 0 to ps2Count - 1 do
  1847.          glVertex2f(ps2[i].X, ps2[i].Y);
  1848.       glVertex2f(x, y);
  1849.       glEnd;
  1850.    end;
  1851.    Result := Self;
  1852. end;
  1853. function TGLCanvas.PlotPixel(const x, y: Integer): TGLCanvas;
  1854. begin
  1855.    glBegin(GL_POINTS);
  1856.    glVertex2i(x, y);
  1857.    glEnd;
  1858.    Result := Self;
  1859. end;
  1860. function TGLCanvas.PlotPixel(const x, y: Single): TGLCanvas;
  1861. begin
  1862.    glBegin(GL_POINTS);
  1863.    glVertex2f(x, y);
  1864.    glEnd;
  1865.    Result := Self;
  1866. end;
  1867. function TGLCanvas.BeginPixels: TGLCanvas;
  1868. begin
  1869.    glBegin(GL_POINTS);
  1870.    Result := Self;
  1871. end;
  1872. function TGLCanvas.Pixels(const x, y: Integer): TGLCanvas;
  1873. begin
  1874.    glVertex2i(x, y);
  1875.    Result := Self;
  1876. end;
  1877. function TGLCanvas.Pixels(const x, y: Single): TGLCanvas;
  1878. begin
  1879.    glVertex2f(x, y);
  1880.    Result := Self;
  1881. end;
  1882. function TGLCanvas.EndPixels: TGLCanvas;
  1883. begin
  1884.    glEnd;
  1885.    Result := Self;
  1886. end;
  1887. function TGLCanvas.FrameRect(const x1, y1, x2, y2: Integer): TGLCanvas;
  1888. begin
  1889.    glBegin(GL_LINE_LOOP);
  1890.    glVertex2i(x1, y1);
  1891.    glVertex2i(x2, y1);
  1892.    glVertex2i(x2, y2);
  1893.    glVertex2i(x1, y2);
  1894.    glEnd;
  1895.    Result := Self;
  1896. end;
  1897. function TGLCanvas.FrameRect(const x1, y1, x2, y2: Single): TGLCanvas;
  1898. begin
  1899.    glBegin(GL_LINE_LOOP);
  1900.    glVertex2f(x1, y1);
  1901.    glVertex2f(x2, y1);
  1902.    glVertex2f(x2, y2);
  1903.    glVertex2f(x1, y2);
  1904.    glEnd;
  1905.    Result := Self;
  1906. end;
  1907. function TGLCanvas.FillRect(const x1, y1, x2, y2: Integer; Border: Boolean = False): TGLCanvas;
  1908. begin
  1909.    if not FIgnoreColor then 
  1910.       glColor4fv(@FBrushColor);
  1911.    glRecti(x1, y1, x2, y2);
  1912.    if not FIgnoreColor then 
  1913.       glColor4fv(@FPenColor);
  1914.    if Border then
  1915.       FrameRect(x1, y1, x2, y2);
  1916.    Result := Self;
  1917. end;
  1918. function TGLCanvas.FillRect(const x1, y1, x2, y2: Single; Border: Boolean = False): TGLCanvas;
  1919. begin
  1920.    if not FIgnoreColor then 
  1921.       glColor4fv(@FBrushColor);
  1922.    glRectf(x1, y1, x2, y2);
  1923.    if not FIgnoreColor then 
  1924.       glColor4fv(@FPenColor);
  1925.    if Border then
  1926.       FrameRect(x1, y1, x2, y2);
  1927.    Result := Self;
  1928. end;
  1929. function TGLCanvas.Triangle(const x1, y1, x2, y2, x3, y3: Integer): TGLCanvas;
  1930. begin
  1931.    glBegin(GL_LINE_LOOP);
  1932.    glVertex2i(x1, y1);
  1933.    glVertex2i(x2, y2);
  1934.    glVertex2i(x3, y3);
  1935.    glEnd;
  1936.    Result := Self;
  1937. end;
  1938. function TGLCanvas.Triangle(const x1, y1, x2, y2, x3, y3: Single): TGLCanvas;
  1939. begin
  1940.    glBegin(GL_LINE_LOOP);
  1941.    glVertex2f(x1, y1);
  1942.    glVertex2f(x2, y2);
  1943.    glVertex2f(x3, y3);
  1944.    glEnd;
  1945.    Result := Self;
  1946. end;
  1947. function TGLCanvas.FillTriangle(const x1, y1, x2, y2, x3, y3: Integer;
  1948.    Border: Boolean = False): TGLCanvas;
  1949. begin
  1950.    if not FIgnoreColor then 
  1951.       glColor4fv(@FBrushColor);
  1952.    glBegin(GL_TRIANGLE_FAN);
  1953.    glVertex2i(x1, y1);
  1954.    glVertex2i(x2, y2);
  1955.    glVertex2i(x3, y3);
  1956.    glEnd;
  1957.    if not FIgnoreColor then 
  1958.       glColor4fv(@FPenColor);
  1959.    if Border then
  1960.       Triangle(x1, y1, x2, y2, x3, y3);
  1961.    Result := Self;
  1962. end;
  1963. function TGLCanvas.FillTriangle(const x1, y1, x2, y2, x3, y3: Single;
  1964.    Border: Boolean = False): TGLCanvas;
  1965. begin
  1966.    if not FIgnoreColor then 
  1967.       glColor4fv(@FBrushColor);
  1968.    glBegin(GL_TRIANGLE_FAN);
  1969.    glVertex2f(x1, y1);
  1970.    glVertex2f(x2, y2);
  1971.    glVertex2f(x3, y3);
  1972.    glEnd;
  1973.    if not FIgnoreColor then 
  1974.       glColor4fv(@FPenColor);
  1975.    if Border then
  1976.       Triangle(x1, y1, x2, y2, x3, y3);
  1977.    Result := Self;
  1978. end;
  1979. // Ellipse drawing methods are borrowed from GLScene.GLCanvas unit
  1980. procedure PrepareSinCosCache(var s, c: array of Single;
  1981.    startAngle, stopAngle: Single);
  1982. var
  1983.    i: Integer;
  1984.    d, alpha, beta: Single;
  1985. begin
  1986.    stopAngle := stopAngle + 1E-5;
  1987.    if High(s) > Low(s) then
  1988.       d := PiDiv180 * (stopAngle - startAngle) / (High(s) - Low(s))
  1989.    else
  1990.       d := 0;
  1991.    if High(s) - Low(s) < 1000 then
  1992.    begin
  1993.       // Fast computation (approx 5.5x)
  1994.       alpha := 2 * Sqr(Sin(d * 0.5));
  1995.       beta := Sin(d);
  1996.       SinCos(startAngle * PiDiv180, s[Low(s)], c[Low(s)]);
  1997.       for i := Low(s) to High(s) - 1 do
  1998.       begin
  1999.          // Make use of the incremental formulae:
  2000.          // cos (theta+delta) = cos(theta) - [alpha*cos(theta) + beta*sin(theta)]
  2001.          // sin (theta+delta) = sin(theta) - [alpha*sin(theta) - beta*cos(theta)]
  2002.          c[i + 1] := c[i] - alpha * c[i] - beta * s[i];
  2003.          s[i + 1] := s[i] - alpha * s[i] + beta * c[i];
  2004.       end;
  2005.    end
  2006.    else
  2007.    begin
  2008.       // Slower, but maintains precision when steps are small
  2009.       startAngle := startAngle * PiDiv180;
  2010.       for i := Low(s) to High(s) do
  2011.          SinCos((i - Low(s)) * d + startAngle, s[i], c[i]);
  2012.    end;
  2013. end;
  2014. procedure TGLCanvas.EllipseVertices(const x, y, xRadius, yRadius: Single);
  2015. var
  2016.    i, n: Integer;
  2017.    s, c: TSingleArray;
  2018. begin
  2019.    if xRadius > yRadius then
  2020.       n := Round(xRadius * 0.1) + 10
  2021.    else
  2022.       n := Round(yRadius * 0.1) + 10;
  2023.    SetLength(s, n);
  2024.    SetLength(c, n);
  2025.    Dec(n);
  2026.    PrepareSinCosCache(s, c, 0, 90);
  2027.    // first quadrant (top right)
  2028.    for i := 0 to n do
  2029.    begin
  2030.       s[i] := s[i] * yRadius;
  2031.       c[i] := c[i] * xRadius;
  2032.       glVertex2f(x + c[i], y - s[i]);
  2033.    end;
  2034.    // second quadrant (top left)
  2035.    for i := n - 1 downto 0 do
  2036.       glVertex2f(x - c[i], y - s[i]);
  2037.    // third quadrant (bottom left)
  2038.    for i := 1 to n do
  2039.       glVertex2f(x - c[i], y + s[i]);
  2040.    // fourth quadrant (bottom right)
  2041.    for i := n - 1 downto 0 do
  2042.       glVertex2f(x + c[i], y + s[i]);
  2043. end;
  2044. function TGLCanvas.EllipseRect(const x1, y1, x2, y2: Single): TGLCanvas;
  2045. begin
  2046.    Ellipse((x1 + x2) * 0.5, (y1 + y2) * 0.5, Abs(x2 - x1) * 0.5, Abs(y2 - y1) * 0.5);
  2047.    Result := Self;
  2048. end;
  2049. function TGLCanvas.Ellipse(const x, y, xRadius, yRadius: Single): TGLCanvas;
  2050. begin
  2051.    glBegin(GL_LINE_STRIP);
  2052.    EllipseVertices(x, y, xRadius, yRadius);
  2053.    glEnd;
  2054.    Result := Self;
  2055. end;
  2056. function TGLCanvas.FillEllipseRect(const x1, y1, x2, y2: Single;
  2057.    Border: Boolean = False): TGLCanvas;
  2058. begin
  2059.    FillEllipse((x1 + x2) * 0.5, (y1 + y2) * 0.5, Abs(x2 - x1) * 0.5, Abs(y2 - y1) * 0.5, Border);
  2060.    Result := Self;
  2061. end;
  2062. function TGLCanvas.FillEllipse(const x, y, xRadius, yRadius: Single;
  2063.    Border: Boolean = False): TGLCanvas;
  2064. begin
  2065.    if not FIgnoreColor then
  2066.       glColor4fv(@FBrushColor);
  2067.    glBegin(GL_TRIANGLE_FAN);
  2068.    glVertex2f(x, y); // not really necessary, but may help with memory stride
  2069.    EllipseVertices(x, y, xRadius, yRadius);
  2070.    glEnd;
  2071.    if not FIgnoreColor then 
  2072.       glColor4fv(@FPenColor);
  2073.    if Border then
  2074.       Ellipse(x, y, xRadius, yRadius);
  2075.    Result := Self;
  2076. end;
  2077. procedure TGLCanvas.RecreateDefaultFont;
  2078. begin
  2079.    if Assigned(FDefaultFont) then
  2080.       FDefaultFont.Free;
  2081.    FDefaultFont := TGLFont.Create('Tahoma', 14);
  2082.    FDefaultFont.NotifyChange := DefaultFontNotify; // Mustn't assign NotifyChange by TCnGLFont.Create
  2083. end;
  2084. function TGLCanvas.TextOutASCII(const text: string; x, y: Integer;
  2085.    Font: TGLFont = nil): TGLCanvas;
  2086. var
  2087.    i: Integer;
  2088.    GLList: GLuint;
  2089.    NeedFreeList: Boolean;
  2090. begin
  2091.    if Assigned(Font) then
  2092.    begin
  2093.       SelectObject(FBufferHDC, Font.HFont);
  2094.       GLList := glGenLists(MaxChar);
  2095.       wglUseFontBitmaps(FBufferHDC, 0, MaxChar, GLList);
  2096.       NeedFreeList := True;
  2097.    end
  2098.    else
  2099.    begin
  2100.       Font := FDefaultFont;
  2101.       GLList := FASCIICharList;
  2102.       NeedFreeList := False;
  2103.    end;
  2104.    glPushMatrix;
  2105.    glLoadIdentity;
  2106.    glColor4fv(@Font.FColorVector);
  2107.    glRasterPos2i(x, y);
  2108.    for i := 1 to Length(text) do
  2109.       glCallList(GLList + Ord(text[i]));
  2110.    glPopMatrix;
  2111.    if NeedFreeList then
  2112.       glDeleteLists(GLList, MaxChar);
  2113.    glColor4fv(@FPenColor);
  2114.    Result := Self;
  2115. end;
  2116. function TGLCanvas.TextOut(const text: WideString; x, y: Integer;
  2117.    Font: TGLFont = nil): TGLCanvas;
  2118. var
  2119.    i: Integer;
  2120.    list: GLuint;
  2121. begin
  2122.    if not Assigned(Font) then
  2123.       Font := FDefaultFont;
  2124.    SelectObject(FBufferHDC, Font.HFont);
  2125.    glColor4fv(@Font.FColorVector);
  2126.    glPushMatrix;
  2127.    glLoadIdentity;
  2128.    glRasterPos2i(x, y);
  2129.    for i := 1 to Length(text) do
  2130.    begin
  2131.       wglUseFontBitmapsW(FBufferHDC, Ord(text[i]), 1, list);
  2132.       glCallList(list);
  2133.    end;
  2134.    glDeleteLists(list, 1);
  2135.    glColor4fv(@FPenColor);
  2136.    glPopMatrix;
  2137.    Result := Self;
  2138. end;
  2139. function TGLCanvas.BuildTexture(bmp: TBitmap; var texId: GLuint): TGLCanvas; // Creates Texture From A Bitmap File
  2140. var
  2141.    bmpInfo: BITMAP;
  2142. begin
  2143.    GetObject(bmp.Handle, SizeOf(bmpInfo), @bmpInfo);
  2144.    glGenTextures(1, @texId);          // Create The Texture
  2145.    glPixelStorei(GL_PACK_ALIGNMENT, 1);
  2146.    // Typical Texture Generation Using Data From The Bitmap
  2147.    glBindTexture(GL_TEXTURE_2D, texId);        // Bind To The Texture ID
  2148.    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Linear Min Filter
  2149.    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Mag Filter
  2150.    glTexImage2D(GL_TEXTURE_2D, 0, 3, bmpInfo.bmWidth, bmpInfo.bmHeight, 0, GL_BGR, GL_UNSIGNED_BYTE, bmpInfo.bmBits);
  2151.    Result := Self;
  2152. end;
  2153. function TGLCanvas.DeleteTexture(texId: GLuint): TGLCanvas;
  2154. begin
  2155.    glDeleteTextures(1, @texId);
  2156.    Result := Self;
  2157. end;
  2158. function TGLCanvas.DrawBitmap(bmp: TBitmap; x, y: Integer;
  2159.    xZoom: Single = 1.0; yZoom: Single = 1.0): TGLCanvas;
  2160. var
  2161.    bmpInfo: BITMAP;
  2162. begin
  2163.    GetObject(bmp.Handle, SizeOf(bmpInfo), @bmpInfo);
  2164.    glPixelZoom(xZoom, yZoom);
  2165.    glPushMatrix;
  2166.    glLoadIdentity;
  2167.    glRasterPos2i(x, y);
  2168.    glDrawPixels(bmp.Width, bmp.Height, GL_BGR, GL_UNSIGNED_BYTE, bmpInfo.bmBits);
  2169.    glPopMatrix;
  2170.    Result := Self;
  2171. end;
  2172. function TGLCanvas.DrawBitmapTex(bmp: TBitmap; x, y, w, h: Integer): TGLCanvas; var    tex: GLuint;
  2173. begin
  2174.    glColor3f(1.0, 1.0, 1.0);
  2175.    glDisable(GL_BLEND);
  2176.    glEnable(GL_TEXTURE_2D);
  2177.    BuildTexture(bmp, tex);
  2178.    glBegin(GL_QUADS);
  2179.    glTexCoord2f(0.0, 0.0); glVertex3i(x, y, 0);
  2180.    glTexCoord2f(1.0, 0.0); glVertex3f(x + w, y, 0);
  2181.    glTexCoord2f(1.0, 1.0); glVertex3f(x + w, y + h, 0);
  2182.    glTexCoord2f(0.0, 1.0); glVertex3f(x, y + h, 0);
  2183.    glEnd;
  2184.    glDeleteTextures(1, @tex);
  2185.    glDisable(GL_TEXTURE_2D);
  2186.    SetBlendState(FBlend);
  2187.    glColor4fv(@FPenColor); // Restore color
  2188.    Result := Self;
  2189. end;
  2190. function TGLCanvas.DrawBitmapTex(texId: GLuint; x, y, w, h: Integer): TGLCanvas;
  2191. begin
  2192.    glColor3f(1.0, 1.0, 1.0);
  2193.    glDisable(GL_BLEND);
  2194.    glEnable(GL_TEXTURE_2D);
  2195.    glBindTexture(GL_TEXTURE_2D, texid);        // Bind To The Texture ID
  2196.    glBegin(GL_QUADS);
  2197.    glTexCoord2f(0.0, 0.0); glVertex3i(x, y, 0);
  2198.    glTexCoord2f(1.0, 0.0); glVertex3f(x + w, y, 0);
  2199.    glTexCoord2f(1.0, 1.0); glVertex3f(x + w, y + h, 0);
  2200.    glTexCoord2f(0.0, 1.0); glVertex3f(x, y + h, 0);
  2201.    glEnd;
  2202.    glDisable(GL_TEXTURE_2D);
  2203.    SetBlendState(FBlend);
  2204.    glColor4fv(@FPenColor); // Restore color
  2205.    Result := Self;
  2206. end;
  2207. end.