LZScene

Форк
0
/
GLObjects.pas 
4702 строки · 122.4 Кб
1
//
2
// This unit is part of the GLScene Engine https://github.com/glscene
3
//
4
{
5
  Implementation of basic scene objects plus some management routines.
6

7
  All objects declared in this unit are part of the basic GLScene package,
8
  these are only simple objects and should be kept simple and lightweight. 
9

10
  More complex or more specialized versions should be placed in dedicated
11
  units where they can grow and prosper untammed. "Generic" geometrical
12
  objects can be found GLGeomObjects.
13

14
   History :  
15
   12/03/13 - Yar - Added TGLSuperellipsoid (contributed by Eric Hardinge)
16
   10/03/13 - PW - Added OctahedronBuildList and TetrahedronBuildList
17
   20/11/12 - PW - CPP compatibility: replaced direct access to some properties with
18
                 getter and a setter methods
19
   23/03/11 - Yar - Bugfixed TGLPlane.Assign (thanks ltyrosine)
20
                       Replaced plane primitives to triangles, added tangent and binormal attributes
21
   29/11/10 - Yar - Bugfixed client color array enabling in TGLPoints.BuildList when it not used (thanks rbenetis)
22
   23/08/10 - Yar - Added OpenGLTokens to uses, replaced OpenGL1x functions to OpenGLAdapter
23
   29/06/10 - Yar - Added loColorLogicXor to TGLLines.Options
24
   22/04/10 - Yar - Fixes after GLState revision
25
   11/04/10 - Yar - Replaced glNewList to GLState.NewList in TGLDummyCube.DoRender
26
   05/03/10 - DanB - More state added to TGLStateCache
27
   22/02/10 - Yar - Removed NoZWrite in TGLPlane, TGLSprite
28
                 Now use Material.DepthProperties
29
   28/12/09 - DanB - Modifying TGLLineBase.LineColor now calls StructureChanged
30
   13/03/09 - DanB - ScreenRect now accepts a buffer parameter, rather than using CurrentBuffer
31
   05/10/08 - DaStr - Added lsmLoop support to TGLLines
32
                (thanks Alejandro Leon Escalera) (BugtrackerID = 2084250)
33
   22/01/08 - DaStr - Fixed rendering of TGLPoints
34
                (thanks Kapitan) (BugtrackerID = 1876920)
35
   06/06/07 - DaStr - Added GLColor to uses (BugtrackerID = 1732211)
36
   14/03/07 - DaStr - Added explicit pointer dereferencing
37
                 (thanks Burkhard Carstens) (Bugtracker ID = 1678644)
38
   15/02/07 - DaStr - Global $R- removed, added default values to
39
                 TGLSprite.NoZWrite, MirrorU, MirrorV
40
   14/01/07 - DaStr - Fixed TGLCube.BuildList. Bugtracker ID=1623743 (Thanks Pete Jones)
41
   19/10/06 - LC - Fixed IcosahedronBuildList. Bugtracker ID=1490784 (thanks EPA_Couzijn)
42
   19/10/06 - LC - Fixed TGLLineBase.Assign problem. Bugtracker ID=1549354 (thanks Zapology)
43
   08/10/05 - Mathx - Fixed TGLLines.nodes.assign problem (thanks to  Yong Yoon Kit);
44
                 Also fixed a TGLLineBase.assign problem (object being assigned to
45
                 was refering the base lists, not copying them).
46
                 Bugtracker ID=830846
47
   17/01/05 - SG - Added color support for bezier style TGLLines
48
   03/12/04 - MF - Added TGLSprite.AxisAlignedDimensionsUnscaled override
49
   06/07/04 - SG - TGLCube.RayCastIntersect fix (Eric Pascual)
50
   20/01/04 - SG - Added IcosahedronBuildList
51
   30/11/03 - MF - Added TGLSphere.GenerateSilhouette - it now takes the
52
                      stacks/slices of the sphere into account
53
   10/09/03 - EG - Introduced TGLNodedLines
54
   18/08/03 - SG - Added MirrorU and MirrorV to TGLSprite for mirroring textures
55
   21/07/03 - EG - TGLTeapot moved to new GLTeapot unit,
56
                      TGLDodecahedron moved to new GLPolyhedron unit,
57
                      TGLCylinder, TGLCone, TGLTorus, TGLDisk, TGLArrowLine,
58
                      TGLAnnulus, TGLFrustrum and TGLPolygon moved to new
59
                      GLGeomObjects unit
60
   16/07/03 - EG - Style changes and cleanups
61
   19/06/03 - MF - Added GenerateSilhouette to TGLCube and TGLPlane.
62
   13/06/03 - EG - Fixed TGLAnnulus.RayCastIntersect (Alexandre Hirzel)
63
   03/06/03 - EG - Added TGLAnnulus.RayCastIntersect (Alexandre Hirzel)
64
   01/05/03 - SG - Added NURBS Curve to TGLLines (color not supported yet)
65
   14/04/03 - SG - Added a Simple Bezier Spline to TGLLines (color not supported yet)
66
   02/04/03 - EG - TGLPlane.RayCastIntersect fix (Erick Schuitema)
67
   13/02/03 - DanB - added AxisAlignedDimensionsUnscaled functions
68
   22/01/03 - EG - TGLCube.RayCastIntersect fixes (Dan Bartlett)
69
   10/01/03 - EG - TGLCube.RayCastIntersect (Stuart Gooding)
70
   08/01/03 - RC - Added TGLPlane.XScope and YScope, to use just a part of the texture
71
   27/09/02 - EG - Added TGLPointParameters
72
   24/07/02 - EG - Added TGLCylinder.Alignment
73
   23/07/02 - EG - Added TGLPoints (experimental)
74
   20/07/02 - EG - TGLCylinder.RayCastIntersect and TGLPlane.RayCastIntersect
75
   18/07/02 - EG - Added TGLCylinder.Align methods
76
   07/07/02 - EG - Added TGLPlane.Style
77
   03/07/02 - EG - TGLPolygon now properly setups normals (filippo)
78
   17/03/02 - EG - Support for transparent lines
79
   02/02/02 - EG - Fixed TGLSprite change notification
80
   26/01/02 - EG - TGLPlane & TGLCube now osDirectDraw
81
   20/01/02 - EG - TGLSpaceText moved to GLSpaceText
82
   22/08/01 - EG - TGLTorus.RayCastIntersect fixes
83
   30/07/01 - EG - Updated AxisAlignedDimensions implems
84
   16/03/01 - EG - TGLCylinderBase, changed default Stacks from 8 to 4
85
   27/02/01 - EG - Fix in TGLCube texcoords, added TGLFrustrum (thx Robin Gerrets)
86
   22/02/01 - EG - Added AxisAlignedDimensions overrides by Uwe Raabe
87
   05/02/01 - EG - Minor changes to TGLCube.BuildList
88
   21/01/01 - EG - BaseProjectionMatrix fix for TGLHUDSprite (picking issue),
89
  TGLHUDSprite moved to GLHUDObjects
90
   14/01/01 - EG - Fixed TGLSphere texture coordinates
91
   13/01/01 - EG - TGLSprite matrix compatibility update
92
   09/01/01 - EG - TGLSpaceText now handles its TFont.OnFontChange
93
   08/01/01 - EG - Added TGLLinesNode (color support) and Node size control
94
   22/12/00 - EG - Sprites are no longer texture enabled by default,
95
                      updated TGLSprite.BuildList to work with new matrices
96
   14/11/00 - EG - Added TGLDummyCube.Destroy (thx Airatz)
97
   08/10/00 - EG - Fixed call to wglUseFontOutlines
98
   06/08/00 - EG - TRotationSolid renamed to TGLRevolutionSolid & moved to GLExtrusion
99
   04/08/00 - EG - Fixed sphere main body texture coords + slight speedup
100
   02/08/00 - EG - Added TGLPolygonBase
101
   19/07/00 - EG - Added TGLHUDSprite
102
   18/07/00 - EG - Added TGLRevolutionSolid
103
   15/07/00 - EG - Code reduction and minor speedup for all quadric objects,
104
                      Added TGLLineBase (split of TGLLines),
105
                      TGLDummyCube now uses osDirectDraw instead of special behaviour
106
   13/07/00 - EG - Added TGLArrowLine (code by Aaron Hochwimmer)
107
   28/06/00 - EG - Support for "ObjectStyle"
108
   23/06/00 - EG - Reduced default Loop count for TGLDisk
109
   18/06/00 - EG - TGLMesh and accompanying stuff moved to GLMesh
110
   14/06/00 - EG - Added Capacity to TGLVertexList
111
   09/06/00 - EG - First row of Geometry-related upgrades
112
   08/06/00 - EG - Added ReleaseFontManager, fixed TGLSpaceText DestroyList,
113
   01/06/00 - EG - Added TGLAnnulus (code by Aaron Hochwimmer)
114
   29/05/00 - EG - TGLLines now uses TGLNode/TGLNodes
115
   28/05/00 - EG - Added persistence ability to TGLLines,
116
                      Added defaults for all TGLLines properties
117
   27/05/00 - EG - Moved in RogerCao's TGLLines object, added a TLineNode
118
                      class (currently private) and various enhancements + fixes,
119
                      DodecahedronBuildList now available as a procedure,
120
                      CubeWireframeBuildList now available as a procedure
121
   26/05/00 - RoC - Added division property to TGLLines, and Spline supported
122
   26/05/00 - EG - Moved vectorfile remnants to GLVectorFiles
123
   14/05/00 - EG - Removed Top/Bottom checks for TGLSphere,
124
  Added mmTriangleStrip support in CalcNormals
125
   08/05/00 - EG - Uncommented DisableAutoTexture in TGLSpaceText.BuildList
126
   07/05/00 - RoC - TGLLines added, to show a list of vertex
127
   26/04/00 - EG - Reactivated stuff in SetupQuadricParams (thanks Nelson Chu)
128
   18/04/00 - EG - Overriden TGLDummyCube.Render
129
   16/04/00 - EG - FontManager now published and auto-creating
130
   12/04/00 - EG - Added TGLCylinderBase.Loops (fixes a bug, thanks Uwe)
131
   24/03/00 - EG - Added Rotation to TGLSprite, fixed sprite size
132
   20/03/00 - EG - Enhanced FontManager
133
   17/03/00 - EG - Fixed SpaceText glBaseList bug,
134
  TGLSprite now uses a transposition of the globalmatrix
135
   16/03/00 - EG - Enhanced TFontManager to allow lower quality
136
   14/03/00 - EG - Added subobjects Barycenter support for TGLDummyCube
137
   09/02/00 - EG - ObjectManager stuff moved to GLSceneRegister,
138
  FreeForm and vector file stuff moved to new GLVectorFileObjects
139
   08/02/00 - EG - Added TGLDummyCube
140
   05/02/00 - EG - Javadocisation, fixes and enhancements :
141
                      TGLVertexList.AddVertex, "default"s to properties
142
   
143
}
144
unit GLObjects;
145

146
interface
147

148
{$I GLScene.inc}
149

150
uses
151
  Classes, SysUtils,
152
  GLVectorGeometry, GLVectorTypes, GLScene, OpenGLAdapter,
153
  OpenGLTokens, GLVectorLists, GLCrossPlatform, GLContext, GLSilhouette,
154
  GLColor, GLRenderContextInfo, GLBaseClasses, GLNodes, GLCoordinates;
155

156
type
157

158
  // TGLVisibilityDeterminationEvent
159
  //
160
  TGLVisibilityDeterminationEvent = function(Sender: TObject;
161
    var rci: TGLRenderContextInfo): Boolean of object;
162

163
  PVertexRec = ^TVertexRec;
164
  TVertexRec = record
165
    Position: TVector3f;
166
    Normal: TVector3f;
167
    Binormal: TVector3f;
168
    Tangent: TVector3f;
169
    TexCoord: TVector2f;
170
  end;
171

172
  // TGLDummyCube
173
  //
174
  { : A simple cube, invisible at run-time.
175
    This is a usually non-visible object -except at design-time- used for
176
    building hierarchies or groups, when some kind of joint or movement
177
    mechanism needs be described, you can use DummyCubes. 
178
    DummyCube's barycenter is its children's barycenter. 
179
    The DummyCube can optionnally amalgamate all its children into a single
180
    display list (see Amalgamate property). }
181
  TGLDummyCube = class(TGLCameraInvariantObject)
182
  private
183
     
184
    FCubeSize: TGLFloat;
185
    FEdgeColor: TGLColor;
186
    FVisibleAtRunTime, FAmalgamate: Boolean;
187
    FGroupList: TGLListHandle;
188
    FOnVisibilityDetermination: TGLVisibilityDeterminationEvent;
189

190
  protected
191
     
192
    procedure SetCubeSize(const val: TGLFloat);
193
    procedure SetEdgeColor(const val: TGLColor);
194
    procedure SetVisibleAtRunTime(const val: Boolean);
195
    procedure SetAmalgamate(const val: Boolean);
196

197
  public
198
     
199
    constructor Create(AOwner: TComponent); override;
200
    destructor Destroy; override;
201

202
    procedure Assign(Source: TPersistent); override;
203

204
    function AxisAlignedDimensionsUnscaled: TVector; override;
205
    function RayCastIntersect(const rayStart, rayVector: TVector;
206
      intersectPoint: PVector = nil; intersectNormal: PVector = nil)
207
      : Boolean; override;
208
    procedure BuildList(var rci: TGLRenderContextInfo); override;
209
    procedure DoRender(var rci: TGLRenderContextInfo;
210
      renderSelf, renderChildren: Boolean); override;
211
    procedure StructureChanged; override;
212
    function BarycenterAbsolutePosition: TVector; override;
213

214
  published
215
     
216
    property CubeSize: TGLFloat read FCubeSize write SetCubeSize;
217
    property EdgeColor: TGLColor read FEdgeColor write SetEdgeColor;
218
    { : If true the dummycube's edges will be visible at runtime.
219
      The default behaviour of the dummycube is to be visible at design-time
220
      only, and invisible at runtime. }
221
    property VisibleAtRunTime: Boolean read FVisibleAtRunTime
222
      write SetVisibleAtRunTime default False;
223
    { : Amalgamate the dummy's children in a single OpenGL entity.
224
      This activates a special rendering mode, which will compile
225
      the rendering of all of the dummycube's children objects into a
226
      single display list. This may provide a significant speed up in some
227
      situations, however, this means that changes to the children will
228
      be ignored untill you call StructureChanged on the dummy cube. 
229
      Some objects, that have their own display list management, may not
230
      be compatible with this behaviour. This will also prevents sorting
231
      and culling to operate as usual.
232
      In short, this features is best used for static, non-transparent
233
      geometry, or when the point of view won't change over a large
234
      number of frames. }
235
    property Amalgamate: Boolean read FAmalgamate write SetAmalgamate
236
      default False;
237
    { : Camera Invariance Options.
238
      These options allow to "deactivate" sensitivity to camera, f.i. by
239
      centering the object on the camera or ignoring camera orientation. }
240
    property CamInvarianceMode default cimNone;
241
    { : Event for custom visibility determination.
242
      Event handler should return True if the dummycube and its children
243
      are to be considered visible for the current render. }
244
    property OnVisibilityDetermination: TGLVisibilityDeterminationEvent
245
      read FOnVisibilityDetermination write FOnVisibilityDetermination;
246
  end;
247

248
  // TPlaneStyle
249
  //
250
  TPlaneStyle = (psSingleQuad, psTileTexture);
251
  TPlaneStyles = set of TPlaneStyle;
252

253
  // Plane
254
  //
255
  { : A simple plane object.
256
    Note that a plane is always made of a single quad (two triangles) and the
257
    tiling is only applied to texture coordinates. }
258
  TGLPlane = class(TGLSceneObject)
259
  private
260
     
261
    FXOffset, FYOffset: TGLFloat;
262
    FXScope, FYScope: TGLFloat;
263
    FWidth, FHeight: TGLFloat;
264
    FXTiles, FYTiles: Cardinal;
265
    FStyle: TPlaneStyles;
266
    FMesh: array of array of TVertexRec;
267
  protected
268
     
269
    procedure SetHeight(const aValue: Single);
270
    procedure SetWidth(const aValue: Single);
271
    procedure SetXOffset(const Value: TGLFloat);
272
    procedure SetXScope(const Value: TGLFloat);
273
    function StoreXScope: Boolean;
274
    procedure SetXTiles(const Value: Cardinal);
275
    procedure SetYOffset(const Value: TGLFloat);
276
    procedure SetYScope(const Value: TGLFloat);
277
    function StoreYScope: Boolean;
278
    procedure SetYTiles(const Value: Cardinal);
279
    procedure SetStyle(const val: TPlaneStyles);
280

281
  public
282
     
283
    constructor Create(AOwner: TComponent); override;
284

285
    procedure Assign(Source: TPersistent); override;
286

287
    procedure BuildList(var rci: TGLRenderContextInfo); override;
288
    function GenerateSilhouette(const silhouetteParameters
289
      : TGLSilhouetteParameters): TGLSilhouette; override;
290

291
    function AxisAlignedDimensionsUnscaled: TVector; override;
292
    function RayCastIntersect(const rayStart, rayVector: TVector;
293
      intersectPoint: PVector = nil; intersectNormal: PVector = nil)
294
      : Boolean; override;
295
    { : Computes the screen coordinates of the smallest rectangle encompassing the plane.
296
      Returned extents are NOT limited to any physical screen extents. }
297
    function ScreenRect(aBuffer: TGLSceneBuffer): TGLRect;
298

299
    { : Computes the signed distance to the point.
300
      Point coordinates are expected in absolute coordinates. }
301
    function PointDistance(const aPoint: TVector): Single;
302

303
  published
304
     
305
    property Height: TGLFloat read FHeight write SetHeight;
306
    property Width: TGLFloat read FWidth write SetWidth;
307
    property XOffset: TGLFloat read FXOffset write SetXOffset;
308
    property XScope: TGLFloat read FXScope write SetXScope stored StoreXScope;
309
    property XTiles: Cardinal read FXTiles write SetXTiles default 1;
310
    property YOffset: TGLFloat read FYOffset write SetYOffset;
311
    property YScope: TGLFloat read FYScope write SetYScope stored StoreYScope;
312
    property YTiles: Cardinal read FYTiles write SetYTiles default 1;
313
    property Style: TPlaneStyles read FStyle write SetStyle
314
      default [psSingleQuad, psTileTexture];
315
  end;
316

317
  // TGLSprite
318
  //
319
  { : A rectangular area, perspective projected, but always facing the camera.
320
    A TGLSprite is perspective projected and as such is scaled with distance,
321
    if you want a 2D sprite that does not get scaled, see TGLHUDSprite. }
322
  TGLSprite = class(TGLSceneObject)
323
  private
324
     
325
    FWidth: TGLFloat;
326
    FHeight: TGLFloat;
327
    FRotation: TGLFloat;
328
    FAlphaChannel: Single;
329
    FMirrorU, FMirrorV: Boolean;
330

331
  protected
332
     
333
    procedure SetWidth(const val: TGLFloat);
334
    procedure SetHeight(const val: TGLFloat);
335
    procedure SetRotation(const val: TGLFloat);
336
    procedure SetAlphaChannel(const val: Single);
337
    function StoreAlphaChannel: Boolean;
338
    procedure SetMirrorU(const val: Boolean);
339
    procedure SetMirrorV(const val: Boolean);
340

341
  public
342
     
343
    constructor Create(AOwner: TComponent); override;
344

345
    procedure Assign(Source: TPersistent); override;
346
    procedure BuildList(var rci: TGLRenderContextInfo); override;
347

348
    function AxisAlignedDimensionsUnscaled: TVector; override;
349

350
    procedure SetSize(const Width, Height: TGLFloat);
351
    // : Set width and height to "size"
352
    procedure SetSquareSize(const Size: TGLFloat);
353

354
  published
355
     
356
    { : Sprite Width in 3D world units. }
357
    property Width: TGLFloat read FWidth write SetWidth;
358
    { : Sprite Height in 3D world units. }
359
    property Height: TGLFloat read FHeight write SetHeight;
360
    { : This the ON-SCREEN rotation of the sprite.
361
      Rotatation=0 is handled faster. }
362
    property Rotation: TGLFloat read FRotation write SetRotation;
363
    { : If different from 1, this value will replace that of Diffuse.Alpha }
364
    property AlphaChannel: Single read FAlphaChannel write SetAlphaChannel
365
      stored StoreAlphaChannel;
366
    { : Reverses the texture coordinates in the U and V direction to mirror
367
      the texture. }
368
    property MirrorU: Boolean read FMirrorU write SetMirrorU default False;
369
    property MirrorV: Boolean read FMirrorV write SetMirrorV default False;
370
  end;
371

372
  // TGLPointStyle
373
  //
374
  TGLPointStyle = (psSquare, psRound, psSmooth, psSmoothAdditive,
375
    psSquareAdditive);
376

377
  // TGLPointParameters
378
  //
379
  { : Point parameters as in ARB_point_parameters.
380
    Make sure to read the ARB_point_parameters spec if you want to understand
381
    what each parameter does. }
382
  TGLPointParameters = class(TGLUpdateAbleObject)
383
  private
384
     
385
    FEnabled: Boolean;
386
    FMinSize, FMaxSize: Single;
387
    FFadeTresholdSize: Single;
388
    FDistanceAttenuation: TGLCoordinates;
389

390
  protected
391
     
392
    procedure SetEnabled(const val: Boolean);
393
    procedure SetMinSize(const val: Single);
394
    procedure SetMaxSize(const val: Single);
395
    procedure SetFadeTresholdSize(const val: Single);
396
    procedure SetDistanceAttenuation(const val: TGLCoordinates);
397

398
    procedure DefineProperties(Filer: TFiler); override;
399
    procedure ReadData(Stream: TStream);
400
    procedure WriteData(Stream: TStream);
401

402
  public
403
     
404
    constructor Create(AOwner: TPersistent); override;
405
    destructor Destroy; override;
406

407
    procedure Assign(Source: TPersistent); override;
408

409
    procedure Apply;
410
    procedure UnApply;
411

412
  published
413
     
414
    property Enabled: Boolean read FEnabled write SetEnabled default False;
