2
// This unit is part of the GLScene Engine https://github.com/glscene
5
Dynamic tree generation in GLScene
7
This code was adapted from the nVidia Tree Demo:
8
http://developer.nvidia.com/object/Procedural_Tree.html
11
10/11/12 - PW - Added CPP compatibility: changed vector arrays to records
12
23/08/10 - Yar - Added OpenGLTokens to uses, replaced OpenGL1x functions to OpenGLAdapter
13
30/03/07 - DaStr - Added $I GLScene.inc
14
28/03/07 - DaStr - Renamed parameters in some methods
15
(thanks Burkhard Carstens) (Bugtracker ID = 1678658)
16
13/01/07 - DaStr - Added changes proposed by Tim "Sivael" Kapuœciñski [sivael@gensys.pl]
17
Modified the code to create much more realistic trees -
18
added third branch for every node and modified constants
19
to make the tree look more "alive".
20
Also removed the "fractal effect" that ocurred, when
21
rendering with the older engine - the leaves and
22
branches were much more "in order".
23
Added Center* declarations, CenterBranchConstant,
24
Added AutoRebuild flag.
25
02/08/04 - LR, YHC - BCB corrections: use record instead array
26
14/04/04 - SG - Added AutoCenter property.
27
03/03/04 - SG - Added GetExtents and AxisAlignedDimensionsUnscaled.
28
24/11/03 - SG - Creation.
32
CenterBranchConstant -
33
Defines, how big the central branch is. When around 50%
34
it makes a small branch inside the tree, for higher values
35
much more branches and leaves are created, so either use it
36
with low depth, or set it to zero, and have two-branched tree.
39
Rebuild tree after property change.
51
GLScene, GLMaterial, GLVectorGeometry, GLVectorLists,
52
OpenGLTokens, GLVectorFileObjects, GLApplicationFileIO, GLRenderContextInfo,
53
XOpenGL, GLContext , GLVectorTypes;
57
TGLTreeBranches = class;
58
TGLTreeBranchNoise = class;
67
FVertices : TAffineVectorList;
68
FNormals : TAffineVectorList;
69
FTexCoords : TAffineVectorList;
73
constructor Create(AOwner : TGLTree);
74
destructor Destroy; override;
76
procedure BuildList(var rci : TGLRenderContextInfo);
77
procedure AddNew(matrix : TMatrix);
80
property Owner : TGLTree read FOwner;
81
property Count : Integer read FCount;
82
property Vertices : TAffineVectorList read FVertices;
83
property Normals : TAffineVectorList read FNormals;
84
property TexCoords : TAffineVectorList read FTexCoords;
92
FOwner : TGLTreeBranches;
93
FLeft : TGLTreeBranch;
94
FCenter : TGLTreeBranch;
95
FRight : TGLTreeBranch;
96
FParent : TGLTreeBranch;
100
FLower : TIntegerList;
101
FUpper : TIntegerList;
102
FCentralLeader : Boolean;
104
procedure BuildBranch(branchNoise : TGLTreeBranchNoise; const Matrix : TMatrix;
105
TexCoordY, Twist : Single; Level : Integer);
109
constructor Create(AOwner : TGLTreeBranches; AParent : TGLTreeBranch);
110
destructor Destroy; override;
112
property Owner : TGLTreeBranches read FOwner;
113
property Left : TGLTreeBranch read FLeft;
114
property Center : TGLTreeBranch read FCenter;
115
property Right : TGLTreeBranch read FRight;
116
property Parent : TGLTreeBranch read FParent;
117
property Matrix : TMatrix read FMatrix;
118
property Lower : TIntegerList read FLower;
119
property Upper : TIntegerList read FUpper;
124
TGLTreeBranches = class
128
FSinList : TSingleList;
129
FCosList : TSingleList;
130
FVertices : TAffineVectorList;
131
FNormals : TAffineVectorList;
132
FTexCoords : TAffineVectorList;
133
FIndices : TIntegerList;
134
FRoot : TGLTreeBranch;
136
FBranchCache : TList;
137
FBranchIndices : TIntegerList;
139
procedure BuildBranches;
143
constructor Create(AOwner : TGLTree);
144
destructor Destroy; override;
146
procedure BuildList(var rci : TGLRenderContextInfo);
149
property Owner : TGLTree read FOwner;
150
property SinList : TSingleList read FSinList;
151
property CosList : TSingleList read FCosList;
152
property Vertices : TAffineVectorList read FVertices;
153
property Normals : TAffineVectorList read FNormals;
154
property TexCoords : TAffineVectorList read FTexCoords;
155
property Count : Integer read FCount;
158
// TGLTreeBranchNoise
160
TGLTreeBranchNoise = class
163
FBranchNoise : Single;
164
FLeft, FRight, FCenter : TGLTreeBranchNoise;
166
function GetLeft : TGLTreeBranchNoise;
167
function GetCenter : TGLTreeBranchNoise;
168
function GetRight : TGLTreeBranchNoise;
173
destructor Destroy; override;
175
property Left : TGLTreeBranchNoise read GetLeft;
176
property Center : TGLTreeBranchNoise read GetCenter;
177
property Right : TGLTreeBranchNoise read GetRight;
178
property BranchNoise : Single read FBranchNoise;
183
TGLTree = class (TGLImmaterialSceneObject)
187
FBranchFacets : Integer;
189
FBranchSize : Single;
190
FBranchNoise : Single;
191
FBranchAngleBias : Single;
192
FBranchAngle : Single;
193
FBranchTwist : Single;
194
FBranchRadius : Single;
195
FLeafThreshold : Single;
196
FCentralLeaderBias : Single;
197
FCentralLeader : Boolean;
199
FAutoCenter : Boolean;
200
FAutoRebuild : Boolean;
201
FCenterBranchConstant : Single;
203
FLeaves : TGLTreeLeaves;
204
FBranches : TGLTreeBranches;
205
FNoise : TGLTreeBranchNoise;
207
FMaterialLibrary : TGLMaterialLibrary;
208
FLeafMaterialName : TGLLibMaterialName;
209
FLeafBackMaterialName : TGLLibMaterialName;
210
FBranchMaterialName : TGLLibMaterialName;
212
FRebuildTree : Boolean;
214
FAxisAlignedDimensionsCache : TVector;
218
procedure SetDepth(const Value : Integer);
219
procedure SetBranchFacets(const Value : Integer);
220
procedure SetLeafSize(const Value : Single);
221
procedure SetBranchSize(const Value : Single);
222
procedure SetBranchNoise(const Value : Single);
223
procedure SetBranchAngleBias(const Value : Single);
224
procedure SetBranchAngle(const Value : Single);
225
procedure SetBranchTwist(const Value : Single);
226
procedure SetBranchRadius(const Value : Single);
227
procedure SetLeafThreshold(const Value : Single);
228
procedure SetCentralLeaderBias(const Value : Single);
229
procedure SetCentralLeader(const Value : Boolean);
230
procedure SetSeed(const Value : Integer);
231
procedure SetAutoCenter(const Value : Boolean);
232
procedure SetAutoRebuild(const Value : Boolean);
233
procedure SetCenterBranchConstant(const Value : Single);
235
procedure SetMaterialLibrary(const Value : TGLMaterialLibrary);
236
procedure SetLeafMaterialName(const Value : TGLLibMaterialName);
237
procedure SetLeafBackMaterialName(const Value : TGLLibMaterialName);
238
procedure SetBranchMaterialName(const Value : TGLLibMaterialName);
240
procedure Loaded; override;
244
constructor Create(AOwner : TComponent); override;
245
destructor Destroy; override;
247
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
248
procedure DoRender(var ARci : TGLRenderContextInfo;
249
ARenderSelf, ARenderChildren : Boolean); override;
250
procedure BuildList(var rci : TGLRenderContextInfo); override;
251
procedure StructureChanged; override;
253
procedure BuildMesh(GLBaseMesh : TGLBaseMesh);
254
procedure RebuildTree;
255
procedure ForceTotalRebuild;
258
procedure GetExtents(var min, max : TAffineVector);
259
function AxisAlignedDimensionsUnscaled : TVector; override;
261
procedure LoadFromStream(aStream : TStream);
262
procedure SaveToStream(aStream : TStream);
263
procedure LoadFromFile(aFileName : String);
264
procedure SaveToFile(aFileName : String);
266
property Leaves : TGLTreeLeaves read FLeaves;
267
property Branches : TGLTreeBranches read FBranches;
268
property Noise : TGLTreeBranchNoise read FNoise;
272
{ The depth of tree branch recursion. }
273
property Depth : Integer read FDepth write SetDepth;
274
{ The number of facets for each branch in the tree. }
275
property BranchFacets : Integer read FBranchFacets write SetBranchFacets;
276
{ Leaf size modifier. Leaf size is also influenced by branch recursion
278
property LeafSize : Single read FLeafSize write SetLeafSize;
279
{ Branch length modifier. }
280
property BranchSize : Single read FBranchSize write SetBranchSize;
281
{ Overall branch noise influence. Relates to the 'fullness' of the tree. }
282
property BranchNoise : Single read FBranchNoise write SetBranchNoise;
283
{ Effects the habit of the tree. Values from 0 to 1 refer to Upright to
284
Spreading respectively. }
285
property BranchAngleBias : Single read FBranchAngleBias write SetBranchAngleBias;
286
{ Effects the balance of the tree. }
287
property BranchAngle : Single read FBranchAngle write SetBranchAngle;
288
{ Effects the rotation of each sub branch in recursion. }
289
property BranchTwist : Single read FBranchTwist write SetBranchTwist;
290
{ Effects the thickness of the branches. }
291
property BranchRadius : Single read FBranchRadius write SetBranchRadius;
292
{ Determines how thin a branch can get before a leaf is substituted. }
293
property LeafThreshold : Single read FLeafThreshold write SetLeafThreshold;
294
{ Determines how BranchAngle effects the central leader (CentralLeader must = True). }
295
property CentralLeaderBias : Single read FCentralLeaderBias write SetCentralLeaderBias;
296
{ Does this tree have a central leader? }
297
property CentralLeader : Boolean read FCentralLeader write SetCentralLeader;
298
property Seed : Integer read FSeed write SetSeed;
299
{ Automatically center the tree's vertices after building them. }
300
property AutoCenter : Boolean read FAutoCenter write SetAutoCenter;
301
{ Automatically rebuild the tree after changing the settings }
302
property AutoRebuild : Boolean read FAutoRebuild write SetAutoRebuild;
303
{ Central branch can be thinner(lower values)/thicker(->1) depending on this constant.
304
The effect also depends on the BranchAngle variable. }
305
property CenterBranchConstant : Single read FCenterBranchConstant write SetCenterBranchConstant;
307
property MaterialLibrary : TGLMaterialLibrary read FMaterialLibrary write SetMaterialLibrary;
308
property LeafMaterialName : TGLLibMaterialName read FLeafMaterialName write SetLeafMaterialName;
309
property LeafBackMaterialName : TGLLibMaterialName read FLeafBackMaterialName write SetLeafBackMaterialName;
310
property BranchMaterialName : TGLLibMaterialName read FBranchMaterialName write SetBranchMaterialName;
313
// -----------------------------------------------------------------------------
314
// -----------------------------------------------------------------------------
315
// -----------------------------------------------------------------------------
317
// -----------------------------------------------------------------------------
318
// -----------------------------------------------------------------------------
319
// -----------------------------------------------------------------------------
321
// -----------------------------------------------------------------------------
323
// -----------------------------------------------------------------------------
327
constructor TGLTreeLeaves.Create(AOwner: TGLTree);
331
FVertices:=TAffineVectorList.Create;
332
FNormals:=TAffineVectorList.Create;
333
FTexCoords:=TAffineVectorList.Create;
338
destructor TGLTreeLeaves.Destroy;
348
procedure TGLTreeLeaves.AddNew(matrix : TMatrix);
353
radius:=Owner.LeafSize;
357
Matrix.V[3]:=NullHMGPoint;
358
Matrix:=Roll(matrix, FCount/10);
359
NormalizeMatrix(matrix);
362
FVertices.Add(VectorTransform(PointMake(0, -radius, 0), matrix));
363
FVertices.Add(VectorTransform(PointMake(0, radius, 0), matrix));
364
FVertices.Add(VectorTransform(PointMake(0, radius, 2*radius), matrix));
365
FVertices.Add(VectorTransform(PointMake(0, -radius, 2*radius), matrix));
366
FNormals.Add(VectorTransform(XHmgVector, matrix));
367
FTexCoords.Add(XVector, NullVector);
368
FTexCoords.Add(YVector, XYVector);
373
procedure TGLTreeLeaves.BuildList(var rci: TGLRenderContextInfo);
377
libMat : TGLLibMaterial;
379
libMat:=Owner.MaterialLibrary.LibMaterialByName(Owner.LeafMaterialName);
380
if Assigned(libMat) then
383
GL.EnableClientState(GL_VERTEX_ARRAY);
384
xgl.EnableClientState(GL_TEXTURE_COORD_ARRAY);
386
GL.VertexPointer(3, GL_FLOAT, 0, @FVertices.List[0]);
387
xgl.TexCoordPointer(3, GL_FLOAT, 0, @FTexCoords.List[0]);
389
for i:=0 to (FVertices.Count div 4)-1 do begin
390
GL.Normal3fv(@FNormals.List[i]);
391
GL.DrawArrays(GL_QUADS, 4*i, 4);
394
with Owner do if LeafMaterialName<>LeafBackMaterialName then begin
395
if Assigned(libMat) then
397
libMat:=MaterialLibrary.LibMaterialByName(LeafBackMaterialName);
398
if Assigned(libMat) then
402
rci.GLStates.InvertGLFrontFace;
403
for i:=0 to (FVertices.Count div 4)-1 do begin
404
n:=VectorNegate(FNormals[i]);
406
GL.DrawArrays(GL_QUADS, 4*i, 4);
408
rci.GLStates.InvertGLFrontFace;
410
GL.DisableClientState(GL_VERTEX_ARRAY);
411
xgl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
413
if Assigned(libMat) then
419
procedure TGLTreeLeaves.Clear;
427
// -----------------------------------------------------------------------------
429
// -----------------------------------------------------------------------------
433
constructor TGLTreeBranch.Create(AOwner : TGLTreeBranches; AParent : TGLTreeBranch);
437
FUpper:=TIntegerList.Create;
438
FLower:=TIntegerList.Create;
439
FCentralLeader:=False;
441
// Skeletal construction helpers
442
if Assigned(FOwner) then begin
443
FBranchID:=FOwner.Count-1;
444
FOwner.FBranchCache.Add(Self);
445
end else FBranchID:=-1;
446
if Assigned(FParent) then
447
FParentID:=FParent.FBranchID
453
destructor TGLTreeBranch.Destroy;
464
procedure TGLTreeBranch.BuildBranch(branchNoise : TGLTreeBranchNoise; const Matrix : TMatrix;
465
TexCoordY, Twist : Single; Level : Integer);
469
Branches : TGLTreeBranches;
472
Radius, LeftRadius, RightRadius, CenterRadius : Single;
473
BranchAngle, LeftAngle, RightAngle, CenterAngle : Single;
474
BranchAngleBias, BranchTwist, Taper : Single;
475
LeftBranchNoiseValue, RightBranchNoiseValue, CenterBranchNoiseValue : Single;
476
LeftBranchNoise : TGLTreeBranchNoise;
477
CenterBranchNoise : TGLTreeBranchNoise;
478
RightBranchNoise : TGLTreeBranchNoise;
479
LeftMatrix, RightMatrix, CenterMatrix : TMatrix;
480
central_leader : Boolean;
482
Assert(Assigned(FOwner),'Incorrect use of TGLTreeBranch');
483
Assert(Assigned(FOwner.FOwner),'Incorrect use of TGLTreeBranches');
490
Facets:=Tree.BranchFacets;
491
Radius:=Tree.BranchRadius;
494
FLower.Capacity:=Facets+1;
496
FUpper.Capacity:=Facets+1;
498
BranchAngle:=Tree.BranchAngle;
499
BranchAngleBias:=Tree.BranchAngleBias;
500
BranchTwist:=Twist+Tree.BranchTwist;
502
LeftBranchNoise:=BranchNoise.Left;
503
CenterBranchNoise:=BranchNoise.Center;
504
RightBranchNoise:=BranchNoise.Right;
506
LeftBranchNoiseValue:=((LeftBranchNoise.BranchNoise*0.4)-0.1)*Tree.BranchNoise;
507
LeftRadius:=Sqrt(1-BranchAngle+LeftBranchNoiseValue);
508
LeftRadius:=ClampValue(LeftRadius,0,1);
509
LeftAngle:=BranchAngle*90*BranchAngleBias+10*LeftBranchNoiseValue;
511
CenterBranchNoiseValue:=((CenterBranchNoise.BranchNoise*0.9)-0.1)*Tree.BranchNoise;
512
CenterRadius:=Sqrt(Tree.CenterBranchConstant-BranchAngle+CenterBranchNoiseValue);
513
CenterRadius:=ClampValue(CenterRadius,0,1);
514
CenterAngle:=(1-BranchAngle)*50*CenterBranchNoiseValue*BranchAngleBias;
516
RightBranchNoiseValue:=((RightBranchNoise.BranchNoise*0.6)-0.1)*Tree.BranchNoise;
517
RightRadius:=Sqrt(BranchAngle+RightBranchNoiseValue);
518
RightRadius:=ClampValue(RightRadius,0,1);
519
RightAngle:=(1-BranchAngle)*-90*BranchAngleBias+10*RightBranchNoiseValue;
521
Taper:=MaxFloat(LeftRadius, RightRadius, CenterRadius);
523
// Build cylinder lower
524
for i:=0 to Facets do begin
526
c:=Branches.CosList[i];
527
s:=Branches.SinList[i];
528
Branches.Vertices.Add(VectorTransform(PointMake(c*Radius,s*Radius,Radius),Matrix));
529
Branches.Normals.Add(VectorTransform(VectorMake(c,s,0),Matrix));
530
Branches.TexCoords.Add(t,TexCoordY);
531
FLower.Add(Branches.Vertices.Count-1);
532
Branches.FBranchIndices.Add(FBranchID);
535
TexCoordY:=TexCoordY+1-2*Radius;
537
// Build cylinder upper
538
for i:=0 to Facets do begin
540
c:=Branches.CosList[i];
541
s:=Branches.SinList[i];
542
Branches.Vertices.Add(VectorTransform(PointMake(c*Radius*Taper,s*Radius*Taper,1-Radius),Matrix));
543
Branches.Normals.Add(VectorTransform(VectorMake(c,s,0),Matrix));
544
Branches.TexCoords.Add(t,TexCoordY);
545
FUpper.Add(Branches.Vertices.Count-1);
546
Branches.FBranchIndices.Add(FBranchID);
549
TexCoordY:=TexCoordY+2*Radius;
552
SinCos(DegToRad(BranchTwist),s,c);
555
central_leader:=FCentralLeader
557
central_leader:=FParent.FCentralLeader;
559
if central_leader then begin
560
LeftMatrix:=MatrixMultiply(
561
CreateScaleMatrix(AffineVectorMake(LeftRadius,LeftRadius,LeftRadius)),
562
CreateRotationMatrix(AffineVectorMake(s,c,0),DegToRad(LeftAngle)*Tree.CentralLeaderBias));
564
LeftMatrix:=MatrixMultiply(
565
CreateScaleMatrix(AffineVectorMake(LeftRadius,LeftRadius,LeftRadius)),
566
CreateRotationMatrix(AffineVectorMake(s,c,0),DegToRad(LeftAngle)));
568
LeftMatrix:=MatrixMultiply(
570
MatrixMultiply(CreateTranslationMatrix(AffineVectorMake(0,0,Tree.BranchSize*(1-LeftBranchNoiseValue))),Matrix));
572
CenterMatrix:=MatrixMultiply(
573
CreateScaleMatrix(AffineVectorMake(CenterRadius,CenterRadius,CenterRadius)),
574
CreateRotationMatrix(AffineVectorMake(s,c,0),DegToRad(CenterAngle)));
575
CenterMatrix:=MatrixMultiply(
577
MatrixMultiply(CreateTranslationMatrix(AffineVectorMake(0,0,Tree.BranchSize*(1-CenterBranchNoiseValue))),Matrix));
579
RightMatrix:=MatrixMultiply(
580
CreateScaleMatrix(AffineVectorMake(RightRadius,RightRadius,RightRadius)),
581
CreateRotationMatrix(AffineVectorMake(s,c,0),DegToRad(RightAngle)));
582
RightMatrix:=MatrixMultiply(
584
MatrixMultiply(CreateTranslationMatrix(AffineVectorMake(0,0,Tree.BranchSize*(1-RightBranchNoiseValue))),Matrix));
586
if (((Level+1)>=Tree.Depth) or (LeftRadius<Tree.LeafThreshold)) then begin
587
Tree.Leaves.AddNew(LeftMatrix);
589
Inc(Branches.FCount);
590
FLeft:=TGLTreeBranch.Create(Owner,Self);
591
FLeft.FCentralLeader:=central_leader and (LeftRadius>=RightRadius);
592
FLeft.BuildBranch(LeftBranchNoise,LeftMatrix,TexCoordY,BranchTwist,Level+1);
595
if (((Level+1)>=Tree.Depth) or (CenterRadius<Tree.LeafThreshold)) then begin
596
Tree.Leaves.AddNew(CenterMatrix);
598
Inc(Branches.FCount);
599
FCenter:=TGLTreeBranch.Create(Owner,Self);
600
FCenter.BuildBranch(CenterBranchNoise,CenterMatrix,TexCoordY,BranchTwist,Level+1);
603
if (((Level+1)>=Tree.Depth) or (RightRadius<Tree.LeafThreshold)) then begin
604
Tree.Leaves.AddNew(RightMatrix);
606
Inc(Branches.FCount);
607
FRight:=TGLTreeBranch.Create(Owner,Self);
608
FRight.BuildBranch(RightBranchNoise,RightMatrix,TexCoordY,BranchTwist,Level+1);
611
for i:=0 to Facets do begin
612
Branches.FIndices.Add(Upper[i]);
613
Branches.FIndices.Add(Lower[i]);
616
if Assigned(FRight) then begin
617
for i:=0 to Facets do begin
618
Branches.FIndices.Add(Right.Lower[i]);
619
Branches.FIndices.Add(Upper[i]);
623
if Assigned(FCenter) then begin
624
for i:=0 to Facets do begin
625
Branches.FIndices.Add(Center.Lower[i]);
626
Branches.FIndices.Add(Upper[i]);
630
if Assigned(FLeft) then begin
631
for i:=0 to Facets do begin
632
Branches.FIndices.Add(Left.Lower[i]);
633
Branches.FIndices.Add(Upper[i]);
639
// -----------------------------------------------------------------------------
641
// -----------------------------------------------------------------------------
645
constructor TGLTreeBranches.Create(AOwner: TGLTree);
648
FSinList:=TSingleList.Create;
649
FCosList:=TSingleList.Create;
650
FVertices:=TAffineVectorList.Create;
651
FNormals:=TAffineVectorList.Create;
652
FTexCoords:=TAffineVectorList.Create;
653
FIndices:=TIntegerList.Create;
654
FBranchCache:=TList.Create;
655
FBranchIndices:=TIntegerList.Create;
661
destructor TGLTreeBranches.Destroy;
677
procedure TGLTreeBranches.BuildBranches;
681
delta, min, max : TAffineVector;
683
RandSeed:=Owner.FSeed;
685
for i:=0 to Owner.BranchFacets do begin
686
u:=1/Owner.BranchFacets*i;
687
SinList.Add(Sin(PI*2*u));
688
CosList.Add(Cos(PI*2*u));
692
FRoot:=TGLTreeBranch.Create(Self,nil);
693
FRoot.FCentralLeader:=Owner.CentralLeader;
694
FRoot.BuildBranch(Owner.Noise,IdentityHMGMatrix,0,0,0);
696
delta:=AffineVectorMake(0,0,-Owner.BranchRadius);
697
Vertices.Translate(delta);
698
Owner.Leaves.Vertices.Translate(delta);
700
if Owner.AutoCenter then begin
701
Owner.GetExtents(min, max);
702
delta:=VectorCombine(min,max,-0.5,-0.5);
703
Vertices.Translate(delta);
704
Owner.Leaves.Vertices.Translate(delta);
707
Owner.FAxisAlignedDimensionsCache.V[0]:=-1;
712
procedure TGLTreeBranches.BuildList(var rci: TGLRenderContextInfo);
715
libMat : TGLLibMaterial;
717
stride:=(Owner.BranchFacets+1)*2;
719
libMat:=Owner.MaterialLibrary.LibMaterialByName(Owner.BranchMaterialName);
720
if Assigned(libMat) then
723
GL.VertexPointer(3, GL_FLOAT, 0, @FVertices.List[0]);
724
GL.NormalPointer(GL_FLOAT, 0, @FNormals.List[0]);
725
xgl.TexCoordPointer(3, GL_FLOAT, 0, @FTexCoords.List[0]);
727
GL.EnableClientState(GL_VERTEX_ARRAY);
728
GL.EnableClientState(GL_NORMAL_ARRAY);
729
xgl.EnableClientState(GL_TEXTURE_COORD_ARRAY);
732
for i:=0 to (FIndices.Count div stride)-1 do
733
GL.DrawElements(GL_TRIANGLE_STRIP, stride, GL_UNSIGNED_INT, @FIndices.List[stride*i]);
734
until (not Assigned(libMat)) or (not libMat.UnApply(rci));
736
xgl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
737
GL.DisableClientState(GL_NORMAL_ARRAY);
738
GL.DisableClientState(GL_VERTEX_ARRAY);
743
procedure TGLTreeBranches.Clear;
752
FBranchIndices.Clear;
757
// -----------------------------------------------------------------------------
759
// -----------------------------------------------------------------------------
763
constructor TGLTreeBranchNoise.Create;
765
FBranchNoise:=Random;
770
destructor TGLTreeBranchNoise.Destroy;
779
function TGLTreeBranchNoise.GetLeft: TGLTreeBranchNoise;
781
if not Assigned(FLeft) then
782
FLeft:=TGLTreeBranchNoise.Create;
788
function TGLTreeBranchNoise.GetRight: TGLTreeBranchNoise;
790
if not Assigned(FRight) then
791
FRight:=TGLTreeBranchNoise.Create;
795
function TGLTreeBranchNoise.GetCenter: TGLTreeBranchNoise;
797
if not Assigned(FCenter) then
798
FCenter:=TGLTreeBranchNoise.Create;
802
// -----------------------------------------------------------------------------
804
// -----------------------------------------------------------------------------
808
constructor TGLTree.Create(AOwner: TComponent);
811
// Default tree setting
813
FLeafThreshold:=0.02;
814
FBranchAngleBias:=0.6;
822
FCentralLeader:=False;
826
FCenterBranchConstant:=0.5;
828
FLeaves:=TGLTreeLeaves.Create(Self);
829
FBranches:=TGLTreeBranches.Create(Self);
830
FNoise:=TGLTreeBranchNoise.Create;
835
destructor TGLTree.Destroy;
845
procedure TGLTree.Loaded;
848
FBranches.BuildBranches;
853
procedure TGLTree.Notification(AComponent: TComponent; Operation: TOperation);
855
if (Operation=opRemove) and (AComponent=FMaterialLibrary) then
856
MaterialLibrary:=nil;
862
procedure TGLTree.DoRender(var ARci : TGLRenderContextInfo;
863
ARenderSelf, ARenderChildren : Boolean);
865
MaterialLibrary.LibMaterialByName(BranchMaterialName).PrepareBuildList;
866
MaterialLibrary.LibMaterialByName(LeafMaterialName).PrepareBuildList;
867
MaterialLibrary.LibMaterialByName(LeafBackMaterialName).PrepareBuildList;
873
procedure TGLTree.BuildList(var rci: TGLRenderContextInfo);
875
if FRebuildTree then begin
876
FBranches.BuildBranches;
879
Branches.BuildList(rci);
880
Leaves.BuildList(rci);
885
procedure TGLTree.StructureChanged;
887
FAxisAlignedDimensionsCache.V[0]:=-1;
893
procedure TGLTree.BuildMesh(GLBaseMesh : TGLBaseMesh);
895
procedure RecursBranches(Branch : TGLTreeBranch; bone : TGLSkeletonBone; Frame : TGLSkeletonFrame);
897
trans : TTransformations;
899
rot, pos : TAffineVector;
901
bone.Name:='Branch'+IntToStr(Branch.FBranchID);
902
bone.BoneID:=Branch.FBranchID;
904
// Construct base frame
905
if Assigned(Branch.FParent) then
906
mat:=Branch.FParent.FMatrix
908
mat:=IdentityHMGMatrix;
910
NormalizeMatrix(mat);
911
if MatrixDecompose(mat,trans) then begin
912
SetVector(rot,trans[ttRotateX],trans[ttRotateY],trans[ttRotateZ]);
913
SetVector(pos,mat.V[3]);
918
Frame.Rotation.Add(rot);
919
Frame.Position.Add(pos);
921
// Recurse with child branches
922
if Assigned(Branch.Left) then
923
RecursBranches(Branch.Left, TGLSkeletonBone.CreateOwned(bone), Frame);
924
if Assigned(Branch.Right) then
925
RecursBranches(Branch.Right, TGLSkeletonBone.CreateOwned(bone), Frame);
929
//SkelMesh : TGLSkeletonMeshObject;
930
fg : TFGVertexIndexList;
931
fg2 : TFGVertexNormalTexIndexList;
932
i,j,stride : integer;
933
//parent_id : integer;
934
//bone : TGLSkeletonBone;
936
if not Assigned(GLBaseMesh) then exit;
938
if FRebuildTree then begin
939
FBranches.BuildBranches;
943
GLBaseMesh.MeshObjects.Clear;
944
GLBaseMesh.Skeleton.Clear;
946
//if GLBaseMesh is TGLActor then
947
// TGLSkeletonMeshObject.CreateOwned(GLBaseMesh.MeshObjects)
949
TGLMeshObject.CreateOwned(GLBaseMesh.MeshObjects);
950
GLBaseMesh.MeshObjects[0].Mode:=momFaceGroups;
953
GLBaseMesh.MeshObjects[0].Vertices.Add(Branches.Vertices);
954
GLBaseMesh.MeshObjects[0].Normals.Add(Branches.Normals);
955
GLBaseMesh.MeshObjects[0].TexCoords.Add(Branches.TexCoords);
956
{if GLBaseMesh is TGLActor then begin
957
TGLActor(GLBaseMesh).Reference:=aarSkeleton;
958
RecursBranches(Branches.FRoot,
959
TGLSkeletonBone.CreateOwned(GLBaseMesh.Skeleton.RootBones),
960
TGLSkeletonFrame.CreateOwned(GLBaseMesh.Skeleton.Frames));
961
SkelMesh:=TGLSkeletonMeshObject(GLBaseMesh.MeshObjects[0]);
962
SkelMesh.BonesPerVertex:=1;
963
SkelMesh.VerticeBoneWeightCount:=Branches.FBranchIndices.Count;
964
for i:=0 to Branches.FBranchIndices.Count-1 do
965
SkelMesh.AddWeightedBone(Branches.FBranchIndices[i],1);
966
GLBaseMesh.Skeleton.RootBones.PrepareGlobalMatrices;
967
SkelMesh.PrepareBoneMatrixInvertedMeshes;
969
SkelMesh.ApplyCurrentSkeletonFrame(True);
971
stride:=(BranchFacets+1)*2;
972
for i:=0 to (FBranches.FIndices.Count div stride)-1 do begin
973
fg:=TFGVertexIndexList.CreateOwned(GLBaseMesh.MeshObjects[0].FaceGroups);
974
fg.MaterialName:=BranchMaterialName;
975
fg.Mode:=fgmmTriangleStrip;
976
for j:=0 to stride-1 do
977
fg.VertexIndices.Add(Branches.FIndices[i*stride+j]);
981
//if GLBaseMesh is TGLActor then
982
// TGLSkeletonMeshObject.CreateOwned(GLBaseMesh.MeshObjects)
984
TGLMeshObject.CreateOwned(GLBaseMesh.MeshObjects);
985
GLBaseMesh.MeshObjects[1].Mode:=momFaceGroups;
987
GLBaseMesh.MeshObjects[1].Vertices.Add(Leaves.Vertices);
988
GLBaseMesh.MeshObjects[1].Normals.Add(Leaves.FNormals);
989
for i:=0 to Leaves.Normals.Count-1 do
990
GLBaseMesh.MeshObjects[1].Normals.Add(VectorNegate(Leaves.FNormals[i]));
991
GLBaseMesh.MeshObjects[1].TexCoords.Add(Leaves.TexCoords);
993
for i:=0 to (Leaves.FVertices.Count div 4)-1 do begin
996
fg2:=TFGVertexNormalTexIndexList.CreateOwned(GLBaseMesh.MeshObjects[1].FaceGroups);
997
fg2.MaterialName:=LeafMaterialName;
998
fg2.Mode:=fgmmTriangleStrip;
999
with fg2.VertexIndices do begin
1006
fg2.NormalIndices.Add(i);
1007
with fg2.TexCoordIndices do begin
1015
fg2:=TFGVertexNormalTexIndexList.CreateOwned(GLBaseMesh.MeshObjects[1].FaceGroups);
1016
fg2.MaterialName:=LeafBackMaterialName;
1017
fg2.Mode:=fgmmTriangleStrip;
1018
with fg2.VertexIndices do begin
1025
fg2.NormalIndices.Add(i);
1026
with fg2.TexCoordIndices do begin
1037
procedure TGLTree.Clear;
1045
procedure TGLTree.SetBranchAngle(const Value: Single);
1047
if Value<>FBranchAngle then begin
1048
FBranchAngle:=Value;
1049
if (FAutoRebuild) then RebuildTree;
1053
// SetBranchAngleBias
1055
procedure TGLTree.SetBranchAngleBias(const Value: Single);
1057
if Value<>FBranchAngleBias then begin
1058
FBranchAngleBias:=Value;
1059
if (FAutoRebuild) then RebuildTree;
1065
procedure TGLTree.SetBranchNoise(const Value: Single);
1067
if Value<>FBranchNoise then begin
1068
FBranchNoise:=Value;
1069
if (FAutoRebuild) then RebuildTree;
1075
procedure TGLTree.SetBranchRadius(const Value: Single);
1077
if Value<>FBranchRadius then begin
1078
FBranchRadius:=Value;
1079
if (FAutoRebuild) then RebuildTree;
1085
procedure TGLTree.SetBranchSize(const Value: Single);
1087
if Value<>FBranchSize then begin
1089
if (FAutoRebuild) then RebuildTree;
1095
procedure TGLTree.SetBranchTwist(const Value: Single);
1097
if Value<>FBranchTwist then begin
1098
FBranchTwist:=Value;
1099
if (FAutoRebuild) then RebuildTree;
1105
procedure TGLTree.SetDepth(const Value: Integer);
1107
if Value<>FDepth then begin
1109
if (FAutoRebuild) then RebuildTree;
1115
procedure TGLTree.SetBranchFacets(const Value: Integer);
1117
if Value<>FBranchFacets then begin
1118
FBranchFacets:=Value;
1119
if (FAutoRebuild) then RebuildTree;
1125
procedure TGLTree.SetLeafSize(const Value: Single);
1127
if Value<>FLeafSize then begin
1129
if (FAutoRebuild) then RebuildTree;
1135
procedure TGLTree.SetLeafThreshold(const Value: Single);
1137
if Value<>FLeafThreshold then begin
1138
FLeafThreshold:=Value;
1139
if (FAutoRebuild) then RebuildTree;
1143
// SetCentralLeaderBias
1145
procedure TGLTree.SetCentralLeaderBias(const Value: Single);
1147
if Value<>FCentralLeaderBias then begin
1148
FCentralLeaderBias:=Value;
1149
if (FAutoRebuild) then RebuildTree;
1155
procedure TGLTree.SetCentralLeader(const Value: Boolean);
1157
if Value<>FCentralLeader then begin
1158
FCentralLeader:=Value;
1159
if (FAutoRebuild) then RebuildTree;
1165
procedure TGLTree.SetSeed(const Value: Integer);
1167
if Value<>FSeed then begin
1169
if (FAutoRebuild) then ForceTotalRebuild;
1173
// SetCenterBranchConstant
1175
procedure TGLTree.SetCenterBranchConstant(const Value : Single);
1177
if Value<>CenterBranchConstant then begin
1178
FCenterBranchConstant:=Value;
1179
if (FAutoRebuild) then ForceTotalRebuild;
1183
// SetBranchMaterialName
1185
procedure TGLTree.SetBranchMaterialName(const Value: TGLLibMaterialName);
1187
if Value<>FBranchMaterialName then begin
1188
FBranchMaterialName:=Value;
1193
// SetLeafBackMaterialName
1195
procedure TGLTree.SetLeafBackMaterialName(const Value: TGLLibMaterialName);
1197
if Value<>FLeafBackMaterialName then begin
1198
FLeafBackMaterialName:=Value;
1203
// SetLeafMaterialName
1205
procedure TGLTree.SetLeafMaterialName(const Value: TGLLibMaterialName);
1207
if Value<>FLeafMaterialName then begin
1208
FLeafMaterialName:=Value;
1213
// SetMaterialLibrary
1215
procedure TGLTree.SetMaterialLibrary(const Value: TGLMaterialLibrary);
1217
if Value<>FMaterialLibrary then begin
1218
FMaterialLibrary:=Value;
1225
procedure TGLTree.RebuildTree;
1227
if not FRebuildTree then begin
1236
procedure TGLTree.ForceTotalRebuild;
1241
FNoise:=TGLTreeBranchNoise.Create;
1242
FRebuildTree:=False;
1243
FBranches.BuildBranches;
1249
procedure TGLTree.LoadFromStream(aStream: TStream);
1251
StrList, StrParse : TStringList;
1255
StrList:=TStringList.Create;
1256
StrParse:=TStringList.Create;
1258
StrList.LoadFromStream(aStream);
1260
for i:=0 to StrList.Count-1 do begin
1262
if Pos('#',str)>0 then
1263
str:=Copy(str,0,Pos('#',str)-1);
1264
StrParse.CommaText:=str;
1265
if StrParse.Count>=2 then begin
1266
str:=LowerCase(StrParse[0]);
1267
if str = 'depth' then FDepth:=StrToInt(StrParse[1])
1268
else if str = 'branch_facets' then FBranchFacets:=StrToInt(StrParse[1])
1269
else if str = 'leaf_size' then FLeafSize:=StrToFloat(StrParse[1])
1270
else if str = 'branch_size' then FBranchSize:=StrToFloat(StrParse[1])
1271
else if str = 'branch_noise' then FBranchNoise:=StrToFloat(StrParse[1])
1272
else if str = 'branch_angle_bias' then FBranchAngleBias:=StrToFloat(StrParse[1])
1273
else if str = 'branch_angle' then FBranchAngle:=StrToFloat(StrParse[1])
1274
else if str = 'branch_twist' then FBranchTwist:=StrToFloat(StrParse[1])
1275
else if str = 'branch_radius' then FBranchRadius:=StrToFloat(StrParse[1])
1276
else if str = 'leaf_threshold' then FLeafThreshold:=StrToFloat(StrParse[1])
1277
else if str = 'central_leader_bias' then FCentralLeaderBias:=StrToFloat(StrParse[1])
1278
else if str = 'central_leader' then FCentralLeader:=LowerCase(StrParse[1])='true'
1279
else if str = 'seed' then FSeed:=StrToInt(StrParse[1])
1280
else if str = 'leaf_front_material_name' then FLeafMaterialName:=StrParse[1]
1281
else if str = 'leaf_back_material_name' then FLeafBackMaterialName:=StrParse[1]
1282
else if str = 'branch_material_name' then FBranchMaterialName:=StrParse[1];
1293
procedure TGLTree.SaveToStream(aStream: TStream);
1295
StrList : TStringList;
1297
StrList:=TStringList.Create;
1298
StrList.Add(Format('depth, %d',[Depth]));
1299
StrList.Add(Format('branch_facets, %d',[BranchFacets]));
1300
StrList.Add(Format('leaf_size, %f',[LeafSize]));
1301
StrList.Add(Format('branch_size, %f',[BranchSize]));
1302
StrList.Add(Format('branch_noise, %f',[BranchNoise]));
1303
StrList.Add(Format('branch_angle_bias, %f',[BranchAngleBias]));
1304
StrList.Add(Format('branch_angle, %f',[BranchAngle]));
1305
StrList.Add(Format('branch_twist, %f',[BranchTwist]));
1306
StrList.Add(Format('branch_radius, %f',[BranchRadius]));
1307
StrList.Add(Format('leaf_threshold, %f',[LeafThreshold]));
1308
StrList.Add(Format('central_leader_bias, %f',[CentralLeaderBias]));
1309
if CentralLeader then
1310
StrList.Add('central_leader, true')
1312
StrList.Add('central_leader, false');
1313
StrList.Add(Format('seed, %d',[Seed]));
1314
StrList.Add('leaf_front_material_name, "'+LeafMaterialName+'"');
1315
StrList.Add('leaf_back_material_name, "'+LeafBackMaterialName+'"');
1316
StrList.Add('branch_material_name, "'+BranchMaterialName+'"');
1317
StrList.SaveToStream(aStream);
1323
procedure TGLTree.LoadFromFile(aFileName: String);
1327
stream:=CreateFileStream(aFileName);
1329
LoadFromStream(stream);
1337
procedure TGLTree.SaveToFile(aFileName: String);
1341
stream:=CreateFileStream(aFileName,fmCreate);
1343
SaveToStream(stream);
1350
procedure TGLTree.GetExtents(var min, max : TAffineVector);
1353
bmin, bmax : TAffineVector;
1355
if Branches.Vertices.Count = 0 then begin
1356
FBranches.BuildBranches;
1357
FRebuildTree:=False;
1359
if Leaves.Vertices.Count>0 then
1360
Leaves.Vertices.GetExtents(lmin, lmax)
1365
if Branches.Vertices.Count>0 then
1366
Branches.Vertices.GetExtents(bmin, bmax)
1372
min.V[0]:=MinFloat([lmin.V[0], lmax.V[0], bmin.V[0], bmax.V[0]]);
1373
min.V[1]:=MinFloat([lmin.V[1], lmax.V[1], bmin.V[1], bmax.V[1]]);
1374
min.V[2]:=MinFloat([lmin.V[2], lmax.V[2], bmin.V[2], bmax.V[2]]);
1376
max.V[0]:=MaxFloat([lmin.V[0], lmax.V[0], bmin.V[0], bmax.V[0]]);
1377
max.V[1]:=MaxFloat([lmin.V[1], lmax.V[1], bmin.V[1], bmax.V[1]]);
1378
max.V[2]:=MaxFloat([lmin.V[2], lmax.V[2], bmin.V[2], bmax.V[2]]);
1381
// AxisAlignedDimensionsUnscaled
1383
function TGLTree.AxisAlignedDimensionsUnscaled : TVector;
1385
dMin, dMax : TAffineVector;
1387
if FAxisAlignedDimensionsCache.V[0]<0 then begin
1388
GetExtents(dMin, dMax);
1389
FAxisAlignedDimensionsCache.V[0]:=MaxFloat(Abs(dMin.V[0]), Abs(dMax.V[0]));
1390
FAxisAlignedDimensionsCache.V[1]:=MaxFloat(Abs(dMin.V[1]), Abs(dMax.V[1]));
1391
FAxisAlignedDimensionsCache.V[2]:=MaxFloat(Abs(dMin.V[2]), Abs(dMax.V[2]));
1393
SetVector(Result, FAxisAlignedDimensionsCache);
1398
procedure TGLTree.SetAutoCenter(const Value: Boolean);
1400
if Value<>FAutoCenter then begin
1402
if (FAutoRebuild) then RebuildTree;
1408
procedure TGLTree.SetAutoRebuild(const Value: Boolean);
1410
if Value<>FAutoRebuild then begin
1411
FAutoRebuild:=Value;
1417
RegisterClasses([TGLTree]);