415
    property MinSize: Single read FMinSize write SetMinSize stored False;
416
    property MaxSize: Single read FMaxSize write SetMaxSize stored False;
417
    property FadeTresholdSize: Single read FFadeTresholdSize
418
      write SetFadeTresholdSize stored False;
419
    { : Components XYZ are for constant, linear and quadratic attenuation. }
420
    property DistanceAttenuation: TGLCoordinates read FDistanceAttenuation
421
      write SetDistanceAttenuation;
422
  end;
423

424
  // TGLPoints
425
  //
426
  { : Renders a set of non-transparent colored points.
427
    The points positions and their color are defined through the Positions
428
    and Colors properties. }
429
  TGLPoints = class(TGLImmaterialSceneObject)
430
  private
431
     
432
    FPositions: TAffineVectorList;
433
    FColors: TVectorList;
434
    FSize: Single;
435
    FStyle: TGLPointStyle;
436
    FPointParameters: TGLPointParameters;
437
    FStatic, FNoZWrite: Boolean;
438

439
  protected
440
     
441
    function StoreSize: Boolean;
442
    procedure SetNoZWrite(const val: Boolean);
443
    procedure SetStatic(const val: Boolean);
444
    procedure SetSize(const val: Single);
445
    procedure SetPositions(const val: TAffineVectorList);
446
    procedure SetColors(const val: TVectorList);
447
    procedure SetStyle(const val: TGLPointStyle);
448
    procedure SetPointParameters(const val: TGLPointParameters);
449

450
  public
451
     
452
    constructor Create(AOwner: TComponent); override;
453
    destructor Destroy; override;
454

455
    procedure Assign(Source: TPersistent); override;
456
    procedure BuildList(var rci: TGLRenderContextInfo); override;
457

458
    { : Points positions.
459
      If empty, a single point is assumed at (0, 0, 0) }
460
    property Positions: TAffineVectorList read FPositions write SetPositions;
461
    { : Defines the points colors.
462
       
463
       if empty, point color will be opaque white
464
       if contains a single color, all points will use that color
465
       if contains N colors, the first N points (at max) will be rendered
466
      using the corresponding colors.
467
        }
468
    property Colors: TVectorList read FColors write SetColors;
469

470
  published
471
     
472
    { : If true points do not write their Z to the depth buffer. }
473
    property NoZWrite: Boolean read FNoZWrite write SetNoZWrite;
474
    { : Tells the component if point coordinates are static.
475
      If static, changes to the positions should be notified via an
476
      explicit StructureChanged call, or may not refresh. 
477
      Static sets of points may render faster than dynamic ones. }
478
    property Static: Boolean read FStatic write SetStatic;
479
    { : Point size, all points have a fixed size. }
480
    property Size: Single read FSize write SetSize stored StoreSize;
481
    { : Points style. }
482
    property Style: TGLPointStyle read FStyle write SetStyle default psSquare;
483
    { : Point parameters as of ARB_point_parameters.
484
      Allows to vary the size and transparency of points depending
485
      on their distance to the observer. }
486
    property PointParameters: TGLPointParameters read FPointParameters
487
      write SetPointParameters;
488

489
  end;
490

491
  // TLineNodesAspect
492
  //
493
  { : Possible aspects for the nodes of a TLine. }
494
  TLineNodesAspect = (lnaInvisible, lnaAxes, lnaCube, lnaDodecahedron);
495

496
  // TGLLineSplineMode
497
  //
498
  { : Available spline modes for a TLine. }
499
  TGLLineSplineMode = (lsmLines, lsmCubicSpline, lsmBezierSpline, lsmNURBSCurve,
500
    lsmSegments, lsmLoop);
501

502
  // TGLLinesNode
503
  //
504
  { : Specialized Node for use in a TGLLines objects.
505
    Adds a Color property (TGLColor). }
506
  TGLLinesNode = class(TGLNode)
507
  private
508
     
509
    FColor: TGLColor;
510

511
  protected
512
     
513
    procedure SetColor(const val: TGLColor);
514
    procedure OnColorChange(Sender: TObject);
515
    function StoreColor: Boolean;
516

517
  public
518
     
519
    constructor Create(Collection: TCollection); override;
520
    destructor Destroy; override;
521
    procedure Assign(Source: TPersistent); override;
522

523
  published
524
     
525

526
    { : The node color.
527
      Can also defined the line color (interpolated between nodes) if
528
      loUseNodeColorForLines is set (in TGLLines). }
529
    property Color: TGLColor read FColor write SetColor stored StoreColor;
530
  end;
531

532
  // TGLLinesNodes
533
  //
534
  { : Specialized collection for Nodes in a TGLLines objects.
535
    Stores TGLLinesNode items. }
536
  TGLLinesNodes = class(TGLNodes)
537
  public
538
     
539
    constructor Create(AOwner: TComponent); overload;
540

541
    procedure NotifyChange; override;
542
  end;
543

544
  // TGLLineBase
545
  //
546
  { : Base class for line objects.
547
    Introduces line style properties (width, color...). }
548
  TGLLineBase = class(TGLImmaterialSceneObject)
549
  private
550
     
551
    FLineColor: TGLColor;
552
    FLinePattern: TGLushort;
553
    FLineWidth: Single;
554
    FAntiAliased: Boolean;
555

556
  protected
557
     
558
    procedure SetLineColor(const Value: TGLColor);
559
    procedure SetLinePattern(const Value: TGLushort);
560
    procedure SetLineWidth(const val: Single);
561
    function StoreLineWidth: Boolean;
562
    procedure SetAntiAliased(const val: Boolean);
563

564
    { : Setup OpenGL states according to line style.
565
      You must call RestoreLineStyle after drawing your lines.
566
      You may use nested calls with SetupLineStyle/RestoreLineStyle. }
567
    procedure SetupLineStyle(var rci: TGLRenderContextInfo);
568

569
  public
570
     
571
    constructor Create(AOwner: TComponent); override;
572
    destructor Destroy; override;
573
    procedure Assign(Source: TPersistent); override;
574
    procedure NotifyChange(Sender: TObject); override;
575

576
  published
577
     
578
    { : Indicates if OpenGL should smooth line edges.
579
      Smoothed lines looks better but are poorly implemented in most OpenGL
580
      drivers and take *lots* of rendering time. }
581
    property AntiAliased: Boolean read FAntiAliased write SetAntiAliased
582
      default False;
583
    { : Default color of the lines. }
584
    property LineColor: TGLColor read FLineColor write SetLineColor;
585
    { : Bitwise line pattern.
586
      For instance $FFFF (65535) is a white line (stipple disabled), $0000
587
      is a black line, $CCCC is the stipple used in axes and dummycube, etc. }
588
    property LinePattern: TGLushort read FLinePattern write SetLinePattern
589
      default $FFFF;
590
    { : Default width of the lines. }
591
    property LineWidth: Single read FLineWidth write SetLineWidth
592
      stored StoreLineWidth;
593
    property Visible;
594
  end;
595

596
  // TGLNodedLines
597
  //
598
  { : Class that defines lines via a series of nodes.
599
    Base class, does not render anything. }
600
  TGLNodedLines = class(TGLLineBase)
601
  private
602
     
603
    FNodes: TGLLinesNodes;
604
    FNodesAspect: TLineNodesAspect;
605
    FNodeColor: TGLColor;
606
    FNodeSize: Single;
607
    FOldNodeColor: TColorVector;
608

609
  protected
610
     
611
    procedure SetNodesAspect(const Value: TLineNodesAspect);
612
    procedure SetNodeColor(const Value: TGLColor);
613
    procedure OnNodeColorChanged(Sender: TObject);
614
    procedure SetNodes(const aNodes: TGLLinesNodes);
615
    procedure SetNodeSize(const val: Single);
616
    function StoreNodeSize: Boolean;
617

618
    procedure DrawNode(var rci: TGLRenderContextInfo; X, Y, Z: Single;
619
      Color: TGLColor);
620

621
  public
622
     
623
    constructor Create(AOwner: TComponent); override;
624
    destructor Destroy; override;
625
    procedure Assign(Source: TPersistent); override;
626

627
    function AxisAlignedDimensionsUnscaled: TVector; override;
628

629
    procedure AddNode(const coords: TGLCoordinates); overload;
630
    procedure AddNode(const X, Y, Z: TGLFloat); overload;
631
    procedure AddNode(const Value: TVector); overload;
632
    procedure AddNode(const Value: TAffineVector); overload;
633

634
  published
635
     
636
    { : Default color for nodes.
637
      lnaInvisible and lnaAxes ignore this setting. }
638
    property NodeColor: TGLColor read FNodeColor write SetNodeColor;
639
    { : The nodes list. }
640
    property Nodes: TGLLinesNodes read FNodes write SetNodes;
641

642
    { : Default aspect of line nodes.
643
      May help you materialize nodes, segments and control points. }
644
    property NodesAspect: TLineNodesAspect read FNodesAspect
645
      write SetNodesAspect default lnaAxes;
646
    { : Size for the various node aspects. }
647
    property NodeSize: Single read FNodeSize write SetNodeSize
648
      stored StoreNodeSize;
649
  end;
650

651
  // TLinesOptions
652
  //
653
  TLinesOption = (loUseNodeColorForLines, loColorLogicXor);
654
  TLinesOptions = set of TLinesOption;
655

656
  // TGLLines
657
  //
658
  { : Set of 3D line segments.
659
    You define a 3D Line by adding its nodes in the "Nodes" property. The line
660
    may be rendered as a set of segment or as a curve (nodes then act as spline
661
    control points).
662
    Alternatively, you can also use it to render a set of spacial nodes (points
663
    in space), just make the lines transparent and the nodes visible by picking
664
    the node aspect that suits you. }
665
  TGLLines = class(TGLNodedLines)
666
  private
667
     
668
    FDivision: Integer;
669
    FSplineMode: TGLLineSplineMode;
670
    FOptions: TLinesOptions;
671
    FNURBSOrder: Integer;
672
    FNURBSTolerance: Single;
673
    FNURBSKnots: TSingleList;
674

675
  protected
676
     
677
    procedure SetSplineMode(const val: TGLLineSplineMode);
678
    procedure SetDivision(const Value: Integer);
679
    procedure SetOptions(const val: TLinesOptions);
680
    procedure SetNURBSOrder(const val: Integer);
681
    procedure SetNURBSTolerance(const val: Single);
682

683
  public
684
     
685
    constructor Create(AOwner: TComponent); override;
686
    destructor Destroy; override;
687
    procedure Assign(Source: TPersistent); override;
688

689
    procedure BuildList(var rci: TGLRenderContextInfo); override;
690

691
    property NURBSKnots: TSingleList read FNURBSKnots;
692
    property NURBSOrder: Integer read FNURBSOrder write SetNURBSOrder;
693
    property NURBSTolerance: Single read FNURBSTolerance
694
      write SetNURBSTolerance;
695

696
  published
697
     
698
    { : Number of divisions for each segment in spline modes.
699
      Minimum 1 (disabled), ignored in lsmLines mode. }
700
    property Division: Integer read FDivision write SetDivision default 10;
701
    { : Default spline drawing mode. }
702
    property SplineMode: TGLLineSplineMode read FSplineMode write SetSplineMode
703
      default lsmLines;
704

705
    { : Rendering options for the line.
706
       
707
       loUseNodeColorForLines: if set lines will be drawn using node
708
      colors (and color interpolation between nodes), if not, LineColor
709
      will be used (single color).
710
      loColorLogicXor: enable logic operation for color of XOR type.
711
        }
712
    property Options: TLinesOptions read FOptions write SetOptions;
713
  end;
714

715
  TCubePart = (cpTop, cpBottom, cpFront, cpBack, cpLeft, cpRight);
716
  TCubeParts = set of TCubePart;
717

718
  // TGLCube
719
  //
720
  { : A simple cube object.
721
    This cube use the same material for each of its faces, ie. all faces look
722
    the same. If you want a multi-material cube, use a mesh in conjunction
723
    with a TGLFreeForm and a material library. }
724
  TGLCube = class(TGLSceneObject)
725
  private
726
     
727
    FCubeSize: TAffineVector;
728
    FParts: TCubeParts;
729
    FNormalDirection: TNormalDirection;
730
    function GetCubeWHD(const Index: Integer): TGLFloat;
731
    procedure SetCubeWHD(Index: Integer; AValue: TGLFloat);
732
    procedure SetParts(aValue: TCubeParts);
733
    procedure SetNormalDirection(aValue: TNormalDirection);
734
  protected
735
     
736
    procedure DefineProperties(Filer: TFiler); override;
737
    procedure ReadData(Stream: TStream);
738
    procedure WriteData(Stream: TStream);
739

740
  public
741
     
742
    constructor Create(AOwner: TComponent); override;
743

744
    function GenerateSilhouette(const silhouetteParameters
745
      : TGLSilhouetteParameters): TGLSilhouette; override;
746
    procedure BuildList(var rci: TGLRenderContextInfo); override;
747

748
    procedure Assign(Source: TPersistent); override;
749
    function AxisAlignedDimensionsUnscaled: TVector; override;
750
    function RayCastIntersect(const rayStart, rayVector: TVector;
751
      intersectPoint: PVector = nil; intersectNormal: PVector = nil)
752
      : Boolean; override;
753

754
  published
755
     
756
    property CubeWidth: TGLFloat index 0 read GetCubeWHD write SetCubeWHD
757
      stored False;
758
    property CubeHeight: TGLFloat index 1 read GetCubeWHD write SetCubeWHD
759
      stored False;
760
    property CubeDepth: TGLFloat index 2 read GetCubeWHD write SetCubeWHD
761
      stored False;
762
    property NormalDirection: TNormalDirection read FNormalDirection
763
      write SetNormalDirection default ndOutside;
764
    property Parts: TCubeParts read FParts write SetParts
765
      default [cpTop, cpBottom, cpFront, cpBack, cpLeft, cpRight];
766
  end;
767

768
  // TNormalSmoothing
769
  //
770
  { : Determines how and if normals are smoothed.
771
    - nsFlat : facetted look 
772
    - nsSmooth : smooth look 
773
    - nsNone : unlighted rendering, usefull for decla texturing }
774
  TNormalSmoothing = (nsFlat, nsSmooth, nsNone);
775

776
  // TGLQuadricObject
777
  //
778
  { : Base class for quadric objects.
779
    Introduces some basic Quadric interaction functions (the actual quadric
780
    math is part of the GLU library). }
781
  TGLQuadricObject = class(TGLSceneObject)
782
  private
783
     
784
    FNormals: TNormalSmoothing;
785
    FNormalDirection: TNormalDirection;
786

787
  protected
788
     
789
    procedure SetNormals(aValue: TNormalSmoothing);
790
    procedure SetNormalDirection(aValue: TNormalDirection);
791
    procedure SetupQuadricParams(quadric: PGLUquadricObj);
792
    procedure SetNormalQuadricOrientation(quadric: PGLUquadricObj);
793
    procedure SetInvertedQuadricOrientation(quadric: PGLUquadricObj);
794

795
  public
796
     
797
    constructor Create(AOwner: TComponent); override;
798
    procedure Assign(Source: TPersistent); override;
799

800
  published
801
     
802
    property Normals: TNormalSmoothing read FNormals write SetNormals
803
      default nsSmooth;
804
    property NormalDirection: TNormalDirection read FNormalDirection
805
      write SetNormalDirection default ndOutside;
806
  end;
807

808
  TAngleLimit1 = -90 .. 90;
809
  TAngleLimit2 = 0 .. 360;
810
  TCapType = (ctNone, ctCenter, ctFlat);
811

812
  // TGLSphere
813
  //
814
  { : A sphere object.
815
    The sphere can have to and bottom caps, as well as being just a slice
816
    of sphere. }
817
  TGLSphere = class(TGLQuadricObject)
818
  private
819
     
820
    FRadius: TGLFloat;
821
    FSlices, FStacks: TGLInt;
822
    FTop: TAngleLimit1;
823
    FBottom: TAngleLimit1;
824
    FStart: TAngleLimit2;
825
    FStop: TAngleLimit2;
826
    FTopCap, FBottomCap: TCapType;
827
    procedure SetBottom(aValue: TAngleLimit1);
828
    procedure SetBottomCap(aValue: TCapType);
829
    procedure SetRadius(const aValue: TGLFloat);
830
    procedure SetSlices(aValue: TGLInt);
831
    procedure SetStart(aValue: TAngleLimit2);
832
    procedure SetStop(aValue: TAngleLimit2);
833
    procedure SetStacks(aValue: TGLInt);
834
    procedure SetTop(aValue: TAngleLimit1);
835
    procedure SetTopCap(aValue: TCapType);
836

837
  public
838
     
839
    constructor Create(AOwner: TComponent); override;
840
    procedure Assign(Source: TPersistent); override;
841

842
    procedure BuildList(var rci: TGLRenderContextInfo); override;
843
    function AxisAlignedDimensionsUnscaled: TVector; override;
844
    function RayCastIntersect(const rayStart, rayVector: TVector;
845
      intersectPoint: PVector = nil; intersectNormal: PVector = nil)
846
      : Boolean; override;
847

848
    function GenerateSilhouette(const silhouetteParameters
849
      : TGLSilhouetteParameters): TGLSilhouette; override;
850
  published
851
     
852
    property Bottom: TAngleLimit1 read FBottom write SetBottom default -90;
853
    property BottomCap: TCapType read FBottomCap write SetBottomCap
854
      default ctNone;
855
    property Radius: TGLFloat read FRadius write SetRadius;
856
    property Slices: TGLInt read FSlices write SetSlices default 16;
857
    property Stacks: TGLInt read FStacks write SetStacks default 16;
858
    property Start: TAngleLimit2 read FStart write SetStart default 0;
859
    property Stop: TAngleLimit2 read FStop write SetStop default 360;
860
    property Top: TAngleLimit1 read FTop write SetTop default 90;
861
    property TopCap: TCapType read FTopCap write SetTopCap default ctNone;
862
  end;
863

864
  // TGLPolygonBase
865
  //
866
  { : Base class for objects based on a polygon. }
867
  TGLPolygonBase = class(TGLSceneObject)
868
  private
869
     
870
    FDivision: Integer;
871
    FSplineMode: TGLLineSplineMode;
872

873
  protected
874
     
875
    FNodes: TGLNodes;
876
    procedure CreateNodes; dynamic;
877
    procedure SetSplineMode(const val: TGLLineSplineMode);
878
    procedure SetDivision(const Value: Integer);
879
    procedure SetNodes(const aNodes: TGLNodes);
880

881
  public
882
     
883
    constructor Create(AOwner: TComponent); override;
884
    destructor Destroy; override;
885
    procedure Assign(Source: TPersistent); override;
886
    procedure NotifyChange(Sender: TObject); override;
887

888
    procedure AddNode(const coords: TGLCoordinates); overload;
889
    procedure AddNode(const X, Y, Z: TGLFloat); overload;
890
    procedure AddNode(const Value: TVector); overload;
891
    procedure AddNode(const Value: TAffineVector); overload;
892

893
  published
894
     
895
    { : The nodes list. }
896
    property Nodes: TGLNodes read FNodes write SetNodes;
897
    { : Number of divisions for each segment in spline modes.
898
      Minimum 1 (disabled), ignored in lsmLines mode. }
899
    property Division: Integer read FDivision write SetDivision default 10;
900
    { : Default spline drawing mode.
901
      This mode is used only for the curve, not for the rotation path. }
902
    property SplineMode: TGLLineSplineMode read FSplineMode write SetSplineMode
903
      default lsmLines;
904

905
  end;
906

907
  // TGLSuperellipsoid
908
  //
909
  { : A Superellipsoid object.
910
    The Superellipsoid can have top and bottom caps,
911
    as well as being just a slice of Superellipsoid. }
912
  TGLSuperellipsoid = class(TGLQuadricObject)
913
  private
914
     
915
    FRadius, FxyCurve, FzCurve: TGLFloat;
916
    FSlices, FStacks: TGLInt;
917
    FTop: TAngleLimit1;
918
    FBottom: TAngleLimit1;
919
    FStart: TAngleLimit2;
920
    FStop: TAngleLimit2;
921
    FTopCap, FBottomCap: TCapType;
922
    procedure SetBottom(aValue: TAngleLimit1);
923
    procedure SetBottomCap(aValue: TCapType);
924
    procedure SetRadius(const aValue: TGLFloat);
925
    procedure SetxyCurve(const aValue: TGLFloat);
926
    procedure SetzCurve(const aValue: TGLFloat);
927
    procedure SetSlices(aValue: TGLInt);
928
    procedure SetStart(aValue: TAngleLimit2);
929
    procedure SetStop(aValue: TAngleLimit2);
930
    procedure SetStacks(aValue: TGLInt);
931
    procedure SetTop(aValue: TAngleLimit1);
932
    procedure SetTopCap(aValue: TCapType);
933

934
  public
935
     
936
    constructor Create(AOwner: TComponent); override;
937
    procedure Assign(Source: TPersistent); override;
938

939
    procedure BuildList(var rci: TGLRenderContextInfo); override;
940
    function AxisAlignedDimensionsUnscaled: TVector; override;
941
    function RayCastIntersect(const rayStart, rayVector: TVector;
942
      intersectPoint: PVector = nil; intersectNormal: PVector = nil)
943
      : Boolean; override;
944

945
    function GenerateSilhouette(const silhouetteParameters
946
      : TGLSilhouetteParameters): TGLSilhouette; override;
947
  published
948
     
949
    property Bottom: TAngleLimit1 read FBottom write SetBottom default -90;
950
    property BottomCap: TCapType read FBottomCap write SetBottomCap
951
      default ctNone;
952
    property Radius: TGLFloat read FRadius write SetRadius;
953
    property xyCurve: TGLFloat read FxyCurve write SetxyCurve;
954
    property zCurve: TGLFloat read FzCurve write SetzCurve;
955
    property Slices: TGLInt read FSlices write SetSlices default 16;
956
    property Stacks: TGLInt read FStacks write SetStacks default 16;
957
    property Start: TAngleLimit2 read FStart write SetStart default 0;
958
    property Stop: TAngleLimit2 read FStop write SetStop default 360;
959
    property Top: TAngleLimit1 read FTop write SetTop default 90;
960
    property TopCap: TCapType read FTopCap write SetTopCap default ctNone;
961
  end;
962

963

964
{ : Issues OpenGL for a unit-size cube stippled wireframe. }
965
procedure CubeWireframeBuildList(var rci: TGLRenderContextInfo; Size: TGLFloat;
966
  Stipple: Boolean; const Color: TColorVector);
967
{ : Issues OpenGL for a unit-size dodecahedron. }
968
procedure DodecahedronBuildList;
969
{ : Issues OpenGL for a unit-size icosahedron. }
970
procedure IcosahedronBuildList;
971
{ : Issues OpenGL for a unit-size octahedron. }
972
procedure OctahedronBuildList;
973
{ : Issues OpenGL for a unit-size tetrahedron. }
974
procedure TetrahedronBuildList;
975

976

977

978
var
979
  TangentAttributeName: AnsiString = 'Tangent';
980
  BinormalAttributeName: AnsiString = 'Binormal';
981

982
// -------------------------------------------------------------
983
// -------------------------------------------------------------
984
// -------------------------------------------------------------
985
implementation
986

987
// -------------------------------------------------------------
988
// -------------------------------------------------------------
989
// -------------------------------------------------------------
990

991
uses
992
  GLSpline,
993
  XOpenGL,
994
  GLState;
995

996
const
997
  cDefaultPointSize: Single = 1.0;
998

999
  // CubeWireframeBuildList
1000
  //
1001

1002
procedure CubeWireframeBuildList(var rci: TGLRenderContextInfo; Size: TGLFloat;
1003
  Stipple: Boolean; const Color: TColorVector);
1004
var
1005
  mi, ma: Single;
1006
begin
1007
{$IFDEF GLS_OPENGL_DEBUG}
1008
  if GL.GREMEDY_string_marker then
1009
    GL.StringMarkerGREMEDY(22, 'CubeWireframeBuildList');
1010
{$ENDIF}
1011
  rci.GLStates.Disable(stLighting);
1012
  rci.GLStates.Enable(stLineSmooth);
1013
  if stipple then
1014
  begin
1015
    rci.GLStates.Enable(stLineStipple);
1016
    rci.GLStates.Enable(stBlend);
1017
    rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
1018
    rci.GLStates.LineStippleFactor := 1;
1019
    rci.GLStates.LineStipplePattern := $CCCC;
1020
  end;
1021
  rci.GLStates.LineWidth := 1;
1022
  ma := 0.5 * Size;
1023
  mi := -ma;
1024

1025
  GL.Color4fv(@Color);
1026
  GL.Begin_(GL_LINE_STRIP);
1027
  // front face
1028
  GL.Vertex3f(ma, mi, mi);
1029
  GL.Vertex3f(ma, ma, mi);
1030
  GL.Vertex3f(ma, ma, ma);
1031
  GL.Vertex3f(ma, mi, ma);
1032
  GL.Vertex3f(ma, mi, mi);
1033
  // partial up back face
1034
  GL.Vertex3f(mi, mi, mi);
1035
  GL.Vertex3f(mi, mi, ma);
1036
  GL.Vertex3f(mi, ma, ma);
1037
  GL.Vertex3f(mi, ma, mi);
1038
  // right side low
1039
  GL.Vertex3f(ma, ma, mi);
1040
  GL.End_;
1041
  GL.Begin_(GL_LINES);
1042
  // right high
1043
  GL.Vertex3f(ma, ma, ma);
1044
  GL.Vertex3f(mi, ma, ma);
1045
  // back low
1046
  GL.Vertex3f(mi, mi, mi);
1047
  GL.Vertex3f(mi, ma, mi);
1048
  // left high
1049
  GL.Vertex3f(ma, mi, ma);
1050
  GL.Vertex3f(mi, mi, ma);
1051
  GL.End_;
1052
end;
1053

1054
// DodecahedronBuildList
1055
//
1056
procedure DodecahedronBuildList;
1057
const
1058
  A = 1.61803398875 * 0.3; // (Sqrt(5)+1)/2
1059
  B = 0.61803398875 * 0.3; // (Sqrt(5)-1)/2
1060
  C = 1 * 0.3;
1061
const
1062
  Vertices: packed array [0 .. 19] of TAffineVector = ((X: - A; Y: 0; Z: B),
1063
    (X: - A; Y: 0; Z: - B), (X: A; Y: 0; Z: - B), (X: A; Y: 0; Z: B), (X: B;
1064
    Y: - A; Z: 0), (X: - B; Y: - A; Z: 0), (X: - B; Y: A; Z: 0), (X: B; Y: A;
1065
    Z: 0), (X: 0; Y: B; Z: - A), (X: 0; Y: - B; Z: - A), (X: 0; Y: - B; Z: A),
1066
    (X: 0; Y: B; Z: A), (X: - C; Y: - C; Z: C), (X: - C; Y: - C; Z: - C), (X: C;
1067
    Y: - C; Z: - C), (X: C; Y: - C; Z: C), (X: - C; Y: C; Z: C), (X: - C; Y: C;
1068
    Z: - C), (X: C; Y: C; Z: - C), (X: C; Y: C; Z: C));
1069

1070
  Polygons: packed array [0 .. 11] of packed array [0 .. 4]
1071
    of Byte = ((0, 12, 10, 11, 16), (1, 17, 8, 9, 13), (2, 14, 9, 8, 18),
1072
    (3, 19, 11, 10, 15), (4, 14, 2, 3, 15), (5, 12, 0, 1, 13),
1073
    (6, 17, 1, 0, 16), (7, 19, 3, 2, 18), (8, 17, 6, 7, 18), (9, 14, 4, 5, 13),
1074
    (10, 12, 5, 4, 15), (11, 19, 7, 6, 16));
1075
var
1076
  i, j: Integer;
1077
  n: TAffineVector;
1078
  faceIndices: PByteArray;
1079
begin
1080
  for i := 0 to 11 do
1081
  begin
1082
    faceIndices := @polygons[i, 0];
1083

1084
    n := CalcPlaneNormal(vertices[faceIndices^[0]], vertices[faceIndices^[1]],
1085
      vertices[faceIndices^[2]]);
1086
    GL.Normal3fv(@n);
1087

1088
//    GL.Begin_(GL_TRIANGLE_FAN);
1089
//    for j := 0 to 4 do
1090
//      GL.Vertex3fv(@vertices[faceIndices^[j]]);
1091
//    GL.End_;
1092

1093
    GL.Begin_(GL_TRIANGLES);
1094

1095
    for j := 1 to 3 do
1096
    begin
1097
      GL.Vertex3fv(@vertices[faceIndices^[0]]);
1098
      GL.Vertex3fv(@vertices[faceIndices^[j]]);
1099
      GL.Vertex3fv(@vertices[faceIndices^[j+1]]);
1100
    end;
1101
    GL.End_;
1102
  end;
1103
end;
1104

1105
// IcosahedronBuildList
1106
//
1107
procedure IcosahedronBuildList;
1108
const
1109
  A = 0.5;
1110
  B = 0.30901699437; // 1/(1+Sqrt(5))
1111
const
1112
  Vertices: packed array [0 .. 11] of TAffineVector = ((X: 0; Y: - B; Z: - A),
1113
    (X: 0; Y: - B; Z: A), (X: 0; Y: B; Z: - A), (X: 0; Y: B; Z: A), (X: - A;
1114
    Y: 0; Z: - B), (X: - A; Y: 0; Z: B), (X: A; Y: 0; Z: - B), (X: A; Y: 0;
1115
    Z: B), (X: - B; Y: - A; Z: 0), (X: - B; Y: A; Z: 0), (X: B; Y: - A; Z: 0),
1116
    (X: B; Y: A; Z: 0));
1117
  Triangles: packed array [0 .. 19] of packed array [0 .. 2]
1118
    of Byte = ((2, 9, 11), (3, 11, 9), (3, 5, 1), (3, 1, 7), (2, 6, 0),
1119
    (2, 0, 4), (1, 8, 10), (0, 10, 8), (9, 4, 5), (8, 5, 4), (11, 7, 6),
1120
    (10, 6, 7), (3, 9, 5), (3, 7, 11), (2, 4, 9), (2, 11, 6), (0, 8, 4),
1121
    (0, 6, 10), (1, 5, 8), (1, 10, 7));
1122

1123
var
1124
  i, j: Integer;
1125
  n: TAffineVector;
1126
  faceIndices: PByteArray;
1127
begin
1128
  for i := 0 to 19 do
1129
  begin
1130
    faceIndices := @triangles[i, 0];
1131

1132
    n := CalcPlaneNormal(vertices[faceIndices^[0]], vertices[faceIndices^[1]],
1133
      vertices[faceIndices^[2]]);
1134
    GL.Normal3fv(@n);
1135

1136
    GL.Begin_(GL_TRIANGLES);
1137
    for j := 0 to 2 do
1138
      GL.Vertex3fv(@vertices[faceIndices^[j]]);
1139
    GL.End_;
1140
  end;
1141
end;
1142

1143
// OctahedronBuildList
1144
//
1145
procedure OctahedronBuildList;
1146
const
1147
  Vertices: packed array [0 .. 5] of TAffineVector =
1148
      ((X: 1.0; Y: 0.0; Z: 0.0),
1149
       (X: -1.0; Y: 0.0; Z: 0.0),
1150
       (X: 0.0; Y: 1.0; Z: 0.0),
1151
       (X: 0.0; Y: -1.0; Z: 0.0),
1152
       (X: 0.0; Y: 0.0; Z: 1.0),
1153
       (X: 0.0; Y: 0.0; Z: -1.0));
1154

1155
  Triangles: packed array [0 .. 7] of packed array [0 .. 2]
1156
    of Byte = ((0, 4, 2), (1, 2, 4), (0, 3, 4), (1, 4, 3),
1157
               (0, 2, 5), (1, 5, 2), (0, 5, 3), (1, 3, 5));
1158

1159
var
1160
  i, j: Integer;
1161
  n: TAffineVector;
1162
  faceIndices: PByteArray;
1163
begin
1164
  for i := 0 to 7 do
1165
  begin
1166
    faceIndices := @triangles[i, 0];
1167

1168
    n := CalcPlaneNormal(vertices[faceIndices^[0]], vertices[faceIndices^[1]],
1169
      vertices[faceIndices^[2]]);
1170
    GL.Normal3fv(@n);
1171

1172
    GL.Begin_(GL_TRIANGLES);
1173
    for j := 0 to 2 do
1174
      GL.Vertex3fv(@vertices[faceIndices^[j]]);
1175
    GL.End_;
1176
  end;
1177
end;
1178

1179
// TetrahedronBuildList
1180
//
1181
procedure TetrahedronBuildList;
1182
const
1183
  TetT = 1.73205080756887729;
1184
const
1185
  Vertices: packed array [0 .. 3] of TAffineVector =
1186
{
1187
       ((X: TetT;  Y: TetT;  Z: TetT),
1188
        (X: TetT;  Y: -TetT; Z: -TetT),
1189
        (X: -TetT; Y: TetT;  Z: -TetT),
1190
        (X: -TetT; Y: -TetT; Z: TetT));
1191
}
1192
       ((X: 1.0;  Y: 1.0;  Z: 1.0),
1193
        (X: 1.0;  Y: -1.0; Z: -1.0),
1194
        (X: -1.0; Y: 1.0;  Z: -1.0),
1195
        (X: -1.0; Y: -1.0; Z: 1.0));
1196

1197
  Triangles: packed array [0 .. 3] of packed array [0 .. 2]
1198
    of Byte = ((0, 1, 3), (2, 1, 0), (3, 2, 0), (1, 2, 3));
1199

1200
var
1201
  i, j: Integer;
1202
  n: TAffineVector;
1203
  faceIndices: PByteArray;
1204
begin
1205
  for i := 0 to 3 do
1206
  begin
1207
    faceIndices := @triangles[i, 0];
1208

1209
    n := CalcPlaneNormal(vertices[faceIndices^[0]], vertices[faceIndices^[1]],
1210
      vertices[faceIndices^[2]]);
1211
    GL.Normal3fv(@n);
1212

1213
    GL.Begin_(GL_TRIANGLES);
1214
    for j := 0 to 2 do
1215
      GL.Vertex3fv(@vertices[faceIndices^[j]]);
1216
    GL.End_;
1217
  end;
1218
end;
1219

1220
// ------------------
1221
// ------------------ TGLDummyCube ------------------
1222
// ------------------
1223

1224
// Create
1225
//
1226

1227
constructor TGLDummyCube.Create(AOwner: TComponent);
1228
begin
1229
  inherited;
1230
  ObjectStyle := ObjectStyle + [osDirectDraw];
1231
  FCubeSize := 1;
1232
  FEdgeColor := TGLColor.Create(Self);
1233
  FEdgeColor.Initialize(clrWhite);
1234
  FGroupList := TGLListHandle.Create;
1235
  CamInvarianceMode := cimNone;
1236
end;
1237

1238
// Destroy
1239
//
1240

1241
destructor TGLDummyCube.Destroy;
1242
begin
1243
  FGroupList.Free;
1244
  FEdgeColor.Free;
1245
  inherited;
1246
end;
1247

1248
 
1249
//
1250

1251
procedure TGLDummyCube.Assign(Source: TPersistent);
1252
begin
1253
  if Source is TGLDummyCube then
1254
  begin
1255
    FCubeSize := TGLDummyCube(Source).FCubeSize;
1256
    FEdgeColor.Color := TGLDummyCube(Source).FEdgeColor.Color;
1257
    FVisibleAtRunTime := TGLDummyCube(Source).FVisibleAtRunTime;
1258
    NotifyChange(Self);
1259
  end;
1260
  inherited Assign(Source);
1261
end;
1262

1263
// AxisAlignedDimensionsUnscaled
1264
//
1265

1266
function TGLDummyCube.AxisAlignedDimensionsUnscaled: TVector;
1267
begin
1268
  Result.X := 0.5 * Abs(FCubeSize);
1269
  Result.Y := Result.X;
1270
  Result.Z := Result.X;
1271
  Result.W := 0;
1272
end;
1273

1274
// RayCastIntersect
1275
//
1276

1277
function TGLDummyCube.RayCastIntersect(const rayStart, rayVector: TVector;
1278
  intersectPoint: PVector = nil; intersectNormal: PVector = nil): Boolean;
1279
begin
1280
  Result := False;
1281
end;
1282

1283
// BuildList
1284
//
1285

1286
procedure TGLDummyCube.BuildList(var rci: TGLRenderContextInfo);
1287
begin
1288
  if (csDesigning in ComponentState) or (FVisibleAtRunTime) then
1289
    CubeWireframeBuildList(rci, FCubeSize, True, EdgeColor.Color);
1290
end;
1291

1292
// DoRender
1293
//
1294

1295
procedure TGLDummyCube.DoRender(var rci: TGLRenderContextInfo;
1296
  renderSelf, renderChildren: Boolean);
1297
begin
1298
  if Assigned(FOnVisibilityDetermination) then
1299
    if not FOnVisibilityDetermination(Self, rci) then
1300
      Exit;
1301
  if FAmalgamate and (not rci.amalgamating) then
1302
  begin
1303
    if FGroupList.Handle = 0 then
1304
    begin
1305
      FGroupList.AllocateHandle;
1306
      Assert(FGroupList.Handle <> 0, 'Handle=0 for ' + ClassName);
1307
      rci.GLStates.NewList(FGroupList.Handle, GL_COMPILE);
1308
      rci.amalgamating := True;
1309
      try
1310
        inherited;
1311
      finally
1312
        rci.amalgamating := False;
1313
        rci.GLStates.EndList;
1314
      end;
1315
    end;
1316
    rci.GLStates.CallList(FGroupList.Handle);
1317
  end
1318
  else
1319
  begin
1320
    // proceed as usual
1321
    inherited;
1322
  end;
1323
end;
1324

1325
// StructureChanged
1326
//
1327

1328
procedure TGLDummyCube.StructureChanged;
1329
begin
1330
  if FAmalgamate then
1331
    FGroupList.DestroyHandle;
1332
  inherited;
1333
end;
1334

1335
// BarycenterAbsolutePosition
1336
//
1337

1338
function TGLDummyCube.BarycenterAbsolutePosition: TVector;
1339
var
1340
  i: Integer;
1341
begin
1342
  if Count > 0 then
1343
  begin
1344
    Result := Children[0].BarycenterAbsolutePosition;
1345
    for i := 1 to Count - 1 do
1346
      Result := VectorAdd(Result, Children[i].BarycenterAbsolutePosition);
1347
    ScaleVector(Result, 1 / Count);
1348
  end
1349
  else
1350
    Result := AbsolutePosition;
1351
end;
1352

1353
// SetCubeSize
1354
//
1355

1356
procedure TGLDummyCube.SetCubeSize(const val: TGLFloat);
1357
begin
1358
  if val <> FCubeSize then
1359
  begin
1360
    FCubeSize := val;
1361
    StructureChanged;
1362
  end;
1363
end;
1364

1365
// SetEdgeColor
1366
//
1367

1368
procedure TGLDummyCube.SetEdgeColor(const val: TGLColor);
1369
begin
1370
  if val <> FEdgeColor then
1371
  begin
1372
    FEdgeColor.Assign(val);
1373
    StructureChanged;
1374
  end;
1375
end;
1376

1377
// SetVisibleAtRunTime
1378
//
1379

1380
procedure TGLDummyCube.SetVisibleAtRunTime(const val: Boolean);
1381
begin
1382
  if val <> FVisibleAtRunTime then
1383
  begin
1384
    FVisibleAtRunTime := val;
1385
    StructureChanged;
1386
  end;
1387
end;
1388

1389
// SetAmalgamate
1390
//
1391

1392
procedure TGLDummyCube.SetAmalgamate(const val: Boolean);
1393
begin
1394
  if val <> FAmalgamate then
1395
  begin
1396
    FAmalgamate := val;
1397
    if not val then
1398
      FGroupList.DestroyHandle;
1399
    inherited StructureChanged;
1400
  end;
1401
end;
1402

1403
// ------------------
1404
// ------------------ TGLPlane ------------------
1405
// ------------------
1406

1407
// Create
1408
//
1409

1410
constructor TGLPlane.Create(AOwner: TComponent);
1411
begin
1412
  inherited Create(AOwner);
1413
  FWidth := 1;
1414
  FHeight := 1;
1415
  FXTiles := 1;
1416
  FYTiles := 1;
1417
  FXScope := 1;
1418
  FYScope := 1;
1419
  ObjectStyle := ObjectStyle + [osDirectDraw];
1420
  FStyle := [psSingleQuad, psTileTexture];
1421
end;
1422

1423
 
1424
//
1425

1426
procedure TGLPlane.Assign(Source: TPersistent);
1427
begin
1428
  if Assigned(Source) and (Source is TGLPlane) then
1429
  begin
1430
    FWidth := TGLPlane(Source).FWidth;
1431
    FHeight := TGLPlane(Source).FHeight;
1432
    FXOffset := TGLPlane(Source).FXOffset;
1433
    FXScope := TGLPlane(Source).FXScope;
1434
    FXTiles := TGLPlane(Source).FXTiles;
1435
    FYOffset := TGLPlane(Source).FYOffset;
1436
    FYScope := TGLPlane(Source).FYScope;
1437
    FYTiles := TGLPlane(Source).FYTiles;
1438
    FStyle := TGLPlane(Source).FStyle;
1439
    StructureChanged;
1440
  end;
1441
  inherited Assign(Source);
1442
end;
1443

1444
// AxisAlignedDimensions
1445
//
1446

1447
function TGLPlane.AxisAlignedDimensionsUnscaled: TVector;
1448
begin
1449
  Result.V[0] := 0.5 * Abs(FWidth);
1450
  Result.V[1] := 0.5 * Abs(FHeight);
1451
  Result.V[2] := 0;
1452
end;
1453

1454
// RayCastIntersect
1455
//
1456

1457
function TGLPlane.RayCastIntersect(const rayStart, rayVector: TVector;
1458
  intersectPoint: PVector = nil; intersectNormal: PVector = nil): Boolean;
1459
var
1460
  locRayStart, locRayVector, ip: TVector;
1461
  t: Single;
1462
begin
1463
  locRayStart := AbsoluteToLocal(rayStart);
1464
  locRayVector := AbsoluteToLocal(rayVector);
1465
  if locRayStart.V[2] >= 0 then
1466
  begin
1467
    // ray start over plane
1468
    if locRayVector.V[2] < 0 then
1469
    begin
1470
      t := locRayStart.V[2] / locRayVector.V[2];
1471
      ip.V[0] := locRayStart.V[0] - t * locRayVector.V[0];
1472
      ip.V[1] := locRayStart.V[1] - t * locRayVector.V[1];
1473
      if (Abs(ip.V[0]) <= 0.5 * Width) and (Abs(ip.V[1]) <= 0.5 * Height) then
1474
      begin
1475
        Result := True;
1476
        if Assigned(intersectNormal) then
1477
          intersectNormal^ := AbsoluteDirection;
1478
      end
1479
      else
1480
        Result := False;
1481
    end
1482
    else
1483
      Result := False;
1484
  end
1485
  else
1486
  begin
1487
    // ray start below plane
1488
    if locRayVector.V[2] > 0 then
1489
    begin
1490
      t := locRayStart.V[2] / locRayVector.V[2];
1491
      ip.V[0] := locRayStart.V[0] - t * locRayVector.V[0];
1492
      ip.V[1] := locRayStart.V[1] - t * locRayVector.V[1];
1493
      if (Abs(ip.V[0]) <= 0.5 * Width) and (Abs(ip.V[1]) <= 0.5 * Height) then
1494
      begin
1495
        Result := True;
1496
        if Assigned(intersectNormal) then
1497
          intersectNormal^ := VectorNegate(AbsoluteDirection);
1498
      end
1499
      else
1500
        Result := False;
1501
    end
1502
    else
1503
      Result := False;
1504
  end;
1505
  if Result and Assigned(intersectPoint) then
1506
  begin
1507
    ip.V[2] := 0;
1508
    ip.V[3] := 1;
1509
    intersectPoint^ := LocalToAbsolute(ip);
1510
  end;
1511
end;
1512

1513
// GenerateSilhouette
1514
//
1515

1516
function TGLPlane.GenerateSilhouette(const silhouetteParameters
1517
  : TGLSilhouetteParameters): TGLSilhouette;
1518
var
1519
  hw, hh: Single;
1520
begin
1521
  Result := TGLSilhouette.Create;
1522

1523
  hw := FWidth * 0.5;
1524
  hh := FHeight * 0.5;
1525

1526
  with Result.vertices do
1527
  begin
1528
    AddPoint(hw, hh);
1529
    AddPoint(hw, -hh);
1530
    AddPoint(-hw, -hh);
1531
    AddPoint(-hw, hh);
1532
  end;
1533

1534
  with Result.Indices do
1535
  begin
1536
    Add(0, 1);
1537
    Add(1, 2);
1538
    Add(2, 3);
1539
    Add(3, 0);
1540
  end;
1541

1542
  if silhouetteParameters.CappingRequired then
1543
    with Result.CapIndices do
1544
    begin
1545
      Add(0, 1, 2);
1546
      Add(2, 3, 0);
1547
    end;
1548
end;
1549

1550
// BuildList
1551
//
1552

1553
procedure TGLPlane.BuildList(var rci: TGLRenderContextInfo);
1554

1555
  procedure EmitVertex(ptr: PVertexRec); {$IFDEF GLS_INLINE}inline;{$ENDIF}
1556
  begin
1557
    XGL.TexCoord2fv(@ptr^.TexCoord);
1558
    GL.Vertex3fv(@ptr^.Position);
1559
  end;
1560

1561
var
1562
  hw, hh, posXFact, posYFact, pX, pY1: TGLFloat;
1563
  tx0, tx1, ty0, ty1, texSFact, texTFact: TGLFloat;
1564
  texS, texT1: TGLFloat;
1565
  X, Y: Integer;
1566
  TanLoc, BinLoc: Integer;
1567
  pVertex: PVertexRec;
1568
begin
1569
  hw := FWidth * 0.5;
1570
  hh := FHeight * 0.5;
1571

1572
  with GL do
1573
  begin
1574
    Normal3fv(@ZVector);
1575
    if ARB_shader_objects and (rci.GLStates.CurrentProgram > 0) then
1576
    begin
1577
      TanLoc := GetAttribLocation(rci.GLStates.CurrentProgram, PGLChar(TangentAttributeName));
1578
      BinLoc := GetAttribLocation(rci.GLStates.CurrentProgram, PGLChar(BinormalAttributeName));
1579
      if TanLoc > -1 then
1580
        VertexAttrib3fv(TanLoc, @XVector);
1581
      if BinLoc > -1 then
1582
        VertexAttrib3fv(BinLoc, @YVector);
1583
    end;
1584
  end;
1585
  // determine tex coords extents
1586
  if psTileTexture in FStyle then
1587
  begin
1588
    tx0 := FXOffset;
1589
    tx1 := FXTiles * FXScope + FXOffset;
1590
    ty0 := FYOffset;
1591
    ty1 := FYTiles * FYScope + FYOffset;
1592
  end
1593
  else
1594
  begin
1595
    tx0 := 0;
1596
    ty0 := tx0;
1597
    tx1 := FXScope;
1598
    ty1 := FYScope;
1599
  end;
1600

1601
  if psSingleQuad in FStyle then
1602
  begin
1603
    // single quad plane
1604
    GL.Begin_(GL_TRIANGLES);
1605
    xgl.TexCoord2f(tx1, ty1);
1606
    GL.Vertex2f(hw, hh);
1607
    xgl.TexCoord2f(tx0, ty1);
1608
    GL.Vertex2f(-hw, hh);
1609
    xgl.TexCoord2f(tx0, ty0);
1610
    GL.Vertex2f(-hw, -hh);
1611

1612
    GL.Vertex2f(-hw, -hh);
1613
    xgl.TexCoord2f(tx1, ty0);
1614
    GL.Vertex2f(hw, -hh);
1615
    xgl.TexCoord2f(tx1, ty1);
1616
    GL.Vertex2f(hw, hh);
1617
    GL.End_;
1618
    exit;
1619
  end
1620
  else
1621
  begin
1622
    // multi-quad plane (actually built from tri-strips)
1623
    texSFact := (tx1 - tx0) / FXTiles;
1624
    texTFact := (ty1 - ty0) / FYTiles;
1625
    posXFact := FWidth / FXTiles;
1626
    posYFact := FHeight / FYTiles;
1627
    if FMesh = nil then
1628
    begin
1629
      SetLength(FMesh, FYTiles+1, FXTiles+1);
1630
      for Y := 0 to FYTiles do
1631
      begin
1632
        texT1 := Y * texTFact;
1633
        pY1 := Y * posYFact - hh;
1634
        for X := 0 to FXTiles do
1635
        begin
1636
          texS := X * texSFact;
1637
          pX := X * posXFact - hw;
1638
          FMesh[Y][X].Position := Vector3fMake(pX, pY1, 0.0);
1639
          FMesh[Y][X].TexCoord := Vector2fMake(texS, texT1);
1640
        end;
1641
      end;
1642
    end;
1643
  end;
1644

1645
  with GL do
1646
  begin
1647
    Begin_(GL_TRIANGLES);
1648
    for Y := 0 to FYTiles-1 do
1649
    begin
1650
      for X := 0 to FXTiles-1 do
1651
      begin
1652
        pVertex := @FMesh[Y][X];
1653
        EmitVertex(pVertex);
1654

1655
        pVertex := @FMesh[Y][X+1];
1656
        EmitVertex(pVertex);
1657

1658
        pVertex := @FMesh[Y+1][X];
1659
        EmitVertex(pVertex);
1660

1661
        pVertex := @FMesh[Y+1][X+1];
1662
        EmitVertex(pVertex);
1663

1664
        pVertex := @FMesh[Y+1][X];
1665
        EmitVertex(pVertex);
1666

1667
        pVertex := @FMesh[Y][X+1];
1668
        EmitVertex(pVertex);
1669
      end;
1670
    end;
1671
    End_;
1672
  end;
1673
end;
1674

1675
// SetWidth
1676
//
1677

1678
procedure TGLPlane.SetWidth(const aValue: Single);
1679
begin
1680
  if aValue <> FWidth then
1681
  begin
1682
    FWidth := aValue;
1683
    FMesh := nil;
1684
    StructureChanged;
1685
  end;
1686
end;
1687

1688
// ScreenRect
1689
//
1690

1691
function TGLPlane.ScreenRect(aBuffer: TGLSceneBuffer): TGLRect;
1692
var
1693
  v: array [0 .. 3] of TVector;
1694
  buf: TGLSceneBuffer;
1695
  hw, hh: TGLFloat;
1696
begin
1697
  buf := aBuffer;
1698
  if Assigned(buf) then
1699
  begin
1700
    hw := FWidth * 0.5;
1701
    hh := FHeight * 0.5;
1702
    v[0] := LocalToAbsolute(PointMake(-hw, -hh, 0));
1703
    v[1] := LocalToAbsolute(PointMake(hw, -hh, 0));
1704
    v[2] := LocalToAbsolute(PointMake(hw, hh, 0));
1705
    v[3] := LocalToAbsolute(PointMake(-hw, hh, 0));
1706
    buf.WorldToScreen(@v[0], 4);
1707
    Result.Left := Round(MinFloat([v[0].V[0], v[1].V[0], v[2].V[0], v[3].V[0]]));
1708
    Result.Right := Round(MaxFloat([v[0].V[0], v[1].V[0], v[2].V[0], v[3].V[0]]));
1709
    Result.Top := Round(MinFloat([v[0].V[1], v[1].V[1], v[2].V[1], v[3].V[1]]));
1710
    Result.Bottom := Round(MaxFloat([v[0].V[1], v[1].V[1], v[2].V[1], v[3].V[1]]));
1711
  end
1712
  else
1713
    FillChar(Result, SizeOf(TGLRect), 0);
1714
end;
1715

1716
// PointDistance
1717
//
1718

1719
function TGLPlane.PointDistance(const aPoint: TVector): Single;
1720
begin
1721
  Result := VectorDotProduct(VectorSubtract(aPoint, AbsolutePosition),
1722
    AbsoluteDirection);
1723
end;
1724

1725
// SetHeight
1726
//
1727

1728
procedure TGLPlane.SetHeight(const aValue: Single);
1729
begin
1730
  if aValue <> FHeight then
1731
  begin
1732
    FHeight := aValue;
1733
    FMesh := nil;
1734
    StructureChanged;
1735
  end;
1736
end;
1737

1738
// SetXOffset
1739
//
1740

1741
procedure TGLPlane.SetXOffset(const Value: TGLFloat);
1742
begin
1743
  if Value <> FXOffset then
1744
  begin
1745
    FXOffset := Value;
1746
    FMesh := nil;
1747
    StructureChanged;
1748
  end;
1749
end;
1750

1751
// SetXScope
1752
//
1753

1754
procedure TGLPlane.SetXScope(const Value: TGLFloat);
1755
begin
1756
  if Value <> FXScope then
1757
  begin
1758
    FXScope := Value;
1759
    if FXScope > 1 then
1760
      FXScope := 1;
1761
    FMesh := nil;
1762
    StructureChanged;
1763
  end;
1764
end;
1765

1766
// StoreXScope
1767
//
1768

1769
function TGLPlane.StoreXScope: Boolean;
1770
begin
1771
  Result := (FXScope <> 1);
1772
end;
1773

1774
// SetXTiles
1775
//
1776

1777
procedure TGLPlane.SetXTiles(const Value: Cardinal);
1778
begin
1779
  if Value <> FXTiles then
1780
  begin
1781
    FXTiles := Value;
1782
    FMesh := nil;
1783
    StructureChanged;
1784
  end;
1785
end;
1786

1787
// SetYOffset
1788
//
1789

1790
procedure TGLPlane.SetYOffset(const Value: TGLFloat);
1791
begin
1792
  if Value <> FYOffset then
1793
  begin
1794
    FYOffset := Value;
1795
    FMesh := nil;
1796
    StructureChanged;
1797
  end;
1798
end;
1799

1800
// SetYScope
1801
//
1802

1803
procedure TGLPlane.SetYScope(const Value: TGLFloat);
1804
begin
1805
  if Value <> FYScope then
1806
  begin
1807
    FYScope := Value;
1808
    if FYScope > 1 then
1809
      FYScope := 1;
1810
    FMesh := nil;
1811
    StructureChanged;
1812
  end;
1813
end;
1814

1815
// StoreYScope
1816
//
1817

1818
function TGLPlane.StoreYScope: Boolean;
1819
begin
1820
  Result := (FYScope <> 1);
1821
end;
1822

1823
// SetYTiles
1824
//
1825

1826
procedure TGLPlane.SetYTiles(const Value: Cardinal);
1827
begin
1828
  if Value <> FYTiles then
1829
  begin
1830
    FYTiles := Value;
1831
    FMesh := nil;
1832
    StructureChanged;
1833
  end;
1834
end;
1835

1836
// SetStyle
1837
//
1838

1839
procedure TGLPlane.SetStyle(const val: TPlaneStyles);
1840
begin
1841
  if val <> FStyle then
1842
  begin
1843
    FStyle := val;
1844
    StructureChanged;
1845
  end;
1846
end;
1847

1848
// ------------------
1849
// ------------------ TGLSprite ------------------
1850
// ------------------
1851

1852
// Create
1853
//
1854

1855
constructor TGLSprite.Create(AOwner: TComponent);
1856
begin
1857
  inherited Create(AOwner);
1858
  ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
1859
  FAlphaChannel := 1;
1860
  FWidth := 1;
1861
  FHeight := 1;
1862
end;
1863

1864
 
1865
//
1866

1867
procedure TGLSprite.Assign(Source: TPersistent);
1868
begin
1869
  if Source is TGLSprite then
1870
  begin
1871
    FWidth := TGLSprite(Source).FWidth;
1872
    FHeight := TGLSprite(Source).FHeight;
1873
    FRotation := TGLSprite(Source).FRotation;
1874
    FAlphaChannel := TGLSprite(Source).FAlphaChannel;
1875
  end;
1876
  inherited Assign(Source);
1877
end;
1878

1879
function TGLSprite.AxisAlignedDimensionsUnscaled: TVector;
1880
begin
1881
  Result.V[0] := 0.5 * Abs(FWidth);
1882
  Result.V[1] := 0.5 * Abs(FHeight);
1883
  // Sprites turn with the camera and can be considered to have the same depth
1884
  // as width
1885
  Result.V[2] := 0.5 * Abs(FWidth);
1886
end;
1887

1888
// BuildList
1889
//
1890

1891
procedure TGLSprite.BuildList(var rci: TGLRenderContextInfo);
1892
var
1893
  vx, vy: TAffineVector;
1894
  w, h: Single;
1895
  mat: TMatrix;
1896
  u0, v0, u1, v1: Integer;
1897
begin
1898
  if FAlphaChannel <> 1 then
1899
    rci.GLStates.SetGLMaterialAlphaChannel(GL_FRONT, FAlphaChannel);
1900

1901
  mat := rci.PipelineTransformation.ModelViewMatrix;
1902
  // extraction of the "vecteurs directeurs de la matrice"
1903
  // (dunno how they are named in english)
1904
  w := FWidth * 0.5;
1905
  h := FHeight * 0.5;
1906
  vx.V[0] := mat.V[0].V[0];
1907
  vy.V[0] := mat.V[0].V[1];
1908
  vx.V[1] := mat.V[1].V[0];
1909
  vy.V[1] := mat.V[1].V[1];
1910
  vx.V[2] := mat.V[2].V[0];
1911
  vy.V[2] := mat.V[2].V[1];
1912
  ScaleVector(vx, w / VectorLength(vx));
1913
  ScaleVector(vy, h / VectorLength(vy));
1914
  if FMirrorU then
1915
  begin
1916
    u0 := 1;
1917
    u1 := 0;
1918
  end
1919
  else
1920
  begin
1921
    u0 := 0;
1922
    u1 := 1;
1923
  end;
1924
  if FMirrorV then
1925
  begin
1926
    v0 := 1;
1927
    v1 := 0;
1928
  end
1929
  else
1930
  begin
1931
    v0 := 0;
1932
    v1 := 1;
1933
  end;
1934

1935
  if FRotation <> 0 then
1936
  begin
1937
    GL.PushMatrix;
1938
    GL.Rotatef(FRotation, mat.V[0].V[2], mat.V[1].V[2], mat.V[2].V[2]);
1939
  end;
1940
  GL.Begin_(GL_QUADS);
1941
  xgl.TexCoord2f(u1, v1);
1942
  GL.Vertex3f(vx.V[0] + vy.V[0], vx.V[1] + vy.V[1], vx.V[2] + vy.V[2]);
1943
  xgl.TexCoord2f(u0, v1);
1944
  GL.Vertex3f(-vx.V[0] + vy.V[0], -vx.V[1] + vy.V[1], -vx.V[2] + vy.V[2]);
1945
  xgl.TexCoord2f(u0, v0);
1946
  GL.Vertex3f(-vx.V[0] - vy.V[0], -vx.V[1] - vy.V[1], -vx.V[2] - vy.V[2]);
1947
  xgl.TexCoord2f(u1, v0);
1948
  GL.Vertex3f(vx.V[0] - vy.V[0], vx.V[1] - vy.V[1], vx.V[2] - vy.V[2]);
1949
  GL.End_;
1950
  if FRotation <> 0 then
1951
    GL.PopMatrix;
1952
end;
1953

1954
// SetWidth
1955
//
1956

1957
procedure TGLSprite.SetWidth(const val: TGLFloat);
1958
begin
1959
  if FWidth <> val then
1960
  begin
1961
    FWidth := val;
1962
    NotifyChange(Self);
1963
  end;
1964
end;
1965

1966
// SetHeight
1967
//
1968

1969
procedure TGLSprite.SetHeight(const val: TGLFloat);
1970
begin
1971
  if FHeight <> val then
1972
  begin
1973
    FHeight := val;
1974
    NotifyChange(Self);
1975
  end;
1976
end;
1977

1978
// SetRotation
1979
//
1980

1981
procedure TGLSprite.SetRotation(const val: TGLFloat);
1982
begin
1983
  if FRotation <> val then
1984
  begin
1985
    FRotation := val;
1986
    NotifyChange(Self);
1987
  end;
1988
end;
1989

1990
// SetAlphaChannel
1991
//
1992

1993
procedure TGLSprite.SetAlphaChannel(const val: Single);
1994
begin
1995
  if val <> FAlphaChannel then
1996
  begin
1997
    if val < 0 then
1998
      FAlphaChannel := 0
1999
    else if val > 1 then
2000
      FAlphaChannel := 1
2001
    else
2002
      FAlphaChannel := val;
2003
    NotifyChange(Self);
2004
  end;
2005
end;
2006

2007
// StoreAlphaChannel
2008
//
2009

2010
function TGLSprite.StoreAlphaChannel: Boolean;
2011
begin
2012
  Result := (FAlphaChannel <> 1);
2013
end;
2014

2015
// SetMirrorU
2016
//
2017

2018
procedure TGLSprite.SetMirrorU(const val: Boolean);
2019
begin
2020
  FMirrorU := val;
2021
  NotifyChange(Self);
2022
end;
2023

2024
// SetMirrorV
2025
//
2026

2027
procedure TGLSprite.SetMirrorV(const val: Boolean);
2028
begin
2029
  FMirrorV := val;
2030
  NotifyChange(Self);
2031
end;
2032

2033
// SetSize
2034
//
2035

2036
procedure TGLSprite.SetSize(const Width, Height: TGLFloat);
2037
begin
2038
  FWidth := Width;
2039
  FHeight := Height;
2040
  NotifyChange(Self);
2041
end;
2042

2043
// SetSquareSize
2044
//
2045

2046
procedure TGLSprite.SetSquareSize(const Size: TGLFloat);
2047
begin
2048
  FWidth := Size;
2049
  FHeight := Size;
2050
  NotifyChange(Self);
2051
end;
2052

2053
// ------------------
2054
// ------------------ TGLPointParameters ------------------
2055
// ------------------
2056

2057
// Create
2058
//
2059

2060
constructor TGLPointParameters.Create(AOwner: TPersistent);
2061
begin
2062
  inherited Create(AOwner);
2063
  FMinSize := 0;
2064
  FMaxSize := 128;
2065
  FFadeTresholdSize := 1;
2066
  FDistanceAttenuation := TGLCoordinates.CreateInitialized(Self, XHmgVector,
2067
    csVector);
2068
end;
2069

2070
// Destroy
2071
//
2072

2073
destructor TGLPointParameters.Destroy;
2074
begin
2075
  FDistanceAttenuation.Free;
2076
  inherited;
2077
end;
2078

2079
 
2080
//
2081

2082
procedure TGLPointParameters.Assign(Source: TPersistent);
2083
begin
2084
  if Source is TGLPointParameters then
2085
  begin
2086
    FMinSize := TGLPointParameters(Source).FMinSize;
2087
    FMaxSize := TGLPointParameters(Source).FMaxSize;
2088
    FFadeTresholdSize := TGLPointParameters(Source).FFadeTresholdSize;
2089
    FDistanceAttenuation.Assign(TGLPointParameters(Source).DistanceAttenuation);
2090
  end;
2091
end;
2092

2093
// DefineProperties
2094
//
2095

2096
procedure TGLPointParameters.DefineProperties(Filer: TFiler);
2097
var
2098
  defaultParams: Boolean;
2099
begin
2100
  inherited;
2101
  defaultParams := (FMaxSize = 128) and (FMinSize = 0) and
2102
    (FFadeTresholdSize = 1);
2103
  Filer.DefineBinaryProperty('PointParams', ReadData, WriteData,
2104
    not defaultParams);
2105
end;
2106

2107
// ReadData
2108
//
2109

2110
procedure TGLPointParameters.ReadData(Stream: TStream);
2111
begin
2112
  with Stream do
2113
  begin
2114
    Read(FMinSize, SizeOf(Single));
2115
    Read(FMaxSize, SizeOf(Single));
2116
    Read(FFadeTresholdSize, SizeOf(Single));
2117
  end;
2118
end;
2119

2120
// WriteData
2121
//
2122

2123
procedure TGLPointParameters.WriteData(Stream: TStream);
2124
begin
2125
  with Stream do
2126
  begin
2127
    Write(FMinSize, SizeOf(Single));
2128
    Write(FMaxSize, SizeOf(Single));
2129
    Write(FFadeTresholdSize, SizeOf(Single));
2130
  end;
2131
end;
2132

2133
// Apply
2134
//
2135

2136
procedure TGLPointParameters.Apply;
2137
begin
2138
  if Enabled and GL.ARB_point_parameters then
2139
  begin
2140
    GL.PointParameterf(GL_POINT_SIZE_MIN_ARB, FMinSize);
2141
    GL.PointParameterf(GL_POINT_SIZE_MAX_ARB, FMaxSize);
2142
    GL.PointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_ARB, FFadeTresholdSize);
2143
    GL.PointParameterfv(GL_DISTANCE_ATTENUATION_ARB,
2144
      FDistanceAttenuation.AsAddress);
2145
  end;
2146
end;
2147

2148
// UnApply
2149
//
2150

2151
procedure TGLPointParameters.UnApply;
2152
begin
2153
  if Enabled and GL.ARB_point_parameters then
2154
  begin
2155
    GL.PointParameterf(GL_POINT_SIZE_MIN_ARB, 0);
2156
    GL.PointParameterf(GL_POINT_SIZE_MAX_ARB, 128);
2157
    GL.PointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 1);
2158
    GL.PointParameterfv(GL_DISTANCE_ATTENUATION_ARB, @XVector);
2159
  end;
2160
end;
2161

2162
// SetEnabled
2163
//
2164

2165
procedure TGLPointParameters.SetEnabled(const val: Boolean);
2166
begin
2167
  if val <> FEnabled then
2168
  begin
2169
    FEnabled := val;
2170
    NotifyChange(Self);
2171
  end;
2172
end;
2173

2174
// SetMinSize
2175
//
2176

2177
procedure TGLPointParameters.SetMinSize(const val: Single);
2178
begin
2179
  if val <> FMinSize then
2180
  begin
2181
    if val < 0 then
2182
      FMinSize := 0
2183
    else
2184
      FMinSize := val;
2185
    NotifyChange(Self);
2186
  end;
2187
end;
2188

2189
// SetMaxSize
2190
//
2191

2192
procedure TGLPointParameters.SetMaxSize(const val: Single);
2193
begin
2194
  if val <> FMaxSize then
2195
  begin
2196
    if val < 0 then
2197
      FMaxSize := 0
2198
    else
2199
      FMaxSize := val;
2200
    NotifyChange(Self);
2201
  end;
2202
end;
2203

2204
// SetFadeTresholdSize
2205
//
2206

2207
procedure TGLPointParameters.SetFadeTresholdSize(const val: Single);
2208
begin
2209
  if val <> FFadeTresholdSize then
2210
  begin
2211
    if val < 0 then
2212
      FFadeTresholdSize := 0
2213
    else
2214
      FFadeTresholdSize := val;
2215
    NotifyChange(Self);
2216
  end;
2217
end;
2218

2219
// SetDistanceAttenuation
2220
//
2221

2222
procedure TGLPointParameters.SetDistanceAttenuation(const val: TGLCoordinates);
2223
begin
2224
  FDistanceAttenuation.Assign(val);
2225
end;
2226

2227
// ------------------
2228
// ------------------ TGLPoints ------------------
2229
// ------------------
2230

2231
// Create
2232
//
2233

2234
constructor TGLPoints.Create(AOwner: TComponent);
2235
begin
2236
  inherited Create(AOwner);
2237
  ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
2238
  FStyle := psSquare;
2239
  FSize := cDefaultPointSize;
2240
  FPositions := TAffineVectorList.Create;
2241
  FPositions.Add(NullVector);
2242
  FColors := TVectorList.Create;
2243
  FPointParameters := TGLPointParameters.Create(Self);
2244
end;
2245

2246
// Destroy
2247
//
2248

2249
destructor TGLPoints.Destroy;
2250
begin
2251
  FPointParameters.Free;
2252
  FColors.Free;
2253
  FPositions.Free;
2254
  inherited;
2255
end;
2256

2257
 
2258
//
2259

2260
procedure TGLPoints.Assign(Source: TPersistent);
2261
begin
2262
  if Source is TGLPoints then
2263
  begin
2264
    FSize := TGLPoints(Source).FSize;
2265
    FStyle := TGLPoints(Source).FStyle;
2266
    FPositions.Assign(TGLPoints(Source).FPositions);
2267
    FColors.Assign(TGLPoints(Source).FColors);
2268
    StructureChanged
2269
  end;
2270
  inherited Assign(Source);
2271
end;
2272

2273
// BuildList
2274
//
2275

2276
procedure TGLPoints.BuildList(var rci: TGLRenderContextInfo);
2277
var
2278
  n: Integer;
2279
  v: TVector;
2280
begin
2281
  n := FPositions.Count;
2282
  if n = 0 then
2283
    Exit;
2284

2285
  case FColors.Count of
2286
    0:
2287
      GL.Color4f(1, 1, 1, 1);
2288
    1:
2289
      GL.Color4fv(PGLFloat(FColors.List));
2290
  else
2291
    if FColors.Count < n then
2292
      n := FColors.Count;
2293
    GL.ColorPointer(4, GL_FLOAT, 0, FColors.List);
2294
    GL.EnableClientState(GL_COLOR_ARRAY);
2295
  end;
2296
  if FColors.Count < 2 then
2297
    GL.DisableClientState(GL_COLOR_ARRAY);
2298

2299
  rci.GLStates.Disable(stLighting);
2300
  if n = 0 then
2301
  begin
2302
    v := NullHmgPoint;
2303
    GL.VertexPointer(3, GL_FLOAT, 0, @v);
2304
    n := 1;
2305
  end
2306
  else
2307
    GL.VertexPointer(3, GL_FLOAT, 0, FPositions.List);
2308
  GL.EnableClientState(GL_VERTEX_ARRAY);
2309

2310
  if NoZWrite then
2311
    rci.GLStates.DepthWriteMask := False;
2312
  rci.GLStates.PointSize := FSize;
2313
  PointParameters.Apply;
2314
  if GL.EXT_compiled_vertex_array and (n > 64) then
2315
    GL.LockArrays(0, n);
2316
  case FStyle of
2317
    psSquare:
2318
      begin
2319
        // square point (simplest method, fastest)
2320
        rci.GLStates.Disable(stBlend);
2321
      end;
2322
    psRound:
2323
      begin
2324
        rci.GLStates.Enable(stPointSmooth);
2325
        rci.GLStates.Enable(stAlphaTest);
2326
        rci.GLStates.SetGLAlphaFunction(cfGreater, 0.5);
2327
        rci.GLStates.Disable(stBlend);
2328
      end;
2329
    psSmooth:
2330
      begin
2331
        rci.GLStates.Enable(stPointSmooth);
2332
        rci.GLStates.Enable(stAlphaTest);
2333
        rci.GLStates.SetGLAlphaFunction(cfNotEqual, 0.0);
2334
        rci.GLStates.Enable(stBlend);
2335
        rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
2336
      end;
2337
    psSmoothAdditive:
2338
      begin
2339
        rci.GLStates.Enable(stPointSmooth);
2340
        rci.GLStates.Enable(stAlphaTest);
2341
        rci.GLStates.SetGLAlphaFunction(cfNotEqual, 0.0);
2342
        rci.GLStates.Enable(stBlend);
2343
        rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOne);
2344
      end;
2345
    psSquareAdditive:
2346
      begin
2347
        rci.GLStates.Enable(stBlend);
2348
        rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOne);
2349
      end;
2350
  else
2351
    Assert(False);
2352
  end;
2353
  GL.DrawArrays(GL_POINTS, 0, n);
2354
  if GL.EXT_compiled_vertex_array and (n > 64) then
2355
    GL.UnlockArrays;
2356
  PointParameters.UnApply;
2357
  GL.DisableClientState(GL_VERTEX_ARRAY);
2358
  if FColors.Count > 1 then
2359
    GL.DisableClientState(GL_COLOR_ARRAY);
2360
end;
2361

2362
// StoreSize
2363
//
2364

2365
function TGLPoints.StoreSize: Boolean;
2366
begin
2367
  Result := (FSize <> cDefaultPointSize);
2368
end;
2369

2370
// SetNoZWrite
2371
//
2372

2373
procedure TGLPoints.SetNoZWrite(const val: Boolean);
2374
begin
2375
  if FNoZWrite <> val then
2376
  begin
2377
    FNoZWrite := val;
2378
    StructureChanged;
2379
  end;
2380
end;
2381

2382
// SetStatic
2383
//
2384

2385
procedure TGLPoints.SetStatic(const val: Boolean);
2386
begin
2387
  if FStatic <> val then
2388
  begin
2389
    FStatic := val;
2390
    if val then
2391
      ObjectStyle := ObjectStyle - [osDirectDraw]
2392
    else
2393
      ObjectStyle := ObjectStyle + [osDirectDraw];
2394
    StructureChanged;
2395
  end;
2396
end;
2397

2398
// SetSize
2399
//
2400

2401
procedure TGLPoints.SetSize(const val: Single);
2402
begin
2403
  if FSize <> val then
2404
  begin
2405
    FSize := val;
2406
    StructureChanged;
2407
  end;
2408
end;
2409

2410
// SetPositions
2411
//
2412

2413
procedure TGLPoints.SetPositions(const val: TAffineVectorList);
2414
begin
2415
  FPositions.Assign(val);
2416
  StructureChanged;
2417
end;
2418

2419
// SetColors
2420
//
2421

2422
procedure TGLPoints.SetColors(const val: TVectorList);
2423
begin
2424
  FColors.Assign(val);
2425
  StructureChanged;
2426
end;
2427

2428
// SetStyle
2429
//
2430

2431
procedure TGLPoints.SetStyle(const val: TGLPointStyle);
2432
begin
2433
  if FStyle <> val then
2434
  begin
2435
    FStyle := val;
2436
    StructureChanged;
2437
  end;
2438
end;
2439

2440
// SetPointParameters
2441
//
2442

2443
procedure TGLPoints.SetPointParameters(const val: TGLPointParameters);
2444
begin
2445
  FPointParameters.Assign(val);
2446
end;
2447

2448
// ------------------
2449
// ------------------ TGLLineBase ------------------
2450
// ------------------
2451

2452
// Create
2453
//
2454

2455
constructor TGLLineBase.Create(AOwner: TComponent);
2456
begin
2457
  inherited Create(AOwner);
2458
  FLineColor := TGLColor.Create(Self);
2459
  FLineColor.Initialize(clrWhite);
2460
  FLinePattern := $FFFF;
2461
  FAntiAliased := False;
2462
  FLineWidth := 1.0;
2463
end;
2464

2465
// Destroy
2466
//
2467

2468
destructor TGLLineBase.Destroy;
2469
begin
2470
  FLineColor.Free;
2471
  inherited Destroy;
2472
end;
2473

2474
procedure TGLLineBase.NotifyChange(Sender: TObject);
2475
begin
2476
  if Sender = FLineColor then
2477
    StructureChanged;
2478
  inherited;
2479
end;
2480

2481
// SetLineColor
2482
//
2483

2484
procedure TGLLineBase.SetLineColor(const Value: TGLColor);
2485
begin
2486
  FLineColor.Color := Value.Color;
2487
  StructureChanged;
2488
end;
2489

2490
// SetLinePattern
2491
//
2492

2493
procedure TGLLineBase.SetLinePattern(const Value: TGLushort);
2494
begin
2495
  if FLinePattern <> Value then
2496
  begin
2497
    FLinePattern := Value;
2498
    StructureChanged;
2499
  end;
2500
end;
2501

2502
// SetLineWidth
2503
//
2504

2505
procedure TGLLineBase.SetLineWidth(const val: Single);
2506
begin
2507
  if FLineWidth <> val then
2508
  begin
2509
    FLineWidth := val;
2510
    StructureChanged;
2511
  end;
2512
end;
2513

2514
// StoreLineWidth
2515
//
2516

2517
function TGLLineBase.StoreLineWidth: Boolean;
2518
begin
2519
  Result := (FLineWidth <> 1.0);
2520
end;
2521

2522
// SetAntiAliased
2523
//
2524

2525
procedure TGLLineBase.SetAntiAliased(const val: Boolean);
2526
begin
2527
  if FAntiAliased <> val then
2528
  begin
2529
    FAntiAliased := val;
2530
    StructureChanged;
2531
  end;
2532
end;
2533

2534
 
2535
//
2536

2537
procedure TGLLineBase.Assign(Source: TPersistent);
2538
begin
2539
  if Source is TGLLineBase then
2540
  begin
2541
    LineColor := TGLLineBase(Source).FLineColor;
2542
    LinePattern := TGLLineBase(Source).FLinePattern;
2543
    LineWidth := TGLLineBase(Source).FLineWidth;
2544
    AntiAliased := TGLLineBase(Source).FAntiAliased;
2545
  end;
2546
  inherited Assign(Source);
2547
end;
2548

2549
// SetupLineStyle
2550
//
2551

2552
procedure TGLLineBase.SetupLineStyle(var rci: TGLRenderContextInfo);
2553
begin
2554
  with rci.GLStates do
2555
  begin
2556
    Disable(stLighting);
2557
    if FLinePattern <> $FFFF then
2558
    begin
2559
      Enable(stLineStipple);
2560
      Enable(stBlend);
2561
      SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
2562
      LineStippleFactor := 1;
2563
      LineStipplePattern := FLinePattern;
2564
    end
2565
    else
2566
      Disable(stLineStipple);
2567
    if FAntiAliased then
2568
    begin
2569
      Enable(stLineSmooth);
2570
      Enable(stBlend);
2571
      SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
2572
    end
2573
    else
2574
      Disable(stLineSmooth);
2575
    LineWidth := FLineWidth;
2576

2577
    if FLineColor.Alpha <> 1 then
2578
    begin
2579
      if not FAntiAliased then
2580
      begin
2581
        Enable(stBlend);
2582
        SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
2583
      end;
2584
      GL.Color4fv(FLineColor.AsAddress);
2585
    end
2586
    else
2587
      GL.Color3fv(FLineColor.AsAddress);
2588

2589
  end;
2590
end;
2591

2592
// ------------------
2593
// ------------------ TGLLinesNode ------------------
2594
// ------------------
2595

2596
// Create
2597
//
2598

2599
constructor TGLLinesNode.Create(Collection: TCollection);
2600
begin
2601
  inherited Create(Collection);
2602
  FColor := TGLColor.Create(Self);
2603
  FColor.Initialize((TGLLinesNodes(Collection).GetOwner as TGLLines)
2604
    .NodeColor.Color);
2605
  FColor.OnNotifyChange := OnColorChange;
2606
end;
2607

2608
// Destroy
2609
//
2610

2611
destructor TGLLinesNode.Destroy;
2612
begin
2613
  FColor.Free;
2614
  inherited Destroy;
2615
end;
2616

2617
 
2618
//
2619

2620
procedure TGLLinesNode.Assign(Source: TPersistent);
2621
begin
2622
  if Source is TGLLinesNode then
2623
    FColor.Assign(TGLLinesNode(Source).FColor);
2624
  inherited;
2625
end;
2626

2627
// SetColor
2628
//
2629

2630
procedure TGLLinesNode.SetColor(const val: TGLColor);
2631
begin
2632
  FColor.Assign(val);
2633
end;
2634

2635
// OnColorChange
2636
//
2637

2638
procedure TGLLinesNode.OnColorChange(Sender: TObject);
2639
begin
2640
  (Collection as TGLNodes).NotifyChange;
2641
end;
2642

2643
// StoreColor
2644
//
2645

2646
function TGLLinesNode.StoreColor: Boolean;
2647
begin
2648
  Result := not VectorEquals((TGLLinesNodes(Collection).GetOwner as TGLLines)
2649
    .NodeColor.Color, FColor.Color);
2650
end;
2651

2652
// ------------------
2653
// ------------------ TGLLinesNodes ------------------
2654
// ------------------
2655

2656
// Create
2657
//
2658

2659
constructor TGLLinesNodes.Create(AOwner: TComponent);
2660
begin
2661
  inherited Create(AOwner, TGLLinesNode);
2662
end;
2663

2664
// NotifyChange
2665
//
2666

2667
procedure TGLLinesNodes.NotifyChange;
2668
begin
2669
  if (GetOwner <> nil) then
2670
    (GetOwner as TGLBaseSceneObject).StructureChanged;
2671
end;
2672

2673
// ------------------
2674
// ------------------ TGLNodedLines ------------------
2675
// ------------------
2676

2677
// Create
2678
//
2679

2680
constructor TGLNodedLines.Create(AOwner: TComponent);
2681
begin
2682
  inherited Create(AOwner);
2683
  FNodes := TGLLinesNodes.Create(Self);
2684
  FNodeColor := TGLColor.Create(Self);
2685
  FNodeColor.Initialize(clrBlue);
2686
  FNodeColor.OnNotifyChange := OnNodeColorChanged;
2687
  FOldNodeColor := clrBlue;
2688
  FNodesAspect := lnaAxes;
2689
  FNodeSize := 1;
2690
end;
2691

2692
// Destroy
2693
//
2694

2695
destructor TGLNodedLines.Destroy;
2696
begin
2697
  FNodes.Free;
2698
  FNodeColor.Free;
2699
  inherited Destroy;
2700
end;
2701

2702
// SetNodesAspect
2703
//
2704

2705
procedure TGLNodedLines.SetNodesAspect(const Value: TLineNodesAspect);
2706
begin
2707
  if Value <> FNodesAspect then
2708
  begin
2709
    FNodesAspect := Value;
2710
    StructureChanged;
2711
  end;
2712
end;
2713

2714
// SetNodeColor
2715
//
2716

2717
procedure TGLNodedLines.SetNodeColor(const Value: TGLColor);
2718
begin
2719
  FNodeColor.Color := Value.Color;
2720
  StructureChanged;
2721
end;
2722

2723
// OnNodeColorChanged
2724
//
2725

2726
procedure TGLNodedLines.OnNodeColorChanged(Sender: TObject);
2727
var
2728
  i: Integer;
2729
begin
2730
  // update color for nodes...
2731
  for i := 0 to Nodes.Count - 1 do
2732
    if VectorEquals(TGLLinesNode(Nodes[i]).Color.Color, FOldNodeColor) then
2733
      TGLLinesNode(Nodes[i]).Color.Assign(FNodeColor);
2734
  SetVector(FOldNodeColor, FNodeColor.Color);
2735
end;
2736

2737
// SetNodes
2738
//
2739

2740
procedure TGLNodedLines.SetNodes(const aNodes: TGLLinesNodes);
2741
begin
2742
  FNodes.Assign(aNodes);
2743
  StructureChanged;
2744
end;
2745

2746
// SetNodeSize
2747
//
2748

2749
procedure TGLNodedLines.SetNodeSize(const val: Single);
2750
begin
2751
  if val <= 0 then
2752
    FNodeSize := 1
2753
  else
2754
    FNodeSize := val;
2755
  StructureChanged;
2756
end;
2757

2758
// StoreNodeSize
2759
//
2760

2761
function TGLNodedLines.StoreNodeSize: Boolean;
2762
begin
2763
  Result := FNodeSize <> 1;
2764
end;
2765

2766
 
2767
//
2768

2769
procedure TGLNodedLines.Assign(Source: TPersistent);
2770
begin
2771
  if Source is TGLNodedLines then
2772
  begin
2773
    SetNodes(TGLNodedLines(Source).FNodes);
2774
    FNodesAspect := TGLNodedLines(Source).FNodesAspect;
2775
    FNodeColor.Color := TGLNodedLines(Source).FNodeColor.Color;
2776
    FNodeSize := TGLNodedLines(Source).FNodeSize;
2777
  end;
2778
  inherited Assign(Source);
2779
end;
2780

2781
// DrawNode
2782
//
2783

2784
procedure TGLNodedLines.DrawNode(var rci: TGLRenderContextInfo; X, Y, Z: Single;
2785
  Color: TGLColor);
2786
begin
2787
  GL.PushMatrix;
2788
  GL.Translatef(X, Y, Z);
2789
  case NodesAspect of
2790
    lnaAxes:
2791
      AxesBuildList(rci, $CCCC, FNodeSize * 0.5);
2792
    lnaCube:
2793
      CubeWireframeBuildList(rci, FNodeSize, False, Color.Color);
2794
    lnaDodecahedron:
2795
      begin
2796
        if FNodeSize <> 1 then
2797
        begin
2798
          GL.PushMatrix;
2799
          GL.Scalef(FNodeSize, FNodeSize, FNodeSize);
2800
          rci.GLStates.SetGLMaterialColors(cmFront, clrBlack, clrGray20,
2801
            Color.Color, clrBlack, 0);
2802
          DodecahedronBuildList;
2803
          GL.PopMatrix;
2804
        end
2805
        else
2806
        begin
2807
          rci.GLStates.SetGLMaterialColors(cmFront, clrBlack, clrGray20,
2808
            Color.Color, clrBlack, 0);
2809
          DodecahedronBuildList;
2810
        end;
2811
      end;
2812
  else
2813
    Assert(False)
2814
  end;
2815
  GL.PopMatrix;
2816
end;
2817

2818
// AxisAlignedDimensionsUnscaled
2819
//
2820

2821
function TGLNodedLines.AxisAlignedDimensionsUnscaled: TVector;
2822
var
2823
  i: Integer;
2824
begin
2825
  RstVector(Result);
2826
  for i := 0 to Nodes.Count - 1 do
2827
    MaxVector(Result, VectorAbs(Nodes[i].AsVector));
2828
  // EG: commented out, line below looks suspicious, since scale isn't taken
2829
  // into account in previous loop, must have been hiding another bug... somewhere...
2830
  // DivideVector(Result, Scale.AsVector);     //DanB ?
2831
end;
2832

2833
// AddNode (coords)
2834
//
2835

2836
procedure TGLNodedLines.AddNode(const coords: TGLCoordinates);
2837
var
2838
  n: TGLNode;
2839
begin
2840
  n := Nodes.Add;
2841
  if Assigned(coords) then
2842
    n.AsVector := coords.AsVector;
2843
  StructureChanged;
2844
end;
2845

2846
// AddNode (xyz)
2847
//
2848

2849
procedure TGLNodedLines.AddNode(const X, Y, Z: TGLFloat);
2850
var
2851
  n: TGLNode;
2852
begin
2853
  n := Nodes.Add;
2854
  n.AsVector := VectorMake(X, Y, Z, 1);
2855
  StructureChanged;
2856
end;
2857

2858
// AddNode (vector)
2859
//
2860

2861
procedure TGLNodedLines.AddNode(const Value: TVector);
2862
var
2863
  n: TGLNode;
2864
begin
2865
  n := Nodes.Add;
2866
  n.AsVector := Value;
2867
  StructureChanged;
2868
end;
2869

2870
// AddNode (affine vector)
2871
//
2872

2873
procedure TGLNodedLines.AddNode(const Value: TAffineVector);
2874
var
2875
  n: TGLNode;
2876
begin
2877
  n := Nodes.Add;
2878
  n.AsVector := VectorMake(Value);
2879
  StructureChanged;
2880
end;
2881

2882
// ------------------
2883
// ------------------ TGLLines ------------------
2884
// ------------------
2885

2886
// Create
2887
//
2888

2889
constructor TGLLines.Create(AOwner: TComponent);
2890
begin
2891
  inherited Create(AOwner);
2892
  FDivision := 10;
2893
  FSplineMode := lsmLines;
2894
  FNURBSKnots := TSingleList.Create;
2895
  FNURBSOrder := 0;
2896
  FNURBSTolerance := 50;
2897
end;
2898

2899
// Destroy
2900
//
2901

2902
destructor TGLLines.Destroy;
2903
begin
2904
  FNURBSKnots.Free;
2905
  inherited Destroy;
2906
end;
2907

2908
// SetDivision
2909
//
2910

2911
procedure TGLLines.SetDivision(const Value: Integer);
2912
begin
2913
  if Value <> FDivision then
2914
  begin
2915
    if Value < 1 then
2916
      FDivision := 1
2917
    else
2918
      FDivision := Value;
2919
    StructureChanged;
2920
  end;
2921
end;
2922

2923
// SetOptions
2924
//
2925

2926
procedure TGLLines.SetOptions(const val: TLinesOptions);
2927
begin
2928
  FOptions := val;
2929
  StructureChanged;
2930
end;
2931

2932
// SetSplineMode
2933
//
2934

2935
procedure TGLLines.SetSplineMode(const val: TGLLineSplineMode);
2936
begin
2937
  if FSplineMode <> val then
2938
  begin
2939
    FSplineMode := val;
2940
    StructureChanged;
2941
  end;
2942
end;
2943

2944
// SetNURBSOrder
2945
//
2946

2947
procedure TGLLines.SetNURBSOrder(const val: Integer);
2948
begin
2949
  if val <> FNURBSOrder then
2950
  begin
2951
    FNURBSOrder := val;
2952
    StructureChanged;
2953
  end;
2954
end;
2955

2956
// SetNURBSTolerance
2957
//
2958

2959
procedure TGLLines.SetNURBSTolerance(const val: Single);
2960
begin
2961
  if val <> FNURBSTolerance then
2962
  begin
2963
    FNURBSTolerance := val;
2964
    StructureChanged;
2965
  end;
2966
end;
2967

2968
 
2969
//
2970

2971
procedure TGLLines.Assign(Source: TPersistent);
2972
begin
2973
  if Source is TGLLines then
2974
  begin
2975
    FDivision := TGLLines(Source).FDivision;
2976
    FSplineMode := TGLLines(Source).FSplineMode;
2977
    FOptions := TGLLines(Source).FOptions;
2978
  end;
2979
  inherited Assign(Source);
2980
end;
2981

2982
// BuildList
2983
//
2984

2985
procedure TGLLines.BuildList(var rci: TGLRenderContextInfo);
2986
var
2987
  i, n: Integer;
2988
  A, B, C: TGLFloat;
2989
  f: Single;
2990
  Spline: TCubicSpline;
2991
  vertexColor: TVector;
2992
  nodeBuffer: array of TAffineVector;
2993
  colorBuffer: array of TVector;
2994
  nurbsRenderer: PGLUNurbs;
2995
begin
2996
  if Nodes.Count > 1 then
2997
  begin
2998
    // first, we setup the line color & stippling styles
2999
    SetupLineStyle(rci);
3000
    if rci.bufferDepthTest then
3001
      rci.GLStates.Enable(stDepthTest);
3002
    if loColorLogicXor in Options then
3003
    begin
3004
      rci.GLStates.Enable(stColorLogicOp);
3005
      rci.GLStates.LogicOpMode := loXOr;
3006
    end;
3007
    // Set up the control point buffer for Bezier splines and NURBS curves.
3008
    // If required this could be optimized by storing a cached node buffer.
3009
    if (FSplineMode = lsmBezierSpline) or (FSplineMode = lsmNURBSCurve) then
3010
    begin
3011
      SetLength(nodeBuffer, Nodes.Count);
3012
      SetLength(colorBuffer, Nodes.Count);
3013
      for i := 0 to Nodes.Count - 1 do
3014
        with TGLLinesNode(Nodes[i]) do
3015
        begin
3016
          nodeBuffer[i] := AsAffineVector;
3017
          colorBuffer[i] := Color.Color;
3018
        end;
3019
    end;
3020

3021
    if FSplineMode = lsmBezierSpline then
3022
    begin
3023
      // map evaluator
3024
      rci.GLStates.PushAttrib([sttEval]);
3025
      GL.Enable(GL_MAP1_VERTEX_3);
3026
      GL.Enable(GL_MAP1_COLOR_4);
3027

3028
      GL.Map1f(GL_MAP1_VERTEX_3, 0, 1, 3, Nodes.Count, @nodeBuffer[0]);
3029
      GL.Map1f(GL_MAP1_COLOR_4, 0, 1, 4, Nodes.Count, @colorBuffer[0]);
3030
    end;
3031

3032
    // start drawing the line
3033
    if (FSplineMode = lsmNURBSCurve) and (FDivision >= 2) then
3034
    begin
3035
      if (FNURBSOrder > 0) and (FNURBSKnots.Count > 0) then
3036
      begin
3037

3038
        nurbsRenderer := gluNewNurbsRenderer;
3039
        try
3040
          gluNurbsProperty(nurbsRenderer, GLU_SAMPLING_TOLERANCE,
3041
            FNURBSTolerance);
3042
          gluNurbsProperty(nurbsRenderer, GLU_DISPLAY_MODE, GLU_FILL);
3043
          gluBeginCurve(nurbsRenderer);
3044
          gluNurbsCurve(nurbsRenderer, FNURBSKnots.Count, @FNURBSKnots.List[0],
3045
            3, @nodeBuffer[0], FNURBSOrder, GL_MAP1_VERTEX_3);
3046
          gluEndCurve(nurbsRenderer);
3047
        finally
3048
          gluDeleteNurbsRenderer(nurbsRenderer);
3049
        end;
3050
      end;
3051
    end
3052
    else
3053
    begin
3054
      // lines, cubic splines or bezier
3055
      if FSplineMode = lsmSegments then
3056
        GL.Begin_(GL_LINES)
3057
      else if FSplineMode = lsmLoop then
3058
        GL.Begin_(GL_LINE_LOOP)
3059
      else
3060
        GL.Begin_(GL_LINE_STRIP);
3061
      if (FDivision < 2) or (FSplineMode in [lsmLines, lsmSegments,
3062
        lsmLoop]) then
3063
      begin
3064
        // standard line(s), draw directly
3065
        if loUseNodeColorForLines in Options then
3066
        begin
3067
          // node color interpolation
3068
          for i := 0 to Nodes.Count - 1 do
3069
            with TGLLinesNode(Nodes[i]) do
3070
            begin
3071
              GL.Color4fv(Color.AsAddress);
3072
              GL.Vertex3f(X, Y, Z);
3073
            end;
3074
        end
3075
        else
3076
        begin
3077
          // single color
3078
          for i := 0 to Nodes.Count - 1 do
3079
            with Nodes[i] do
3080
              GL.Vertex3f(X, Y, Z);
3081
        end;
3082
      end
3083
      else if FSplineMode = lsmCubicSpline then
3084
      begin
3085
        // cubic spline
3086
        Spline := Nodes.CreateNewCubicSpline;
3087
        try
3088
          f := 1 / FDivision;
3089
          for i := 0 to (Nodes.Count - 1) * FDivision do
3090
          begin
3091
            Spline.SplineXYZ(i * f, A, B, C);
3092
            if loUseNodeColorForLines in Options then
3093
            begin
3094
              n := (i div FDivision);
3095
              if n < Nodes.Count - 1 then
3096
                VectorLerp(TGLLinesNode(Nodes[n]).Color.Color,
3097
                  TGLLinesNode(Nodes[n + 1]).Color.Color, (i mod FDivision) * f,
3098
                  vertexColor)
3099
              else
3100
                SetVector(vertexColor, TGLLinesNode(Nodes[Nodes.Count - 1])
3101
                  .Color.Color);
3102
              GL.Color4fv(@vertexColor);
3103
            end;
3104
            GL.Vertex3f(A, B, C);
3105
          end;
3106
        finally
3107
          Spline.Free;
3108
        end;
3109
      end
3110
      else if FSplineMode = lsmBezierSpline then
3111
      begin
3112
        f := 1 / FDivision;
3113
        for i := 0 to FDivision do
3114
          GL.EvalCoord1f(i * f);
3115
      end;
3116
      GL.End_;
3117
    end;
3118
    rci.GLStates.Disable(stColorLogicOp);
3119

3120
    if FSplineMode = lsmBezierSpline then
3121
      rci.GLStates.PopAttrib;
3122
    if Length(nodeBuffer) > 0 then
3123
    begin
3124
      SetLength(nodeBuffer, 0);
3125
      SetLength(colorBuffer, 0);
3126
    end;
3127

3128
    if FNodesAspect <> lnaInvisible then
3129
    begin
3130
      if not rci.ignoreBlendingRequests then
3131
      begin
3132
        rci.GLStates.Enable(stBlend);
3133
        rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
3134
      end;
3135

3136
      for i := 0 to Nodes.Count - 1 do
3137
        with TGLLinesNode(Nodes[i]) do
3138
          DrawNode(rci, X, Y, Z, Color);
3139
    end;
3140
  end;
3141
end;
3142

3143
// ------------------
3144
// ------------------ TGLCube ------------------
3145
// ------------------
3146

3147
// Create
3148
//
3149

3150
constructor TGLCube.Create(AOwner: TComponent);
3151
begin
3152
  inherited Create(AOwner);
3153
  FCubeSize := XYZVector;
3154
  FParts := [cpTop, cpBottom, cpFront, cpBack, cpLeft, cpRight];
3155
  FNormalDirection := ndOutside;
3156
  ObjectStyle := ObjectStyle + [osDirectDraw];
3157
end;
3158

3159
// BuildList
3160
//
3161

3162
procedure TGLCube.BuildList(var rci: TGLRenderContextInfo);
3163
var
3164
  hw, hh, hd, nd: TGLFloat;
3165
  TanLoc, BinLoc: Integer;
3166
begin
3167
  if FNormalDirection = ndInside then
3168
    nd := -1
3169
  else
3170
    nd := 1;
3171
  hw := FCubeSize.X * 0.5;
3172
  hh := FCubeSize.Y * 0.5;
3173
  hd := FCubeSize.Z * 0.5;
3174

3175
  with GL do
3176
  begin
3177
    if ARB_shader_objects and (rci.GLStates.CurrentProgram > 0) then
3178
    begin
3179
      TanLoc := GetAttribLocation(rci.GLStates.CurrentProgram, PGLChar(TangentAttributeName));
3180
      BinLoc := GetAttribLocation(rci.GLStates.CurrentProgram, PGLChar(BinormalAttributeName));
3181
    end
3182
    else
3183
    begin
3184
      TanLoc := -1;
3185
      BinLoc := -1;
3186
    end;
3187

3188
    Begin_(GL_TRIANGLES);
3189
    if cpFront in FParts then
3190
    begin
3191
      Normal3f(0, 0, nd);
3192
      if TanLoc > -1 then
3193
        VertexAttrib3f(TanLoc, nd, 0, 0);
3194
      if BinLoc > -1 then
3195
        VertexAttrib3f(BinLoc, 0, nd, 0);
3196
      xgl.TexCoord2fv(@XYTexPoint);
3197
      Vertex3f(hw, hh, hd);
3198
      xgl.TexCoord2fv(@YTexPoint);
3199
      Vertex3f(-hw * nd, hh * nd, hd);
3200
      xgl.TexCoord2fv(@NullTexPoint);
3201
      Vertex3f(-hw, -hh, hd);
3202
      Vertex3f(-hw, -hh, hd);
3203
      xgl.TexCoord2fv(@XTexPoint);
3204
      Vertex3f(hw * nd, -hh * nd, hd);
3205
      xgl.TexCoord2fv(@XYTexPoint);
3206
      Vertex3f(hw, hh, hd);
3207
    end;
3208
    if cpBack in FParts then
3209
    begin
3210
      Normal3f(0, 0, -nd);
3211
      if TanLoc > -1 then
3212
        VertexAttrib3f(TanLoc, -nd, 0, 0);
3213
      if BinLoc > -1 then
3214
        VertexAttrib3f(BinLoc, 0, nd, 0);
3215
      xgl.TexCoord2fv(@YTexPoint);
3216
      Vertex3f(hw, hh, -hd);
3217
      xgl.TexCoord2fv(@NullTexPoint);
3218
      Vertex3f(hw * nd, -hh * nd, -hd);
3219
      xgl.TexCoord2fv(@XTexPoint);
3220
      Vertex3f(-hw, -hh, -hd);
3221
      Vertex3f(-hw, -hh, -hd);
3222
      xgl.TexCoord2fv(@XYTexPoint);
3223
      Vertex3f(-hw * nd, hh * nd, -hd);
3224
      xgl.TexCoord2fv(@YTexPoint);
3225
      Vertex3f(hw, hh, -hd);
3226
    end;
3227
    if cpLeft in FParts then
3228
    begin
3229
      Normal3f(-nd, 0, 0);
3230
      if TanLoc > -1 then
3231
        VertexAttrib3f(TanLoc, 0, 0, nd);
3232
      if BinLoc > -1 then
3233
        VertexAttrib3f(BinLoc, 0, nd, 0);
3234
      xgl.TexCoord2fv(@XYTexPoint);
3235
      Vertex3f(-hw, hh, hd);
3236
      xgl.TexCoord2fv(@YTexPoint);
3237
      Vertex3f(-hw, hh * nd, -hd * nd);
3238
      xgl.TexCoord2fv(@NullTexPoint);
3239
      Vertex3f(-hw, -hh, -hd);
3240
      Vertex3f(-hw, -hh, -hd);
3241
      xgl.TexCoord2fv(@XTexPoint);
3242
      Vertex3f(-hw, -hh * nd, hd * nd);
3243
      xgl.TexCoord2fv(@XYTexPoint);
3244
      Vertex3f(-hw, hh, hd);
3245
    end;
3246
    if cpRight in FParts then
3247
    begin
3248
      Normal3f(nd, 0, 0);
3249
      if TanLoc > -1 then
3250
        VertexAttrib3f(TanLoc, 0, 0, -nd);
3251
      if BinLoc > -1 then
3252
        VertexAttrib3f(BinLoc, 0, nd, 0);
3253
      xgl.TexCoord2fv(@YTexPoint);
3254
      Vertex3f(hw, hh, hd);
3255
      xgl.TexCoord2fv(@NullTexPoint);
3256
      Vertex3f(hw, -hh * nd, hd * nd);
3257
      xgl.TexCoord2fv(@XTexPoint);
3258
      Vertex3f(hw, -hh, -hd);
3259
      Vertex3f(hw, -hh, -hd);
3260
      xgl.TexCoord2fv(@XYTexPoint);
3261
      Vertex3f(hw, hh * nd, -hd * nd);
3262
      xgl.TexCoord2fv(@YTexPoint);
3263
      Vertex3f(hw, hh, hd);
3264
    end;
3265
    if cpTop in FParts then
3266
    begin
3267
      Normal3f(0, nd, 0);
3268
      if TanLoc > -1 then
3269
        VertexAttrib3f(TanLoc, nd, 0, 0);
3270
      if BinLoc > -1 then
3271
        VertexAttrib3f(BinLoc, 0, 0, -nd);
3272
      xgl.TexCoord2fv(@YTexPoint);
3273
      Vertex3f(-hw, hh, -hd);
3274
      xgl.TexCoord2fv(@NullTexPoint);
3275
      Vertex3f(-hw * nd, hh, hd * nd);
3276
      xgl.TexCoord2fv(@XTexPoint);
3277
      Vertex3f(hw, hh, hd);
3278
      Vertex3f(hw, hh, hd);
3279
      xgl.TexCoord2fv(@XYTexPoint);
3280
      Vertex3f(hw * nd, hh, -hd * nd);
3281
      xgl.TexCoord2fv(@YTexPoint);
3282
      Vertex3f(-hw, hh, -hd);
3283
    end;
3284
    if cpBottom in FParts then
3285
    begin
3286
      Normal3f(0, -nd, 0);
3287
      if TanLoc > -1 then
3288
        VertexAttrib3f(TanLoc, -nd, 0, 0);
3289
      if BinLoc > -1 then
3290
        VertexAttrib3f(BinLoc, 0, 0, nd);
3291
      xgl.TexCoord2fv(@NullTexPoint);
3292
      Vertex3f(-hw, -hh, -hd);
3293
      xgl.TexCoord2fv(@XTexPoint);
3294
      Vertex3f(hw * nd, -hh, -hd * nd);
3295
      xgl.TexCoord2fv(@XYTexPoint);
3296
      Vertex3f(hw, -hh, hd);
3297
      Vertex3f(hw, -hh, hd);
3298
      xgl.TexCoord2fv(@YTexPoint);
3299
      Vertex3f(-hw * nd, -hh, hd * nd);
3300
      xgl.TexCoord2fv(@NullTexPoint);
3301
      Vertex3f(-hw, -hh, -hd);
3302
    end;
3303
    End_;
3304
  end;
3305
end;
3306

3307
// GenerateSilhouette
3308
//
3309

3310
function TGLCube.GenerateSilhouette(const silhouetteParameters
3311
  : TGLSilhouetteParameters): TGLSilhouette;
3312
var
3313
  hw, hh, hd: TGLFloat;
3314
  connectivity: TConnectivity;
3315
  sil: TGLSilhouette;
3316
begin
3317
  connectivity := TConnectivity.Create(True);
3318

3319
  hw := FCubeSize.X * 0.5;
3320
  hh := FCubeSize.Y * 0.5;
3321
  hd := FCubeSize.Z * 0.5;
3322

3323
  if cpFront in FParts then
3324
  begin
3325
    connectivity.AddQuad(AffineVectorMake(hw, hh, hd),
3326
      AffineVectorMake(-hw, hh, hd), AffineVectorMake(-hw, -hh, hd),
3327
      AffineVectorMake(hw, -hh, hd));
3328
  end;
3329
  if cpBack in FParts then
3330
  begin
3331
    connectivity.AddQuad(AffineVectorMake(hw, hh, -hd),
3332
      AffineVectorMake(hw, -hh, -hd), AffineVectorMake(-hw, -hh, -hd),
3333
      AffineVectorMake(-hw, hh, -hd));
3334
  end;
3335
  if cpLeft in FParts then
3336
  begin
3337
    connectivity.AddQuad(AffineVectorMake(-hw, hh, hd),
3338
      AffineVectorMake(-hw, hh, -hd), AffineVectorMake(-hw, -hh, -hd),
3339
      AffineVectorMake(-hw, -hh, hd));
3340
  end;
3341
  if cpRight in FParts then
3342
  begin
3343
    connectivity.AddQuad(AffineVectorMake(hw, hh, hd),
3344
      AffineVectorMake(hw, -hh, hd), AffineVectorMake(hw, -hh, -hd),
3345
      AffineVectorMake(hw, hh, -hd));
3346
  end;
3347
  if cpTop in FParts then
3348
  begin
3349
    connectivity.AddQuad(AffineVectorMake(-hw, hh, -hd),
3350
      AffineVectorMake(-hw, hh, hd), AffineVectorMake(hw, hh, hd),
3351
      AffineVectorMake(hw, hh, -hd));
3352
  end;
3353
  if cpBottom in FParts then
3354
  begin
3355
    connectivity.AddQuad(AffineVectorMake(-hw, -hh, -hd),
3356
      AffineVectorMake(hw, -hh, -hd), AffineVectorMake(hw, -hh, hd),
3357
      AffineVectorMake(-hw, -hh, hd));
3358
  end;
3359

3360
  sil := nil;
3361
  connectivity.CreateSilhouette(silhouetteParameters, sil, False);
3362

3363
  Result := sil;
3364

3365
  connectivity.Free;
3366
end;
3367

3368
// GetCubeWHD
3369
//
3370
function TGLCube.GetCubeWHD(const Index: Integer): TGLFloat;
3371
begin
3372
  Result := FCubeSize.V[index];
3373
end;
3374

3375

3376
// SetCubeWHD
3377
//
3378
procedure TGLCube.SetCubeWHD(Index: Integer; AValue: TGLFloat);
3379
begin
3380
  if AValue <> FCubeSize.V[index] then
3381
  begin
3382
    FCubeSize.V[index] := AValue;
3383
    StructureChanged;
3384
  end;
3385
end;
3386

3387

3388
// SetParts
3389
//
3390
procedure TGLCube.SetParts(aValue: TCubeParts);
3391
begin
3392
  if aValue <> FParts then
3393
  begin
3394
    FParts := aValue;
3395
    StructureChanged;
3396
  end;
3397
end;
3398

3399
// SetNormalDirection
3400
//
3401

3402
procedure TGLCube.SetNormalDirection(aValue: TNormalDirection);
3403
begin
3404
  if aValue <> FNormalDirection then
3405
  begin
3406
    FNormalDirection := aValue;
3407
    StructureChanged;
3408
  end;
3409
end;
3410

3411
 
3412
//
3413

3414
procedure TGLCube.Assign(Source: TPersistent);
3415
begin
3416
  if Assigned(Source) and (Source is TGLCube) then
3417
  begin
3418
    FCubeSize := TGLCube(Source).FCubeSize;
3419
    FParts := TGLCube(Source).FParts;
3420
    FNormalDirection := TGLCube(Source).FNormalDirection;
3421
  end;
3422
  inherited Assign(Source);
3423
end;
3424

3425
// AxisAlignedDimensions
3426
//
3427

3428
function TGLCube.AxisAlignedDimensionsUnscaled: TVector;
3429
begin
3430
  Result.X := FCubeSize.X * 0.5;
3431
  Result.Y := FCubeSize.Y * 0.5;
3432
  Result.Z := FCubeSize.Z * 0.5;
3433
  Result.W := 0;
3434
end;
3435

3436
// RayCastIntersect
3437
//
3438

3439
function TGLCube.RayCastIntersect(const rayStart, rayVector: TVector;
3440
  intersectPoint: PVector = nil; intersectNormal: PVector = nil): Boolean;
3441
var
3442
  p: array [0 .. 5] of TVector;
3443
  rv: TVector;
3444
  rs, r: TVector;
3445
  i: Integer;
3446
  t, e: Single;
3447
  eSize: TAffineVector;
3448
begin
3449
  rs := AbsoluteToLocal(rayStart);
3450
  SetVector(rv, VectorNormalize(AbsoluteToLocal(rayVector)));
3451
  e := 0.5 + 0.0001; // Small value for floating point imprecisions
3452
  eSize.X := FCubeSize.X * e;
3453
  eSize.Y := FCubeSize.Y * e;
3454
  eSize.Z := FCubeSize.Z * e;
3455
  p[0] := XHmgVector;
3456
  p[1] := YHmgVector;
3457
  p[2] := ZHmgVector;
3458
  SetVector(p[3], -1, 0, 0);
3459
  SetVector(p[4], 0, -1, 0);
3460
  SetVector(p[5], 0, 0, -1);
3461
  for i := 0 to 5 do
3462
  begin
3463
    if VectorDotProduct(p[i], rv) > 0 then
3464
    begin
3465
      t := -(p[i].X * rs.X + p[i].Y * rs.Y +
3466
             p[i].Z * rs.Z + 0.5 *
3467
        FCubeSize.V[i mod 3]) / (p[i].X * rv.X +
3468
                                 p[i].Y * rv.Y +
3469
                                 p[i].Z * rv.Z);
3470
      MakePoint(r, rs.V[0] + t * rv.X, rs.Y +
3471
                             t * rv.Y, rs.Z +
3472
                             t * rv.Z);
3473
      if (Abs(r.X) <= eSize.X) and
3474
         (Abs(r.Y) <= eSize.Y) and
3475
         (Abs(r.Z) <= eSize.Z) and
3476
        (VectorDotProduct(VectorSubtract(r, rs), rv) > 0) then
3477
      begin
3478
        if Assigned(intersectPoint) then
3479
          MakePoint(intersectPoint^, LocalToAbsolute(r));
3480
        if Assigned(intersectNormal) then
3481
          MakeVector(intersectNormal^, LocalToAbsolute(VectorNegate(p[i])));
3482
        Result := True;
3483
        Exit;
3484
      end;
3485
    end;
3486
  end;
3487
  Result := False;
3488
end;
3489

3490
// DefineProperties
3491
//
3492

3493
procedure TGLCube.DefineProperties(Filer: TFiler);
3494
begin
3495
  inherited;
3496
  Filer.DefineBinaryProperty('CubeSize', ReadData, WriteData,
3497
    (FCubeSize.V[0] <> 1) or (FCubeSize.V[1] <> 1) or (FCubeSize.V[2] <> 1));
3498
end;
3499

3500
// ReadData
3501
//
3502

3503
procedure TGLCube.ReadData(Stream: TStream);
3504
begin
3505
  with Stream do
3506
  begin
3507
    Read(FCubeSize, SizeOf(TAffineVector));
3508
  end;
3509
end;
3510

3511
// WriteData
3512
//
3513

3514
procedure TGLCube.WriteData(Stream: TStream);
3515
begin
3516
  with Stream do
3517
  begin
3518
    Write(FCubeSize, SizeOf(TAffineVector));
3519
  end;
3520
end;
3521

3522
// ------------------
3523
// ------------------ TGLQuadricObject ------------------
3524
// ------------------
3525

3526
// Create
3527
//
3528

3529
constructor TGLQuadricObject.Create(AOwner: TComponent);
3530
begin
3531
  inherited;
3532
  FNormals := nsSmooth;
3533
  FNormalDirection := ndOutside;
3534
end;
3535

3536
// SetNormals
3537
//
3538

3539
procedure TGLQuadricObject.SetNormals(aValue: TNormalSmoothing);
3540
begin
3541
  if aValue <> FNormals then
3542
  begin
3543
    FNormals := aValue;
3544
    StructureChanged;
3545
  end;
3546
end;
3547

3548
// SetNormalDirection
3549
//
3550

3551
procedure TGLQuadricObject.SetNormalDirection(aValue: TNormalDirection);
3552
begin
3553
  if aValue <> FNormalDirection then
3554
  begin
3555
    FNormalDirection := aValue;
3556
    StructureChanged;
3557
  end;
3558
end;
3559

3560
// SetupQuadricParams
3561
//
3562

3563
procedure TGLQuadricObject.SetupQuadricParams(quadric: PGLUquadricObj);
3564
const
3565
  cNormalSmoothinToEnum: array [nsFlat .. nsNone] of TGLEnum = (GLU_FLAT,
3566
    GLU_SMOOTH, GLU_NONE);
3567
begin
3568
  gluQuadricDrawStyle(quadric, GLU_FILL);
3569
  gluQuadricNormals(quadric, cNormalSmoothinToEnum[FNormals]);
3570
  SetNormalQuadricOrientation(quadric);
3571
  gluQuadricTexture(quadric, True);
3572
end;
3573

3574
// SetNormalQuadricOrientation
3575
//
3576

3577
procedure TGLQuadricObject.SetNormalQuadricOrientation(quadric: PGLUquadricObj);
3578
const
3579
  cNormalDirectionToEnum: array [ndInside .. ndOutside] of TGLEnum =
3580
    (GLU_INSIDE, GLU_OUTSIDE);
3581
begin
3582
  gluQuadricOrientation(quadric, cNormalDirectionToEnum[FNormalDirection]);
3583
end;
3584

3585
// SetInvertedQuadricOrientation
3586
//
3587

3588
procedure TGLQuadricObject.SetInvertedQuadricOrientation
3589
  (quadric: PGLUquadricObj);
3590
const
3591
  cNormalDirectionToEnum: array [ndInside .. ndOutside] of TGLEnum =
3592
    (GLU_OUTSIDE, GLU_INSIDE);
3593
begin
3594
  gluQuadricOrientation(quadric, cNormalDirectionToEnum[FNormalDirection]);
3595
end;
3596

3597
 
3598
//
3599

3600
procedure TGLQuadricObject.Assign(Source: TPersistent);
3601
begin
3602
  if Assigned(Source) and (Source is TGLQuadricObject) then
3603
  begin
3604
    FNormals := TGLQuadricObject(Source).FNormals;
3605
    FNormalDirection := TGLQuadricObject(Source).FNormalDirection;
3606
  end;
3607
  inherited Assign(Source);
3608
end;
3609

3610
// ------------------
3611
// ------------------ TGLSphere ------------------
3612
// ------------------
3613

3614
// Create
3615
//
3616

3617
constructor TGLSphere.Create(AOwner: TComponent);
3618
begin
3619
  inherited Create(AOwner);
3620
  FRadius := 0.5;
3621
  FSlices := 16;
3622
  FStacks := 16;
3623
  FTop := 90;
3624
  FBottom := -90;
3625
  FStart := 0;
3626
  FStop := 360;
3627
end;
3628

3629
// BuildList
3630
//
3631

3632
procedure TGLSphere.BuildList(var rci: TGLRenderContextInfo);
3633
var
3634
  v1, V2, N1: TAffineVector;
3635
  AngTop, AngBottom, AngStart, AngStop, StepV, StepH: Double;
3636
  SinP, CosP, SinP2, CosP2, SinT, CosT, Phi, Phi2, Theta: Double;
3637
  uTexCoord, uTexFactor, vTexFactor, vTexCoord0, vTexCoord1: Single;
3638
  i, j: Integer;
3639
  DoReverse: Boolean;
3640
begin
3641
  DoReverse := (FNormalDirection = ndInside);
3642
  rci.GLStates.PushAttrib([sttPolygon]);
3643
  if DoReverse then
3644
    rci.GLStates.InvertGLFrontFace;
3645

3646
  // common settings
3647
  AngTop := DegToRad(1.0 * FTop);
3648
  AngBottom := DegToRad(1.0 * FBottom);
3649
  AngStart := DegToRad(1.0 * FStart);
3650
  AngStop := DegToRad(1.0 * FStop);
3651
  StepH := (AngStop - AngStart) / FSlices;
3652
  StepV := (AngTop - AngBottom) / FStacks;
3653
  GL.PushMatrix;
3654
  GL.Scalef(Radius, Radius, Radius);
3655

3656
  // top cap
3657
  if (FTop < 90) and (FTopCap in [ctCenter, ctFlat]) then
3658
  begin
3659
    GL.Begin_(GL_TRIANGLE_FAN);
3660
    GLVectorGeometry.SinCos(AngTop, SinP, CosP);
3661
    xgl.TexCoord2f(0.5, 0.5);
3662
    if DoReverse then
3663
      GL.Normal3f(0, -1, 0)
3664
    else
3665
      GL.Normal3f(0, 1, 0);
3666
    if FTopCap = ctCenter then
3667
      GL.Vertex3f(0, 0, 0)
3668
    else
3669
    begin
3670
      GL.Vertex3f(0, SinP, 0);
3671
      N1 := YVector;
3672
      if DoReverse then
3673
        N1.V[1] := -N1.V[1];
3674
    end;
3675
    v1.V[1] := SinP;
3676
    Theta := AngStart;
3677
    for i := 0 to FSlices do
3678
    begin
3679
      GLVectorGeometry.SinCos(Theta, SinT, CosT);
3680
      v1.V[0] := CosP * SinT;
3681
      v1.V[2] := CosP * CosT;
3682
      if FTopCap = ctCenter then
3683
      begin
3684
        N1 := VectorPerpendicular(YVector, v1);
3685
        if DoReverse then
3686
          NegateVector(N1);
3687
      end;
3688
      xgl.TexCoord2f(SinT * 0.5 + 0.5, CosT * 0.5 + 0.5);
3689
      GL.Normal3fv(@N1);
3690
      GL.Vertex3fv(@v1);
3691
      Theta := Theta + StepH;
3692
    end;
3693
    GL.End_;
3694
  end;
3695

3696
  // main body
3697
  Phi := AngTop;
3698
  Phi2 := Phi - StepV;
3699
  uTexFactor := 1 / FSlices;
3700
  vTexFactor := 1 / FStacks;
3701

3702
  for j := 0 to FStacks - 1 do
3703
  begin
3704
    Theta := AngStart;
3705
    GLVectorGeometry.SinCos(Phi, SinP, CosP);
3706
    GLVectorGeometry.SinCos(Phi2, SinP2, CosP2);
3707
    v1.V[1] := SinP;
3708
    V2.V[1] := SinP2;
3709
    vTexCoord0 := 1 - j * vTexFactor;
3710
    vTexCoord1 := 1 - (j + 1) * vTexFactor;
3711

3712
    GL.Begin_(GL_TRIANGLE_STRIP);
3713
    for i := 0 to FSlices do
3714
    begin
3715

3716
      SinCos(Theta, SinT, CosT);
3717
      v1.V[0] := CosP * SinT;
3718
      V2.V[0] := CosP2 * SinT;
3719
      v1.V[2] := CosP * CosT;
3720
      V2.V[2] := CosP2 * CosT;
3721

3722
      uTexCoord := i * uTexFactor;
3723
      xgl.TexCoord2f(uTexCoord, vTexCoord0);
3724
      if DoReverse then
3725
      begin
3726
        N1 := VectorNegate(v1);
3727
        GL.Normal3fv(@N1);
3728
      end
3729
      else
3730
        GL.Normal3fv(@v1);
3731
      GL.Vertex3fv(@v1);
3732

3733
      xgl.TexCoord2f(uTexCoord, vTexCoord1);
3734
      if DoReverse then
3735
      begin
3736
        N1 := VectorNegate(V2);
3737
        GL.Normal3fv(@N1);
3738
      end
3739
      else
3740
        GL.Normal3fv(@V2);
3741
      GL.Vertex3fv(@V2);
3742

3743
      Theta := Theta + StepH;
3744
    end;
3745
    GL.End_;
3746
    Phi := Phi2;
3747
    Phi2 := Phi2 - StepV;
3748
  end;
3749

3750
  // bottom cap
3751
  if (FBottom > -90) and (FBottomCap in [ctCenter, ctFlat]) then
3752
  begin
3753
    GL.Begin_(GL_TRIANGLE_FAN);
3754
    SinCos(AngBottom, SinP, CosP);
3755
    xgl.TexCoord2f(0.5, 0.5);
3756
    if DoReverse then
3757
      GL.Normal3f(0, 1, 0)
3758
    else
3759
      GL.Normal3f(0, -1, 0);
3760
    if FBottomCap = ctCenter then
3761
      GL.Vertex3f(0, 0, 0)
3762
    else
3763
    begin
3764
      GL.Vertex3f(0, SinP, 0);
3765
      if DoReverse then
3766
        MakeVector(N1, 0, -1, 0)
3767
      else
3768
      begin
3769
        N1 := YVector;
3770
        NegateVector(N1); 
3771
      end;
3772
    end;
3773
    v1.V[1] := SinP;
3774
    Theta := AngStop;
3775
    for i := 0 to FSlices do
3776
    begin
3777
      SinCos(Theta, SinT, CosT);
3778
      v1.V[0] := CosP * SinT;
3779
      v1.V[2] := CosP * CosT;
3780
      if FBottomCap = ctCenter then
3781
      begin
3782
        N1 := VectorPerpendicular(AffineVectorMake(0, -1, 0), v1);
3783
        if DoReverse then
3784
          NegateVector(N1);
3785
      end;
3786
      xgl.TexCoord2f(SinT * 0.5 + 0.5, CosT * 0.5 + 0.5);
3787
      GL.Normal3fv(@N1);
3788
      GL.Vertex3fv(@v1);
3789
      Theta := Theta - StepH;
3790
    end;
3791
    GL.End_;
3792
  end;
3793
  if DoReverse then
3794
    rci.GLStates.InvertGLFrontFace;
3795
  GL.PopMatrix;
3796
  rci.GLStates.PopAttrib;
3797
end;
3798

3799
// RayCastIntersect
3800
//
3801

3802
function TGLSphere.RayCastIntersect(const rayStart, rayVector: TVector;
3803
  intersectPoint: PVector = nil; intersectNormal: PVector = nil): Boolean;
3804
var
3805
  i1, i2: TVector;
3806
  localStart, localVector: TVector;
3807
begin
3808
  // compute coefficients of quartic polynomial
3809
  SetVector(localStart, AbsoluteToLocal(rayStart));
3810
  SetVector(localVector, AbsoluteToLocal(rayVector));
3811
  NormalizeVector(localVector);
3812
  if RayCastSphereIntersect(localStart, localVector, NullHmgVector, Radius, i1,
3813
    i2) > 0 then
3814
  begin
3815
    Result := True;
3816
    if Assigned(intersectPoint) then
3817
      SetVector(intersectPoint^, LocalToAbsolute(i1));
3818
    if Assigned(intersectNormal) then
3819
    begin
3820
      i1.V[3] := 0; // vector transform
3821
      SetVector(intersectNormal^, LocalToAbsolute(i1));
3822
    end;
3823
  end
3824
  else
3825
    Result := False;
3826
end;
3827

3828
// GenerateSilhouette
3829
//
3830

3831
function TGLSphere.GenerateSilhouette(const silhouetteParameters
3832
  : TGLSilhouetteParameters): TGLSilhouette;
3833
var
3834
  i, j: Integer;
3835
  s, C, angleFactor: Single;
3836
  sVec, tVec: TAffineVector;
3837
  Segments: Integer;
3838
begin
3839
  Segments := MaxInteger(FStacks, FSlices);
3840

3841
  // determine a local orthonormal matrix, viewer-oriented
3842
  sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, XVector);
3843
  if VectorLength(sVec) < 1E-3 then
3844
    sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, YVector);
3845
  tVec := VectorCrossProduct(silhouetteParameters.SeenFrom, sVec);
3846
  NormalizeVector(sVec);
3847
  NormalizeVector(tVec);
3848
  // generate the silhouette (outline and capping)
3849
  Result := TGLSilhouette.Create;
3850
  angleFactor := (2 * PI) / Segments;
3851
  for i := 0 to Segments - 1 do
3852
  begin
3853
    SinCos(i * angleFactor, FRadius, s, C);
3854
    Result.vertices.AddPoint(VectorCombine(sVec, tVec, s, C));
3855
    j := (i + 1) mod Segments;
3856
    Result.Indices.Add(i, j);
3857
    if silhouetteParameters.CappingRequired then
3858
      Result.CapIndices.Add(Segments, i, j)
3859
  end;
3860
  if silhouetteParameters.CappingRequired then
3861
    Result.vertices.Add(NullHmgPoint);
3862
end;
3863

3864
// SetBottom
3865
//
3866

3867
procedure TGLSphere.SetBottom(aValue: TAngleLimit1);
3868
begin
3869
  if FBottom <> aValue then
3870
  begin
3871
    FBottom := aValue;
3872
    StructureChanged;
3873
  end;
3874
end;
3875

3876
// SetBottomCap
3877
//
3878

3879
procedure TGLSphere.SetBottomCap(aValue: TCapType);
3880
begin
3881
  if FBottomCap <> aValue then
3882
  begin
3883
    FBottomCap := aValue;
3884
    StructureChanged;
3885
  end;
3886
end;
3887

3888
// SetRadius
3889
//
3890

3891
procedure TGLSphere.SetRadius(const aValue: TGLFloat);
3892
begin
3893
  if aValue <> FRadius then
3894
  begin
3895
    FRadius := aValue;
3896
    StructureChanged;
3897
  end;
3898
end;
3899

3900
// SetSlices
3901
//
3902

3903
procedure TGLSphere.SetSlices(aValue: Integer);
3904
begin
3905
  if aValue <> FSlices then
3906
  begin
3907
    if aValue <= 0 then
3908
      FSlices := 1
3909
    else
3910
      FSlices := aValue;
3911
    StructureChanged;
3912
  end;
3913
end;
3914

3915
// SetStacks
3916
//
3917

3918
procedure TGLSphere.SetStacks(aValue: TGLInt);
3919
begin
3920
  if aValue <> FStacks then
3921
  begin
3922
    if aValue <= 0 then
3923
      FStacks := 1
3924
    else
3925
      FStacks := aValue;
3926
    StructureChanged;
3927
  end;
3928
end;
3929

3930
// SetStart
3931
//
3932

3933
procedure TGLSphere.SetStart(aValue: TAngleLimit2);
3934
begin
3935
  if FStart <> aValue then
3936
  begin
3937
    Assert(aValue <= FStop);
3938
    FStart := aValue;
3939
    StructureChanged;
3940
  end;
3941
end;
3942

3943
// SetStop
3944
//
3945

3946
procedure TGLSphere.SetStop(aValue: TAngleLimit2);
3947
begin
3948
  if FStop <> aValue then
3949
  begin
3950
    Assert(aValue >= FStart);
3951
    FStop := aValue;
3952
    StructureChanged;
3953
  end;
3954
end;
3955

3956
// SetTop
3957
//
3958

3959
procedure TGLSphere.SetTop(aValue: TAngleLimit1);
3960
begin
3961
  if FTop <> aValue then
3962
  begin
3963
    FTop := aValue;
3964
    StructureChanged;
3965
  end;
3966
end;
3967

3968
// SetTopCap
3969
//
3970

3971
procedure TGLSphere.SetTopCap(aValue: TCapType);
3972
begin
3973
  if FTopCap <> aValue then
3974
  begin
3975
    FTopCap := aValue;
3976
    StructureChanged;
3977
  end;
3978
end;
3979

3980
 
3981
//
3982

3983
procedure TGLSphere.Assign(Source: TPersistent);
3984
begin
3985
  if Assigned(Source) and (Source is TGLSphere) then
3986
  begin
3987
    FRadius := TGLSphere(Source).FRadius;
3988
    FSlices := TGLSphere(Source).FSlices;
3989
    FStacks := TGLSphere(Source).FStacks;
3990
    FBottom := TGLSphere(Source).FBottom;
3991
    FTop := TGLSphere(Source).FTop;
3992
    FStart := TGLSphere(Source).FStart;
3993
    FStop := TGLSphere(Source).FStop;
3994
  end;
3995
  inherited Assign(Source);
3996
end;
3997

3998
// AxisAlignedDimensions
3999
//
4000

4001
function TGLSphere.AxisAlignedDimensionsUnscaled: TVector;
4002
begin
4003
  Result.V[0] := Abs(FRadius);
4004
  Result.V[1] := Result.V[0];
4005
  Result.V[2] := Result.V[0];
4006
  Result.V[3] := 0;
4007
end;
4008

4009
// ------------------
4010
// ------------------ TGLPolygonBase ------------------
4011
// ------------------
4012

4013
// Create
4014
//
4015

4016
constructor TGLPolygonBase.Create(AOwner: TComponent);
4017
begin
4018
  inherited Create(AOwner);
4019
  CreateNodes;
4020
  FDivision := 10;
4021
  FSplineMode := lsmLines;
4022
end;
4023

4024
// CreateNodes
4025
//
4026

4027
procedure TGLPolygonBase.CreateNodes;
4028
begin
4029
  FNodes := TGLNodes.Create(Self);
4030
end;
4031

4032
// Destroy
4033
//
4034

4035
destructor TGLPolygonBase.Destroy;
4036
begin
4037
  FNodes.Free;
4038
  inherited Destroy;
4039
end;
4040

4041
 
4042
//
4043

4044
procedure TGLPolygonBase.Assign(Source: TPersistent);
4045
begin
4046
  if Source is TGLPolygonBase then
4047
  begin
4048
    SetNodes(TGLPolygonBase(Source).FNodes);
4049
    FDivision := TGLPolygonBase(Source).FDivision;
4050
    FSplineMode := TGLPolygonBase(Source).FSplineMode;
4051
  end;
4052
  inherited Assign(Source);
4053
end;
4054

4055
// NotifyChange
4056
//
4057

4058
procedure TGLPolygonBase.NotifyChange(Sender: TObject);
4059
begin
4060
  if Sender = Nodes then
4061
    StructureChanged;
4062
  inherited;
4063
end;
4064

4065
// SetDivision
4066
//
4067

4068
procedure TGLPolygonBase.SetDivision(const Value: Integer);
4069
begin
4070
  if Value <> FDivision then
4071
  begin
4072
    if Value < 1 then
4073
      FDivision := 1
4074
    else
4075
      FDivision := Value;
4076
    StructureChanged;
4077
  end;
4078
end;
4079

4080
// SetNodes
4081
//
4082

4083
procedure TGLPolygonBase.SetNodes(const aNodes: TGLNodes);
4084
begin
4085
  FNodes.Assign(aNodes);
4086
  StructureChanged;
4087
end;
4088

4089
// SetSplineMode
4090
//
4091

4092
procedure TGLPolygonBase.SetSplineMode(const val: TGLLineSplineMode);
4093
begin
4094
  if FSplineMode <> val then
4095
  begin
4096
    FSplineMode := val;
4097
    StructureChanged;
4098
  end;
4099
end;
4100

4101
// AddNode (coords)
4102
//
4103

4104
procedure TGLPolygonBase.AddNode(const coords: TGLCoordinates);
4105
var
4106
  n: TGLNode;
4107
begin
4108
  n := Nodes.Add;
4109
  if Assigned(coords) then
4110
    n.AsVector := coords.AsVector;
4111
  StructureChanged;
4112
end;
4113

4114
// AddNode (xyz)
4115
//
4116

4117
procedure TGLPolygonBase.AddNode(const X, Y, Z: TGLFloat);
4118
var
4119
  n: TGLNode;
4120
begin
4121
  n := Nodes.Add;
4122
  n.AsVector := VectorMake(X, Y, Z, 1);
4123
  StructureChanged;
4124
end;
4125

4126
// AddNode (vector)
4127
//
4128

4129
procedure TGLPolygonBase.AddNode(const Value: TVector);
4130
var
4131
  n: TGLNode;
4132
begin
4133
  n := Nodes.Add;
4134
  n.AsVector := Value;
4135
  StructureChanged;
4136
end;
4137

4138
// AddNode (affine vector)
4139
//
4140

4141
procedure TGLPolygonBase.AddNode(const Value: TAffineVector);
4142
var
4143
  n: TGLNode;
4144
begin
4145
  n := Nodes.Add;
4146
  n.AsVector := VectorMake(Value);
4147
  StructureChanged;
4148
end;
4149

4150
// ------------------
4151
// ------------------ TGLSuperellipsoid ------------------
4152
// ------------------
4153

4154
// Create
4155
//
4156

4157
constructor TGLSuperellipsoid.Create(AOwner: TComponent);
4158
begin
4159
  inherited Create(AOwner);
4160
  FRadius := 0.5;
4161
  FxyCurve := 1.0;
4162
  FzCurve := 1.0;
4163
  FSlices := 16;
4164
  FStacks := 16;
4165
  FTop := 90;
4166
  FBottom := -90;
4167
  FStart := 0;
4168
  FStop := 360;
4169
end;
4170

4171
// BuildList
4172
//
4173

4174
procedure TGLSuperellipsoid.BuildList(var rci: TGLRenderContextInfo);
4175
var
4176
  CosPc1, SinPc1, CosTc2, SinTc2: Double;
4177

4178
  tc1, tc2: integer;
4179
  v1, v2, vs, N1: TAffineVector;
4180
  AngTop, AngBottom, AngStart, AngStop, StepV, StepH: Double;
4181
  SinP, CosP, SinP2, CosP2, SinT, CosT, Phi, Phi2, Theta: Double;
4182
  uTexCoord, uTexFactor, vTexFactor, vTexCoord0, vTexCoord1: Double;
4183
  i, j: Integer;
4184
  DoReverse: Boolean;
4185

4186
begin
4187
  DoReverse := (FNormalDirection = ndInside);
4188
  if DoReverse then
4189
    rci.GLStates.InvertGLFrontFace;
4190

4191
  // common settings
4192
  AngTop := DegToRad(1.0 * FTop);
4193
  AngBottom := DegToRad(1.0 * FBottom);
4194
  AngStart := DegToRad(1.0 * FStart);
4195
  AngStop := DegToRad(1.0 * FStop);
4196
  StepH := (AngStop - AngStart) / FSlices;
4197
  StepV := (AngTop - AngBottom) / FStacks;
4198

4199
  { Even integer used with the Power function, only produce positive points }
4200
  tc1 := trunc(xyCurve);
4201
  tc2 := trunc(zCurve);
4202
  if tc1 mod 2 = 0 then
4203
    xyCurve := xyCurve + 1e-6;
4204
  if tc2 mod 2 = 0 then
4205
    zCurve := zCurve - 1e-6;
4206

4207
  // top cap
4208
  if (FTop < 90) and (FTopCap in [ctCenter, ctFlat]) then
4209
  begin
4210
    GL.Begin_(GL_TRIANGLE_FAN);
4211
    SinCos(AngTop, SinP, CosP);
4212
    xgl.TexCoord2f(0.5, 0.5);
4213
    if DoReverse then
4214
      GL.Normal3f(0, -1, 0)
4215
    else
4216
      GL.Normal3f(0, 1, 0);
4217

4218
    if FTopCap = ctCenter then
4219
      GL.Vertex3f(0, 0, 0)
4220
    else
4221
    begin { FTopCap = ctFlat }
4222
      if (Sign(SinP) = 1) or (tc1 = xyCurve) then
4223
        SinPc1 := Power(SinP, xyCurve)
4224
      else
4225
        SinPc1 := -Power(-SinP, xyCurve);
4226
      GL.Vertex3f(0, SinPc1*Radius, 0);
4227

4228
      N1 := YVector;
4229
      if DoReverse then
4230
        N1.Y := -N1.Y;
4231
    end; { FTopCap = ctFlat }
4232

4233
    //  v1.Y := SinP;
4234
    if (Sign(SinP) = 1) or (tc1 = xyCurve) then
4235
      SinPc1 := Power(SinP, xyCurve)
4236
    else
4237
      SinPc1 := -Power(-SinP, xyCurve);
4238
    v1.Y := SinPc1;
4239

4240
    Theta := AngStart;
4241

4242
    for i := 0 to FSlices do
4243
    begin
4244
      SinCos(Theta, SinT, CosT);
4245
      //    v1.X := CosP * SinT;
4246
      if (Sign(CosP) = 1) or (tc1 = xyCurve) then
4247
        CosPc1 := Power(CosP, xyCurve)
4248
      else
4249
        CosPc1 := -Power(-CosP, xyCurve);
4250

4251
      if (Sign(SinT) = 1) or (tc2 = zCurve) then
4252
        SinTc2 := Power(SinT, zCurve)
4253
      else
4254
        SinTc2 := -Power(-SinT, zCurve);
4255
      v1.X := CosPc1 * SinTc2;
4256

4257
      //    v1.Z := CosP * CosT;
4258
      if (Sign(CosT) = 1) or (tc2 = zCurve) then
4259
        CosTc2 := Power(CosT, zCurve)
4260
      else
4261
        CosTc2 := -Power(-CosT, zCurve);
4262
      v1.Z := CosPc1 * CosTc2;
4263

4264
      if FTopCap = ctCenter then
4265
      begin
4266
        N1 := VectorPerpendicular(YVector, v1);
4267
        if DoReverse then
4268
          NegateVector(N1);
4269
      end;
4270
      //    xgl.TexCoord2f(SinT * 0.5 + 0.5, CosT * 0.5 + 0.5);
4271
      xgl.TexCoord2f(SinTc2 * 0.5 + 0.5, CosTc2 * 0.5 + 0.5);
4272
      GL.Normal3fv(@N1);
4273
      vs := v1;
4274
      ScaleVector(vs, Radius);
4275
      GL.Vertex3fv(@vs);
4276
      Theta := Theta + StepH;
4277
    end;
4278
    GL.End_;
4279
  end;
4280

4281
  // main body
4282
  Phi := AngTop;
4283
  Phi2 := Phi - StepV;
4284
  uTexFactor := 1 / FSlices;
4285
  vTexFactor := 1 / FStacks;
4286

4287
  for j := 0 to FStacks - 1 do
4288
  begin
4289
    Theta := AngStart;
4290
    SinCos(Phi, SinP, CosP);
4291
    SinCos(Phi2, SinP2, CosP2);
4292

4293
    if (Sign(SinP) = 1) or (tc1 = xyCurve) then
4294
      SinPc1 := Power(SinP, xyCurve)
4295
    else
4296
      SinPc1 := -Power(-SinP, xyCurve);
4297
    v1.Y := SinPc1;
4298

4299
    if (Sign(SinP2) = 1) or (tc1 = xyCurve) then
4300
      SinPc1 := Power(SinP2, xyCurve)
4301
    else
4302
      SinPc1 := -Power(-SinP2, xyCurve);
4303
    v2.Y := SinPc1;
4304

4305
    vTexCoord0 := 1 - j * vTexFactor;
4306
    vTexCoord1 := 1 - (j + 1) * vTexFactor;
4307

4308
    GL.Begin_(GL_TRIANGLE_STRIP);
4309
    for i := 0 to FSlices do
4310
    begin
4311
      SinCos(Theta, SinT, CosT);
4312

4313
      if (Sign(CosP) = 1) or (tc1 = xyCurve) then
4314
        CosPc1 := Power(CosP, xyCurve)
4315
      else
4316
        CosPc1 := -Power(-CosP, xyCurve);
4317

4318
      if (Sign(SinT) = 1) or (tc2 = zCurve) then
4319
        SinTc2 := Power(SinT, zCurve)
4320
      else
4321
        SinTc2 := -Power(-SinT, zCurve);
4322
      v1.X := CosPc1 * SinTc2;
4323

4324
      if (Sign(CosP2) = 1) or (tc1 = xyCurve) then
4325
        CosPc1 := Power(CosP2, xyCurve)
4326
      else
4327
        CosPc1 := -Power(-CosP2, xyCurve);
4328
      V2.X := CosPc1 * SinTc2;
4329

4330
      if (Sign(CosP) = 1) or (tc1 = xyCurve) then
4331
        CosPc1 := Power(CosP, xyCurve)
4332
      else
4333
        CosPc1 := -Power(-CosP, xyCurve);
4334

4335
      if (Sign(CosT) = 1) or (tc2 = zCurve) then
4336
        CosTc2 := Power(CosT, zCurve)
4337
      else
4338
        CosTc2 := -Power(-CosT, zCurve);
4339
      v1.Z := CosPc1 * CosTc2;
4340

4341
      if (Sign(CosP2) = 1) or (tc1 = xyCurve) then
4342
        CosPc1 := Power(CosP2, xyCurve)
4343
      else
4344
        CosPc1 := -Power(-CosP2, xyCurve);
4345
      V2.Z := CosPc1 * CosTc2;
4346

4347
      uTexCoord := i * uTexFactor;
4348
      xgl.TexCoord2f(uTexCoord, vTexCoord0);
4349
      if DoReverse then
4350
      begin
4351
        N1 := VectorNegate(v1);
4352
        GL.Normal3fv(@N1);
4353
      end
4354
      else
4355
        GL.Normal3fv(@v1);
4356
      vs := v1;
4357
      ScaleVector(vs, Radius);
4358
      GL.Vertex3fv(@vs);
4359

4360
      xgl.TexCoord2f(uTexCoord, vTexCoord1);
4361
      if DoReverse then
4362
      begin
4363
        N1 := VectorNegate(V2);
4364
        GL.Normal3fv(@N1);
4365
      end
4366
      else
4367
        GL.Normal3fv(@v2);
4368
      vs := v2;
4369
      ScaleVector(vs, Radius);
4370
      GL.Vertex3fv(@vs);
4371

4372
      Theta := Theta + StepH;
4373
    end;
4374
    GL.End_;
4375
    Phi := Phi2;
4376
    Phi2 := Phi2 - StepV;
4377
  end;
4378

4379
  // bottom cap
4380
  if (FBottom > -90) and (FBottomCap in [ctCenter, ctFlat]) then
4381
  begin
4382
    GL.Begin_(GL_TRIANGLE_FAN);
4383
    SinCos(AngBottom, SinP, CosP);
4384
    xgl.TexCoord2f(0.5, 0.5);
4385
    if DoReverse then
4386
      GL.Normal3f(0, 1, 0)
4387
    else
4388
      GL.Normal3f(0, -1, 0);
4389
    if FBottomCap = ctCenter then
4390
      GL.Vertex3f(0, 0, 0)
4391
    else
4392
    begin { FTopCap = ctFlat }
4393
      if (Sign(SinP) = 1) or (tc1 = xyCurve) then
4394
        SinPc1 := Power(SinP, xyCurve)
4395
      else
4396
        SinPc1 := -Power(-SinP, xyCurve);
4397
      GL.Vertex3f(0, SinPc1*Radius, 0);
4398

4399
      if DoReverse then
4400
        MakeVector(N1, 0, -1, 0)
4401
      else
4402
        N1 := YVector;
4403
    end;
4404
    //  v1.Y := SinP;
4405
    if (Sign(SinP) = 1) or (tc1 = xyCurve) then
4406
      SinPc1 := Power(SinP, xyCurve)
4407
    else
4408
      SinPc1 := -Power(-SinP, xyCurve);
4409
    v1.Y := SinPc1;
4410

4411
    Theta := AngStop;
4412
    for i := 0 to FSlices do
4413
    begin
4414
      SinCos(Theta, SinT, CosT);
4415
      //    v1.X := CosP * SinT;
4416
      if (Sign(CosP) = 1) or (tc1 = xyCurve) then
4417
        CosPc1 := Power(CosP, xyCurve)
4418
      else
4419
        CosPc1 := -Power(-CosP, xyCurve);
4420

4421
      if (Sign(SinT) = 1) or (tc2 = zCurve) then
4422
        SinTc2 := Power(SinT, zCurve)
4423
      else
4424
        SinTc2 := -Power(-SinT, zCurve);
4425
      v1.X := CosPc1 * SinTc2;
4426

4427
      //    v1.Z := CosP * CosT;
4428
      if (Sign(CosT) = 1) or (tc2 = zCurve) then
4429
        CosTc2 := Power(CosT, zCurve)
4430
      else
4431
        CosTc2 := -Power(-CosT, zCurve);
4432
      v1.Z := CosPc1 * CosTc2;
4433

4434
      if FBottomCap = ctCenter then
4435
      begin
4436
        N1 := VectorPerpendicular(AffineVectorMake(0, -1, 0), v1);
4437
        if DoReverse then
4438
          NegateVector(N1);
4439
        GL.Normal3fv(@N1);
4440
      end;
4441
      //    xgl.TexCoord2f(SinT * 0.5 + 0.5, CosT * 0.5 + 0.5);
4442
      xgl.TexCoord2f(SinTc2 * 0.5 + 0.5, CosTc2 * 0.5 + 0.5);
4443
      vs := v1;
4444
      ScaleVector(vs, Radius);
4445
      GL.Vertex3fv(@vs);
4446
      Theta := Theta - StepH;
4447
    end;
4448
    GL.End_;
4449
  end;
4450
  if DoReverse then
4451
    rci.GLStates.InvertGLFrontFace;
4452
end;
4453

4454
// RayCastIntersect
4455
// This will probably not work, karamba
4456
// RayCastSphereIntersect -> RayCastSuperellipsoidIntersect ??????
4457

4458
function TGLSuperellipsoid.RayCastIntersect(const rayStart, rayVector: TVector;
4459
  intersectPoint: PVector = nil; intersectNormal: PVector = nil): Boolean;
4460
var
4461
  i1, i2: TVector;
4462
  localStart, localVector: TVector;
4463
begin
4464
  // compute coefficients of quartic polynomial
4465
  SetVector(localStart, AbsoluteToLocal(rayStart));
4466
  SetVector(localVector, AbsoluteToLocal(rayVector));
4467
  NormalizeVector(localVector);
4468
  if RayCastSphereIntersect(localStart, localVector, NullHmgVector, Radius, i1,
4469
    i2) > 0 then
4470
  begin
4471
    Result := True;
4472
    if Assigned(intersectPoint) then
4473
      SetVector(intersectPoint^, LocalToAbsolute(i1));
4474
    if Assigned(intersectNormal) then
4475
    begin
4476
      i1.W := 0; // vector transform
4477
      SetVector(intersectNormal^, LocalToAbsolute(i1));
4478
    end;
4479
  end
4480
  else
4481
    Result := False;
4482
end;
4483

4484
// GenerateSilhouette
4485
// This will probably not work;
4486

4487
function TGLSuperellipsoid.GenerateSilhouette(const silhouetteParameters
4488
  : TGLSilhouetteParameters): TGLSilhouette;
4489
var
4490
  i, j: Integer;
4491
  s, C, angleFactor: Single;
4492
  sVec, tVec: TAffineVector;
4493
  Segments: Integer;
4494
begin
4495
  Segments := MaxInteger(FStacks, FSlices);
4496

4497
  // determine a local orthonormal matrix, viewer-oriented
4498
  sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, XVector);
4499
  if VectorLength(sVec) < 1E-3 then
4500
    sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, YVector);
4501
  tVec := VectorCrossProduct(silhouetteParameters.SeenFrom, sVec);
4502
  NormalizeVector(sVec);
4503
  NormalizeVector(tVec);
4504
  // generate the silhouette (outline and capping)
4505
  Result := TGLSilhouette.Create;
4506
  angleFactor := (2 * PI) / Segments;
4507
  for i := 0 to Segments - 1 do
4508
  begin
4509
    SinCos(i * angleFactor, FRadius, s, C);
4510
    Result.vertices.AddPoint(VectorCombine(sVec, tVec, s, C));
4511
    j := (i + 1) mod Segments;
4512
    Result.Indices.Add(i, j);
4513
    if silhouetteParameters.CappingRequired then
4514
      Result.CapIndices.Add(Segments, i, j)
4515
  end;
4516
  if silhouetteParameters.CappingRequired then
4517
    Result.vertices.Add(NullHmgPoint);
4518
end;
4519

4520
// SetBottom
4521
//
4522

4523
procedure TGLSuperellipsoid.SetBottom(aValue: TAngleLimit1);
4524
begin
4525
  if FBottom <> aValue then
4526
  begin
4527
    FBottom := aValue;
4528
    StructureChanged;
4529
  end;
4530
end;
4531

4532
// SetBottomCap
4533
//
4534

4535
procedure TGLSuperellipsoid.SetBottomCap(aValue: TCapType);
4536
begin
4537
  if FBottomCap <> aValue then
4538
  begin
4539
    FBottomCap := aValue;
4540
    StructureChanged;
4541
  end;
4542
end;
4543

4544
// SetRadius
4545
//
4546

4547
procedure TGLSuperellipsoid.SetRadius(const aValue: TGLFloat);
4548
begin
4549
  if aValue <> FRadius then
4550
  begin
4551
    FRadius := aValue;
4552
    StructureChanged;
4553
  end;
4554
end;
4555

4556
// SetxyCurve
4557
//
4558

4559
procedure TGLSuperellipsoid.SetxyCurve(const aValue: TGLFloat);
4560
begin
4561
  if aValue <> FxyCurve then
4562
  begin
4563
    FxyCurve := aValue;
4564
    StructureChanged;
4565
  end;
4566
end;
4567

4568
// SetzCurve
4569
//
4570

4571
procedure TGLSuperellipsoid.SetzCurve(const aValue: TGLFloat);
4572
begin
4573
  if aValue <> FzCurve then
4574
  begin
4575
    FzCurve := aValue;
4576
    StructureChanged;
4577
  end;
4578
end;
4579

4580
// SetSlices
4581
//
4582

4583
procedure TGLSuperellipsoid.SetSlices(aValue: Integer);
4584
begin
4585
  if aValue <> FSlices then
4586
  begin
4587
    if aValue <= 0 then
4588
      FSlices := 1
4589
    else
4590
      FSlices := aValue;
4591
    StructureChanged;
4592
  end;
4593
end;
4594

4595
// SetStacks
4596
//
4597

4598
procedure TGLSuperellipsoid.SetStacks(aValue: TGLInt);
4599
begin
4600
  if aValue <> FStacks then
4601
  begin
4602
    if aValue <= 0 then
4603
      FStacks := 1
4604
    else
4605
      FStacks := aValue;
4606
    StructureChanged;
4607
  end;
4608
end;
4609

4610
// SetStart
4611
//
4612

4613
procedure TGLSuperellipsoid.SetStart(aValue: TAngleLimit2);
4614
begin
4615
  if FStart <> aValue then
4616
  begin
4617
    Assert(aValue <= FStop);
4618
    FStart := aValue;
4619
    StructureChanged;
4620
  end;
4621
end;
4622

4623
// SetStop
4624
//
4625

4626
procedure TGLSuperellipsoid.SetStop(aValue: TAngleLimit2);
4627
begin
4628
  if FStop <> aValue then
4629
  begin
4630
    Assert(aValue >= FStart);
4631
    FStop := aValue;
4632
    StructureChanged;
4633
  end;
4634
end;
4635

4636
// SetTop
4637
//
4638

4639
procedure TGLSuperellipsoid.SetTop(aValue: TAngleLimit1);
4640
begin
4641
  if FTop <> aValue then
4642
  begin
4643
    FTop := aValue;
4644
    StructureChanged;
4645
  end;
4646
end;
4647

4648
// SetTopCap
4649
//
4650

4651
procedure TGLSuperellipsoid.SetTopCap(aValue: TCapType);
4652
begin
4653
  if FTopCap <> aValue then
4654
  begin
4655
    FTopCap := aValue;
4656
    StructureChanged;
4657
  end;
4658
end;
4659

4660
 
4661
//
4662

4663
procedure TGLSuperellipsoid.Assign(Source: TPersistent);
4664
begin
4665
  if Assigned(Source) and (Source is TGLSuperellipsoid) then
4666
  begin
4667
    FRadius := TGLSuperellipsoid(Source).FRadius;
4668
    FSlices := TGLSuperellipsoid(Source).FSlices;
4669
    FStacks := TGLSuperellipsoid(Source).FStacks;
4670
    FBottom := TGLSuperellipsoid(Source).FBottom;
4671
    FTop := TGLSuperellipsoid(Source).FTop;
4672
    FStart := TGLSuperellipsoid(Source).FStart;
4673
    FStop := TGLSuperellipsoid(Source).FStop;
4674
  end;
4675
  inherited Assign(Source);
4676
end;
4677

4678
// AxisAlignedDimensions
4679
//
4680

4681
function TGLSuperellipsoid.AxisAlignedDimensionsUnscaled: TVector;
4682
begin
4683
  Result.X := Abs(FRadius);
4684
  Result.Y := Result.X;
4685
  Result.Z := Result.X;
4686
  Result.W := 0;
4687
end;
4688

4689
// -------------------------------------------------------------
4690
// -------------------------------------------------------------
4691
// -------------------------------------------------------------
4692

4693
initialization
4694

4695
// -------------------------------------------------------------
4696
// -------------------------------------------------------------
4697
// -------------------------------------------------------------
4698

4699
RegisterClasses([TGLSphere, TGLCube, TGLPlane, TGLSprite, TGLPoints,
4700
  TGLDummyCube, TGLLines, TGLSuperellipsoid]);
4701

4702
end.
4703

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.