GXS.Tree.pas 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.Tree;
  5. (*
  6. Dynamic tree generation
  7. This code was adapted from the nVidia Tree Demo:
  8. http://developer.nvidia.com/object/Procedural_Tree.html
  9. Some info:
  10. CenterBranchConstant - Defines, how big the central branch is. When around 50%
  11. it makes a small branch inside the tree, for higher values
  12. much more branches and leaves are created, so either use it
  13. with low depth, or set it to zero, and have two-branched tree.
  14. Default : 0.5
  15. "AutoRebuild" flag - Rebuild tree after property change.
  16. Default: True *)
  17. interface
  18. {$I Stage.Defines.inc}
  19. uses
  20. Winapi.OpenGL,
  21. System.Classes,
  22. System.SysUtils,
  23. System.Math,
  24. GXS.XOpenGL,
  25. Stage.VectorGeometry,
  26. GXS.VectorLists,
  27. GXS.ApplicationFileIO,
  28. Stage.VectorTypes,
  29. Stage.Strings,
  30. GXS.State,
  31. GXS.Scene,
  32. GXS.VectorFileObjects,
  33. GXS.RenderContextInfo,
  34. GXS.Context,
  35. GXS.Material;
  36. type
  37. TgxTree = class;
  38. TgxTreeBranches = class;
  39. TgxTreeBranchNoise = class;
  40. TgxTreeLeaves = class
  41. private
  42. FOwner: TgxTree;
  43. FCount: Integer;
  44. FVertices: TgxAffineVectorList;
  45. FNormals: TgxAffineVectorList;
  46. FTexCoords: TgxAffineVectorList;
  47. public
  48. constructor Create(AOwner: TgxTree);
  49. destructor Destroy; override;
  50. procedure BuildList(var rci: TgxRenderContextInfo);
  51. procedure AddNew(matrix: TMatrix4f);
  52. procedure Clear;
  53. property Owner: TgxTree read FOwner;
  54. property Count: Integer read FCount;
  55. property Vertices: TgxAffineVectorList read FVertices;
  56. property Normals: TgxAffineVectorList read FNormals;
  57. property TexCoords: TgxAffineVectorList read FTexCoords;
  58. end;
  59. TgxTreeBranch = class
  60. private
  61. FOwner: TgxTreeBranches;
  62. FLeft: TgxTreeBranch;
  63. FCenter: TgxTreeBranch;
  64. FRight: TgxTreeBranch;
  65. FParent: TgxTreeBranch;
  66. FBranchID: Integer;
  67. FParentID: Integer;
  68. FMatrix: TMatrix4f;
  69. FLower: TgxIntegerList;
  70. FUpper: TgxIntegerList;
  71. FCentralLeader: Boolean;
  72. procedure BuildBranch(branchNoise: TgxTreeBranchNoise;
  73. const matrix: TMatrix4f; TexCoordY, Twist: Single; Level: Integer);
  74. public
  75. constructor Create(AOwner: TgxTreeBranches; AParent: TgxTreeBranch);
  76. destructor Destroy; override;
  77. property Owner: TgxTreeBranches read FOwner;
  78. property Left: TgxTreeBranch read FLeft;
  79. property Center: TgxTreeBranch read FCenter;
  80. property Right: TgxTreeBranch read FRight;
  81. property Parent: TgxTreeBranch read FParent;
  82. property matrix: TMatrix4f read FMatrix;
  83. property Lower: TgxIntegerList read FLower;
  84. property Upper: TgxIntegerList read FUpper;
  85. end;
  86. TgxTreeBranches = class
  87. private
  88. FOwner: TgxTree;
  89. FSinList: TgxSingleList;
  90. FCosList: TgxSingleList;
  91. FVertices: TgxAffineVectorList;
  92. FNormals: TgxAffineVectorList;
  93. FTexCoords: TgxAffineVectorList;
  94. FIndices: TgxIntegerList;
  95. FRoot: TgxTreeBranch;
  96. FCount: Integer;
  97. FBranchCache: TList;
  98. FBranchIndices: TgxIntegerList;
  99. procedure BuildBranches;
  100. public
  101. constructor Create(AOwner: TgxTree);
  102. destructor Destroy; override;
  103. procedure BuildList(var rci: TgxRenderContextInfo);
  104. procedure Clear;
  105. property Owner: TgxTree read FOwner;
  106. property SinList: TgxSingleList read FSinList;
  107. property CosList: TgxSingleList read FCosList;
  108. property Vertices: TgxAffineVectorList read FVertices;
  109. property Normals: TgxAffineVectorList read FNormals;
  110. property TexCoords: TgxAffineVectorList read FTexCoords;
  111. property Count: Integer read FCount;
  112. end;
  113. TgxTreeBranchNoise = class
  114. private
  115. FBranchNoise: Single;
  116. FLeft, FRight, FCenter: TgxTreeBranchNoise;
  117. function GetLeft: TgxTreeBranchNoise;
  118. function GetCenter: TgxTreeBranchNoise;
  119. function GetRight: TgxTreeBranchNoise;
  120. public
  121. constructor Create;
  122. destructor Destroy; override;
  123. property Left: TgxTreeBranchNoise read GetLeft;
  124. property Center: TgxTreeBranchNoise read GetCenter;
  125. property Right: TgxTreeBranchNoise read GetRight;
  126. property branchNoise: Single read FBranchNoise;
  127. end;
  128. TgxTree = class(TgxImmaterialSceneObject)
  129. private
  130. FDepth: Integer;
  131. FBranchFacets: Integer;
  132. FLeafSize: Single;
  133. FBranchSize: Single;
  134. FBranchNoise: Single;
  135. FBranchAngleBias: Single;
  136. FBranchAngle: Single;
  137. FBranchTwist: Single;
  138. FBranchRadius: Single;
  139. FLeafThreshold: Single;
  140. FCentralLeaderBias: Single;
  141. FCentralLeader: Boolean;
  142. FSeed: Integer;
  143. FAutoCenter: Boolean;
  144. FAutoRebuild: Boolean;
  145. FCenterBranchConstant: Single;
  146. FLeaves: TgxTreeLeaves;
  147. FBranches: TgxTreeBranches;
  148. FNoise: TgxTreeBranchNoise;
  149. FMaterialLibrary: TgxMaterialLibrary;
  150. FLeafMaterialName: TgxLibMaterialName;
  151. FLeafBackMaterialName: TgxLibMaterialName;
  152. FBranchMaterialName: TgxLibMaterialName;
  153. FRebuildTree: Boolean;
  154. FAxisAlignedDimensionsCache: TVector4f;
  155. protected
  156. procedure SetDepth(const Value: Integer);
  157. procedure SetBranchFacets(const Value: Integer);
  158. procedure SetLeafSize(const Value: Single);
  159. procedure SetBranchSize(const Value: Single);
  160. procedure SetBranchNoise(const Value: Single);
  161. procedure SetBranchAngleBias(const Value: Single);
  162. procedure SetBranchAngle(const Value: Single);
  163. procedure SetBranchTwist(const Value: Single);
  164. procedure SetBranchRadius(const Value: Single);
  165. procedure SetLeafThreshold(const Value: Single);
  166. procedure SetCentralLeaderBias(const Value: Single);
  167. procedure SetCentralLeader(const Value: Boolean);
  168. procedure SetSeed(const Value: Integer);
  169. procedure SetAutoCenter(const Value: Boolean);
  170. procedure SetAutoRebuild(const Value: Boolean);
  171. procedure SetCenterBranchConstant(const Value: Single);
  172. procedure SetMaterialLibrary(const Value: TgxMaterialLibrary);
  173. procedure SetLeafMaterialName(const Value: TgxLibMaterialName);
  174. procedure SetLeafBackMaterialName(const Value: TgxLibMaterialName);
  175. procedure SetBranchMaterialName(const Value: TgxLibMaterialName);
  176. procedure Loaded; override;
  177. public
  178. constructor Create(AOwner: TComponent); override;
  179. destructor Destroy; override;
  180. procedure Notification(AComponent: TComponent;
  181. Operation: TOperation); override;
  182. procedure DoRender(var ARci: TgxRenderContextInfo;
  183. ARenderSelf, ARenderChildren: Boolean); override;
  184. procedure BuildList(var rci: TgxRenderContextInfo); override;
  185. procedure StructureChanged; override;
  186. procedure BuildMesh(GLBaseMesh: TgxBaseMesh);
  187. procedure RebuildTree;
  188. procedure ForceTotalRebuild;
  189. procedure Clear;
  190. procedure GetExtents(var min, max: TAffineVector);
  191. function AxisAlignedDimensionsUnscaled: TVector4f; override;
  192. procedure LoadFromStream(aStream: TStream);
  193. procedure SaveToStream(aStream: TStream);
  194. procedure LoadFromFile(aFileName: String);
  195. procedure SaveToFile(aFileName: String);
  196. property Leaves: TgxTreeLeaves read FLeaves;
  197. property Branches: TgxTreeBranches read FBranches;
  198. property Noise: TgxTreeBranchNoise read FNoise;
  199. published
  200. // The depth of tree branch recursion.
  201. property Depth: Integer read FDepth write SetDepth;
  202. // The number of facets for each branch in the tree.
  203. property BranchFacets: Integer read FBranchFacets write SetBranchFacets;
  204. (* Leaf size modifier. Leaf size is also influenced by branch recursion
  205. scale. *)
  206. property LeafSize: Single read FLeafSize write SetLeafSize;
  207. // Branch length modifier.
  208. property BranchSize: Single read FBranchSize write SetBranchSize;
  209. (* Overall branch noise influence. Relates to the 'fullness' of the tree. *)
  210. property branchNoise: Single read FBranchNoise write SetBranchNoise;
  211. (* Effects the habit of the tree. Values from 0 to 1 refer to Upright to
  212. Spreading respectively. *)
  213. property BranchAngleBias: Single read FBranchAngleBias
  214. write SetBranchAngleBias;
  215. // Effects the balance of the tree.
  216. property BranchAngle: Single read FBranchAngle write SetBranchAngle;
  217. // Effects the rotation of each sub branch in recursion.
  218. property BranchTwist: Single read FBranchTwist write SetBranchTwist;
  219. // Effects the thickness of the branches.
  220. property BranchRadius: Single read FBranchRadius write SetBranchRadius;
  221. // Determines how thin a branch can get before a leaf is substituted.
  222. property LeafThreshold: Single read FLeafThreshold write SetLeafThreshold;
  223. (* Determines how BranchAngle effects the central leader
  224. (CentralLeader must = True). *)
  225. property CentralLeaderBias: Single read FCentralLeaderBias
  226. write SetCentralLeaderBias;
  227. // Does this tree have a central leader?
  228. property CentralLeader: Boolean read FCentralLeader write SetCentralLeader;
  229. property Seed: Integer read FSeed write SetSeed;
  230. // Automatically center the tree's vertices after building them.
  231. property AutoCenter: Boolean read FAutoCenter write SetAutoCenter;
  232. // Automatically rebuild the tree after changing the settings
  233. property AutoRebuild: Boolean read FAutoRebuild write SetAutoRebuild;
  234. (* Central branch can be thinner(lower values)/thicker(->1) depending on this constant.
  235. The effect also depends on the BranchAngle variable. *)
  236. property CenterBranchConstant: Single read FCenterBranchConstant
  237. write SetCenterBranchConstant;
  238. property MaterialLibrary: TgxMaterialLibrary read FMaterialLibrary
  239. write SetMaterialLibrary;
  240. property LeafMaterialName: TgxLibMaterialName read FLeafMaterialName
  241. write SetLeafMaterialName;
  242. property LeafBackMaterialName: TgxLibMaterialName read FLeafBackMaterialName
  243. write SetLeafBackMaterialName;
  244. property BranchMaterialName: TgxLibMaterialName read FBranchMaterialName
  245. write SetBranchMaterialName;
  246. end;
  247. //=========================================================================
  248. implementation
  249. //=========================================================================
  250. // ------------------------------------------------------------------------
  251. // TgxTreeLeaves
  252. // ------------------------------------------------------------------------
  253. constructor TgxTreeLeaves.Create(AOwner: TgxTree);
  254. begin
  255. FOwner := AOwner;
  256. FCount := 0;
  257. FVertices := TgxAffineVectorList.Create;
  258. FNormals := TgxAffineVectorList.Create;
  259. FTexCoords := TgxAffineVectorList.Create;
  260. end;
  261. destructor TgxTreeLeaves.Destroy;
  262. begin
  263. FVertices.Free;
  264. FNormals.Free;
  265. FTexCoords.Free;
  266. inherited;
  267. end;
  268. procedure TgxTreeLeaves.AddNew(matrix: TMatrix4f);
  269. var
  270. radius: Single;
  271. pos: TVector4f;
  272. begin
  273. radius := Owner.LeafSize;
  274. Inc(FCount);
  275. pos := matrix.W;
  276. matrix.W := NullHMGPoint;
  277. matrix := Roll(matrix, FCount / 10);
  278. NormalizeMatrix(matrix);
  279. matrix.W := pos;
  280. FVertices.Add(VectorTransform(PointMake(0, -radius, 0), matrix));
  281. FVertices.Add(VectorTransform(PointMake(0, radius, 0), matrix));
  282. FVertices.Add(VectorTransform(PointMake(0, radius, 2 * radius), matrix));
  283. FVertices.Add(VectorTransform(PointMake(0, -radius, 2 * radius), matrix));
  284. FNormals.Add(VectorTransform(XHmgVector, matrix));
  285. FTexCoords.Add(XVector, NullVector);
  286. FTexCoords.Add(YVector, XYVector);
  287. end;
  288. procedure TgxTreeLeaves.BuildList(var rci: TgxRenderContextInfo);
  289. var
  290. i: Integer;
  291. n: TAffineVector;
  292. libMat: TgxLibMaterial;
  293. begin
  294. libMat := Owner.MaterialLibrary.LibMaterialByName(Owner.LeafMaterialName);
  295. if Assigned(libMat) then
  296. libMat.Apply(rci);
  297. glEnableClientState(GL_VERTEX_ARRAY);
  298. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  299. glVertexPointer(3, GL_FLOAT, 0, @FVertices.List[0]);
  300. glTexCoordPointer(3, GL_FLOAT, 0, @FTexCoords.List[0]);
  301. for i := 0 to (FVertices.Count div 4) - 1 do
  302. begin
  303. glNormal3fv(@FNormals.List[i]);
  304. glDrawArrays(GL_QUADS, 4 * i, 4);
  305. end;
  306. with Owner do
  307. if LeafMaterialName <> LeafBackMaterialName then
  308. begin
  309. if Assigned(libMat) then
  310. libMat.UnApply(rci);
  311. libMat := MaterialLibrary.LibMaterialByName(LeafBackMaterialName);
  312. if Assigned(libMat) then
  313. libMat.Apply(rci);
  314. end;
  315. rci.gxStates.InvertFrontFace;
  316. for i := 0 to (FVertices.Count div 4) - 1 do
  317. begin
  318. n := VectorNegate(FNormals[i]);
  319. glNormal3fv(@n);
  320. glDrawArrays(GL_QUADS, 4 * i, 4);
  321. end;
  322. rci.gxStates.InvertFrontFace;
  323. glDisableClientState(GL_VERTEX_ARRAY);
  324. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  325. if Assigned(libMat) then
  326. libMat.UnApply(rci);
  327. end;
  328. procedure TgxTreeLeaves.Clear;
  329. begin
  330. FVertices.Clear;
  331. FNormals.Clear;
  332. FTexCoords.Clear;
  333. FCount := 0;
  334. end;
  335. // -----------------------------------------------------------------------------
  336. // TgxTreeBranch
  337. // -----------------------------------------------------------------------------
  338. constructor TgxTreeBranch.Create(AOwner: TgxTreeBranches;
  339. AParent: TgxTreeBranch);
  340. begin
  341. FOwner := AOwner;
  342. FParent := AParent;
  343. FUpper := TgxIntegerList.Create;
  344. FLower := TgxIntegerList.Create;
  345. FCentralLeader := False;
  346. // Skeletal construction helpers
  347. if Assigned(FOwner) then
  348. begin
  349. FBranchID := FOwner.Count - 1;
  350. FOwner.FBranchCache.Add(Self);
  351. end
  352. else
  353. FBranchID := -1;
  354. if Assigned(FParent) then
  355. FParentID := FParent.FBranchID
  356. else
  357. FParentID := -1;
  358. end;
  359. destructor TgxTreeBranch.Destroy;
  360. begin
  361. FUpper.Free;
  362. FLower.Free;
  363. FLeft.Free;
  364. FRight.Free;
  365. inherited;
  366. end;
  367. procedure TgxTreeBranch.BuildBranch(branchNoise: TgxTreeBranchNoise;
  368. const matrix: TMatrix4f; TexCoordY, Twist: Single; Level: Integer);
  369. var
  370. i: Integer;
  371. Tree: TgxTree;
  372. Branches: TgxTreeBranches;
  373. Facets: Integer;
  374. t, c, s: Single;
  375. radius, LeftRadius, RightRadius, CenterRadius: Single;
  376. BranchAngle, LeftAngle, RightAngle, CenterAngle: Single;
  377. BranchAngleBias, BranchTwist, Taper: Single;
  378. LeftBranchNoiseValue, RightBranchNoiseValue, CenterBranchNoiseValue: Single;
  379. LeftBranchNoise: TgxTreeBranchNoise;
  380. CenterBranchNoise: TgxTreeBranchNoise;
  381. RightBranchNoise: TgxTreeBranchNoise;
  382. LeftMatrix, RightMatrix, CenterMatrix: TMatrix4f;
  383. central_leader: Boolean;
  384. begin
  385. Assert(Assigned(FOwner), 'Incorrect use of TgxTreeBranch');
  386. Assert(Assigned(FOwner.FOwner), 'Incorrect use of TgxTreeBranches');
  387. FMatrix := matrix;
  388. Branches := FOwner;
  389. Tree := FOwner.FOwner;
  390. Facets := Tree.BranchFacets;
  391. radius := Tree.BranchRadius;
  392. FLower.Clear;
  393. FLower.Capacity := Facets + 1;
  394. FUpper.Clear;
  395. FUpper.Capacity := Facets + 1;
  396. BranchAngle := Tree.BranchAngle;
  397. BranchAngleBias := Tree.BranchAngleBias;
  398. BranchTwist := Twist + Tree.BranchTwist;
  399. LeftBranchNoise := branchNoise.Left;
  400. CenterBranchNoise := branchNoise.Center;
  401. RightBranchNoise := branchNoise.Right;
  402. LeftBranchNoiseValue := ((LeftBranchNoise.branchNoise * 0.4) - 0.1) *
  403. Tree.branchNoise;
  404. LeftRadius := Sqrt(1 - BranchAngle + LeftBranchNoiseValue);
  405. LeftRadius := ClampValue(LeftRadius, 0, 1);
  406. LeftAngle := BranchAngle * 90 * BranchAngleBias + 10 * LeftBranchNoiseValue;
  407. CenterBranchNoiseValue := ((CenterBranchNoise.branchNoise * 0.9) - 0.1) *
  408. Tree.branchNoise;
  409. CenterRadius := Sqrt(Tree.CenterBranchConstant - BranchAngle +
  410. CenterBranchNoiseValue);
  411. CenterRadius := ClampValue(CenterRadius, 0, 1);
  412. CenterAngle := (1 - BranchAngle) * 50 * CenterBranchNoiseValue *
  413. BranchAngleBias;
  414. RightBranchNoiseValue := ((RightBranchNoise.branchNoise * 0.6) - 0.1) *
  415. Tree.branchNoise;
  416. RightRadius := Sqrt(BranchAngle + RightBranchNoiseValue);
  417. RightRadius := ClampValue(RightRadius, 0, 1);
  418. RightAngle := (1 - BranchAngle) * -90 * BranchAngleBias + 10 *
  419. RightBranchNoiseValue;
  420. Taper := MaxFloat(LeftRadius, RightRadius, CenterRadius);
  421. // Build cylinder lower
  422. for i := 0 to Facets do
  423. begin
  424. t := 1 / Facets * i;
  425. c := Branches.CosList[i];
  426. s := Branches.SinList[i];
  427. Branches.Vertices.Add(VectorTransform(PointMake(c * radius, s * radius,
  428. radius), matrix));
  429. Branches.Normals.Add(VectorTransform(VectorMake(c, s, 0), matrix));
  430. Branches.TexCoords.Add(t, TexCoordY);
  431. FLower.Add(Branches.Vertices.Count - 1);
  432. Branches.FBranchIndices.Add(FBranchID);
  433. end;
  434. TexCoordY := TexCoordY + 1 - 2 * radius;
  435. // Build cylinder upper
  436. for i := 0 to Facets do
  437. begin
  438. t := 1 / Facets * i;
  439. c := Branches.CosList[i];
  440. s := Branches.SinList[i];
  441. Branches.Vertices.Add(VectorTransform(PointMake(c * radius * Taper,
  442. s * radius * Taper, 1 - radius), matrix));
  443. Branches.Normals.Add(VectorTransform(VectorMake(c, s, 0), matrix));
  444. Branches.TexCoords.Add(t, TexCoordY);
  445. FUpper.Add(Branches.Vertices.Count - 1);
  446. Branches.FBranchIndices.Add(FBranchID);
  447. end;
  448. TexCoordY := TexCoordY + 2 * radius;
  449. // BuildMatrices
  450. SinCosine(DegToRadian(BranchTwist), s, c);
  451. if Level = 0 then
  452. central_leader := FCentralLeader
  453. else
  454. central_leader := FParent.FCentralLeader;
  455. if central_leader then
  456. begin
  457. LeftMatrix := MatrixMultiply(CreateScaleMatrix(AffineVectorMake(LeftRadius,
  458. LeftRadius, LeftRadius)), CreateRotationMatrix(AffineVectorMake(s, c, 0),
  459. DegToRadian(LeftAngle) * Tree.CentralLeaderBias));
  460. end
  461. else
  462. begin
  463. LeftMatrix := MatrixMultiply(CreateScaleMatrix(AffineVectorMake(LeftRadius,
  464. LeftRadius, LeftRadius)), CreateRotationMatrix(AffineVectorMake(s, c, 0),
  465. DegToRadian(LeftAngle)));
  466. end;
  467. LeftMatrix := MatrixMultiply(LeftMatrix,
  468. MatrixMultiply(CreateTranslationMatrix(AffineVectorMake(0, 0,
  469. Tree.BranchSize * (1 - LeftBranchNoiseValue))), matrix));
  470. CenterMatrix := MatrixMultiply
  471. (CreateScaleMatrix(AffineVectorMake(CenterRadius, CenterRadius,
  472. CenterRadius)), CreateRotationMatrix(AffineVectorMake(s, c, 0),
  473. DegToRadian(CenterAngle)));
  474. CenterMatrix := MatrixMultiply(CenterMatrix,
  475. MatrixMultiply(CreateTranslationMatrix(AffineVectorMake(0, 0,
  476. Tree.BranchSize * (1 - CenterBranchNoiseValue))), matrix));
  477. RightMatrix := MatrixMultiply(CreateScaleMatrix(AffineVectorMake(RightRadius,
  478. RightRadius, RightRadius)), CreateRotationMatrix(AffineVectorMake(s, c, 0),
  479. DegToRadian(RightAngle)));
  480. RightMatrix := MatrixMultiply(RightMatrix,
  481. MatrixMultiply(CreateTranslationMatrix(AffineVectorMake(0, 0,
  482. Tree.BranchSize * (1 - RightBranchNoiseValue))), matrix));
  483. if (((Level + 1) >= Tree.Depth) or (LeftRadius < Tree.LeafThreshold)) then
  484. begin
  485. Tree.Leaves.AddNew(LeftMatrix);
  486. end
  487. else
  488. begin
  489. Inc(Branches.FCount);
  490. FLeft := TgxTreeBranch.Create(Owner, Self);
  491. FLeft.FCentralLeader := central_leader and (LeftRadius >= RightRadius);
  492. FLeft.BuildBranch(LeftBranchNoise, LeftMatrix, TexCoordY, BranchTwist,
  493. Level + 1);
  494. end;
  495. if (((Level + 1) >= Tree.Depth) or (CenterRadius < Tree.LeafThreshold)) then
  496. begin
  497. Tree.Leaves.AddNew(CenterMatrix);
  498. end
  499. else
  500. begin
  501. Inc(Branches.FCount);
  502. FCenter := TgxTreeBranch.Create(Owner, Self);
  503. FCenter.BuildBranch(CenterBranchNoise, CenterMatrix, TexCoordY, BranchTwist,
  504. Level + 1);
  505. end;
  506. if (((Level + 1) >= Tree.Depth) or (RightRadius < Tree.LeafThreshold)) then
  507. begin
  508. Tree.Leaves.AddNew(RightMatrix);
  509. end
  510. else
  511. begin
  512. Inc(Branches.FCount);
  513. FRight := TgxTreeBranch.Create(Owner, Self);
  514. FRight.BuildBranch(RightBranchNoise, RightMatrix, TexCoordY, BranchTwist,
  515. Level + 1);
  516. end;
  517. for i := 0 to Facets do
  518. begin
  519. Branches.FIndices.Add(Upper[i]);
  520. Branches.FIndices.Add(Lower[i]);
  521. end;
  522. if Assigned(FRight) then
  523. begin
  524. for i := 0 to Facets do
  525. begin
  526. Branches.FIndices.Add(Right.Lower[i]);
  527. Branches.FIndices.Add(Upper[i]);
  528. end;
  529. end;
  530. if Assigned(FCenter) then
  531. begin
  532. for i := 0 to Facets do
  533. begin
  534. Branches.FIndices.Add(Center.Lower[i]);
  535. Branches.FIndices.Add(Upper[i]);
  536. end;
  537. end;
  538. if Assigned(FLeft) then
  539. begin
  540. for i := 0 to Facets do
  541. begin
  542. Branches.FIndices.Add(Left.Lower[i]);
  543. Branches.FIndices.Add(Upper[i]);
  544. end;
  545. end;
  546. end;
  547. // -----------------------------------------------------------------------------
  548. // TgxTreeBranches
  549. // -----------------------------------------------------------------------------
  550. constructor TgxTreeBranches.Create(AOwner: TgxTree);
  551. begin
  552. FOwner := AOwner;
  553. FSinList := TgxSingleList.Create;
  554. FCosList := TgxSingleList.Create;
  555. FVertices := TgxAffineVectorList.Create;
  556. FNormals := TgxAffineVectorList.Create;
  557. FTexCoords := TgxAffineVectorList.Create;
  558. FIndices := TgxIntegerList.Create;
  559. FBranchCache := TList.Create;
  560. FBranchIndices := TgxIntegerList.Create;
  561. FCount := 0;
  562. end;
  563. destructor TgxTreeBranches.Destroy;
  564. begin
  565. FSinList.Free;
  566. FCosList.Free;
  567. FVertices.Free;
  568. FNormals.Free;
  569. FTexCoords.Free;
  570. FIndices.Free;
  571. FRoot.Free;
  572. FBranchCache.Free;
  573. FBranchIndices.Free;
  574. inherited;
  575. end;
  576. procedure TgxTreeBranches.BuildBranches;
  577. var
  578. i: Integer;
  579. u: Single;
  580. delta, min, max: TAffineVector;
  581. begin
  582. RandSeed := Owner.FSeed;
  583. for i := 0 to Owner.BranchFacets do
  584. begin
  585. u := 1 / Owner.BranchFacets * i;
  586. SinList.Add(Sin(PI * 2 * u));
  587. CosList.Add(Cos(PI * 2 * u));
  588. end;
  589. Inc(FCount);
  590. FRoot := TgxTreeBranch.Create(Self, nil);
  591. FRoot.FCentralLeader := Owner.CentralLeader;
  592. FRoot.BuildBranch(Owner.Noise, IdentityHMGMatrix, 0, 0, 0);
  593. delta := AffineVectorMake(0, 0, -Owner.BranchRadius);
  594. Vertices.Translate(delta);
  595. Owner.Leaves.Vertices.Translate(delta);
  596. if Owner.AutoCenter then
  597. begin
  598. Owner.GetExtents(min, max);
  599. delta := VectorCombine(min, max, -0.5, -0.5);
  600. Vertices.Translate(delta);
  601. Owner.Leaves.Vertices.Translate(delta);
  602. end;
  603. Owner.FAxisAlignedDimensionsCache.X := -1;
  604. end;
  605. procedure TgxTreeBranches.BuildList(var rci: TgxRenderContextInfo);
  606. var
  607. i, stride: Integer;
  608. libMat: TgxLibMaterial;
  609. begin
  610. stride := (Owner.BranchFacets + 1) * 2;
  611. libMat := Owner.MaterialLibrary.LibMaterialByName(Owner.BranchMaterialName);
  612. if Assigned(libMat) then
  613. libMat.Apply(rci);
  614. glVertexPointer(3, GL_FLOAT, 0, @FVertices.List[0]);
  615. glNormalPointer(GL_FLOAT, 0, @FNormals.List[0]);
  616. glTexCoordPointer(3, GL_FLOAT, 0, @FTexCoords.List[0]);
  617. glEnableClientState(GL_VERTEX_ARRAY);
  618. glEnableClientState(GL_NORMAL_ARRAY);
  619. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  620. repeat
  621. for i := 0 to (FIndices.Count div stride) - 1 do
  622. glDrawElements(GL_TRIANGLE_STRIP, stride, GL_UNSIGNED_INT,
  623. @FIndices.List[stride * i]);
  624. until (not Assigned(libMat)) or (not libMat.UnApply(rci));
  625. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  626. glDisableClientState(GL_NORMAL_ARRAY);
  627. glDisableClientState(GL_VERTEX_ARRAY);
  628. end;
  629. procedure TgxTreeBranches.Clear;
  630. begin
  631. FSinList.Clear;
  632. FCosList.Clear;
  633. FVertices.Clear;
  634. FNormals.Clear;
  635. FTexCoords.Clear;
  636. FIndices.Clear;
  637. FBranchCache.Clear;
  638. FBranchIndices.Clear;
  639. FreeAndNil(FRoot);
  640. FCount := 0;
  641. end;
  642. // -----------------------------------------------------------------------------
  643. // TgxTreeBranchNoise
  644. // -----------------------------------------------------------------------------
  645. constructor TgxTreeBranchNoise.Create;
  646. begin
  647. FBranchNoise := Random;
  648. end;
  649. destructor TgxTreeBranchNoise.Destroy;
  650. begin
  651. FLeft.Free;
  652. FRight.Free;
  653. inherited;
  654. end;
  655. function TgxTreeBranchNoise.GetLeft: TgxTreeBranchNoise;
  656. begin
  657. if not Assigned(FLeft) then
  658. FLeft := TgxTreeBranchNoise.Create;
  659. Result := FLeft;
  660. end;
  661. function TgxTreeBranchNoise.GetRight: TgxTreeBranchNoise;
  662. begin
  663. if not Assigned(FRight) then
  664. FRight := TgxTreeBranchNoise.Create;
  665. Result := FRight;
  666. end;
  667. function TgxTreeBranchNoise.GetCenter: TgxTreeBranchNoise;
  668. begin
  669. if not Assigned(FCenter) then
  670. FCenter := TgxTreeBranchNoise.Create;
  671. Result := FCenter;
  672. end;
  673. // -----------------------------------------------------------------------------
  674. // TgxTree
  675. // -----------------------------------------------------------------------------
  676. constructor TgxTree.Create(AOwner: TComponent);
  677. begin
  678. inherited;
  679. // Default tree setting
  680. FDepth := 5;
  681. FLeafThreshold := 0.02;
  682. FBranchAngleBias := 0.6;
  683. FBranchAngle := 0.4;
  684. FBranchTwist := 45;
  685. FBranchNoise := 0.7;
  686. FBranchSize := 1.0;
  687. FLeafSize := 0.1;
  688. FBranchRadius := 0.12;
  689. FBranchFacets := 6;
  690. FCentralLeader := False;
  691. FSeed := 0;
  692. FAutoCenter := False;
  693. FAutoRebuild := True;
  694. FCenterBranchConstant := 0.5;
  695. FLeaves := TgxTreeLeaves.Create(Self);
  696. FBranches := TgxTreeBranches.Create(Self);
  697. FNoise := TgxTreeBranchNoise.Create;
  698. end;
  699. destructor TgxTree.Destroy;
  700. begin
  701. FLeaves.Free;
  702. FBranches.Free;
  703. FNoise.Free;
  704. inherited;
  705. end;
  706. procedure TgxTree.Loaded;
  707. begin
  708. inherited;
  709. FBranches.BuildBranches;
  710. end;
  711. procedure TgxTree.Notification(AComponent: TComponent; Operation: TOperation);
  712. begin
  713. if (Operation = opRemove) and (AComponent = FMaterialLibrary) then
  714. MaterialLibrary := nil;
  715. inherited;
  716. end;
  717. procedure TgxTree.DoRender(var ARci: TgxRenderContextInfo;
  718. ARenderSelf, ARenderChildren: Boolean);
  719. begin
  720. MaterialLibrary.LibMaterialByName(BranchMaterialName).PrepareBuildList;
  721. MaterialLibrary.LibMaterialByName(LeafMaterialName).PrepareBuildList;
  722. MaterialLibrary.LibMaterialByName(LeafBackMaterialName).PrepareBuildList;
  723. inherited;
  724. end;
  725. procedure TgxTree.BuildList(var rci: TgxRenderContextInfo);
  726. begin
  727. if FRebuildTree then
  728. begin
  729. FBranches.BuildBranches;
  730. FRebuildTree := False;
  731. end;
  732. Branches.BuildList(rci);
  733. Leaves.BuildList(rci);
  734. end;
  735. procedure TgxTree.StructureChanged;
  736. begin
  737. FAxisAlignedDimensionsCache.X := -1;
  738. inherited;
  739. end;
  740. procedure TgxTree.BuildMesh(GLBaseMesh: TgxBaseMesh);
  741. procedure RecursBranches(Branch: TgxTreeBranch; bone: TgxSkeletonBone;
  742. Frame: TgxSkeletonFrame);
  743. var
  744. trans: TTransformations;
  745. mat: TMatrix4f;
  746. rot, pos: TAffineVector;
  747. begin
  748. bone.Name := 'Branch' + IntToStr(Branch.FBranchID);
  749. bone.BoneID := Branch.FBranchID;
  750. // Construct base frame
  751. if Assigned(Branch.FParent) then
  752. mat := Branch.FParent.FMatrix
  753. else
  754. mat := IdentityHMGMatrix;
  755. InvertMatrix(mat);
  756. NormalizeMatrix(mat);
  757. if MatrixDecompose(mat, trans) then
  758. begin
  759. SetVector(rot, trans[ttRotateX], trans[ttRotateY], trans[ttRotateZ]);
  760. SetVector(pos, mat.W);
  761. end
  762. else
  763. begin
  764. rot := NullVector;
  765. pos := NullVector;
  766. end;
  767. Frame.Rotation.Add(rot);
  768. Frame.Position.Add(pos);
  769. // Recurse with child branches
  770. if Assigned(Branch.Left) then
  771. RecursBranches(Branch.Left, TgxSkeletonBone.CreateOwned(bone), Frame);
  772. if Assigned(Branch.Right) then
  773. RecursBranches(Branch.Right, TgxSkeletonBone.CreateOwned(bone), Frame);
  774. end;
  775. var
  776. // SkelMesh : TgxSkeletonMeshObject;
  777. fg: TgxFGVertexIndexList;
  778. fg2: TFGVertexNormalTexIndexList;
  779. i, j, stride: Integer;
  780. // parent_id : integer;
  781. // bone : TgxSkeletonBone;
  782. begin
  783. if not Assigned(GLBaseMesh) then
  784. exit;
  785. if FRebuildTree then
  786. begin
  787. FBranches.BuildBranches;
  788. FRebuildTree := False;
  789. end;
  790. GLBaseMesh.MeshObjects.Clear;
  791. GLBaseMesh.Skeleton.Clear;
  792. // if GLBaseMesh is TgxActor then
  793. // TgxSkeletonMeshObject.CreateOwned(GLBaseMesh.MeshObjects)
  794. // else
  795. TgxMeshObject.CreateOwned(GLBaseMesh.MeshObjects);
  796. GLBaseMesh.MeshObjects[0].Mode := momFaceGroups;
  797. // Branches
  798. GLBaseMesh.MeshObjects[0].Vertices.Add(Branches.Vertices);
  799. GLBaseMesh.MeshObjects[0].Normals.Add(Branches.Normals);
  800. GLBaseMesh.MeshObjects[0].TexCoords.Add(Branches.TexCoords);
  801. { if GLBaseMesh is TgxActor then begin
  802. TgxActor(GLBaseMesh).Reference:=aarSkeleton;
  803. RecursBranches(Branches.FRoot,
  804. TgxSkeletonBone.CreateOwned(GLBaseMesh.Skeleton.RootBones),
  805. TgxSkeletonFrame.CreateOwned(GLBaseMesh.Skeleton.Frames));
  806. SkelMesh:=TgxSkeletonMeshObject(GLBaseMesh.MeshObjects[0]);
  807. SkelMesh.BonesPerVertex:=1;
  808. SkelMesh.VerticeBoneWeightCount:=Branches.FBranchIndices.Count;
  809. for i:=0 to Branches.FBranchIndices.Count-1 do
  810. SkelMesh.AddWeightedBone(Branches.FBranchIndices[i],1);
  811. GLBaseMesh.Skeleton.RootBones.PrepareGlobalMatrices;
  812. SkelMesh.PrepareBoneMatrixInvertedMeshes;
  813. SkelMesh.ApplyCurrentSkeletonFrame(True);
  814. end;// }
  815. stride := (BranchFacets + 1) * 2;
  816. for i := 0 to (FBranches.FIndices.Count div stride) - 1 do
  817. begin
  818. fg := TgxFGVertexIndexList.CreateOwned(GLBaseMesh.MeshObjects[0].FaceGroups);
  819. fg.MaterialName := BranchMaterialName;
  820. fg.Mode := fgmmTriangleStrip;
  821. for j := 0 to stride - 1 do
  822. fg.VertexIndices.Add(Branches.FIndices[i * stride + j]);
  823. end;
  824. // Leaves
  825. // if GLBaseMesh is TgxActor then
  826. // TgxSkeletonMeshObject.CreateOwned(GLBaseMesh.MeshObjects)
  827. // else
  828. TgxMeshObject.CreateOwned(GLBaseMesh.MeshObjects);
  829. GLBaseMesh.MeshObjects[1].Mode := momFaceGroups;
  830. GLBaseMesh.MeshObjects[1].Vertices.Add(Leaves.Vertices);
  831. GLBaseMesh.MeshObjects[1].Normals.Add(Leaves.FNormals);
  832. for i := 0 to Leaves.Normals.Count - 1 do
  833. GLBaseMesh.MeshObjects[1].Normals.Add(VectorNegate(Leaves.FNormals[i]));
  834. GLBaseMesh.MeshObjects[1].TexCoords.Add(Leaves.TexCoords);
  835. for i := 0 to (Leaves.FVertices.Count div 4) - 1 do
  836. begin
  837. // Leaf front
  838. fg2 := TFGVertexNormalTexIndexList.CreateOwned
  839. (GLBaseMesh.MeshObjects[1].FaceGroups);
  840. fg2.MaterialName := LeafMaterialName;
  841. fg2.Mode := fgmmTriangleStrip;
  842. with fg2.VertexIndices do
  843. begin
  844. Add(i * 4);
  845. Add(i * 4 + 1);
  846. Add(i * 4 + 3);
  847. Add(i * 4 + 2);
  848. end;
  849. for j := 0 to 3 do
  850. fg2.NormalIndices.Add(i);
  851. with fg2.TexCoordIndices do
  852. begin
  853. Add(0);
  854. Add(1);
  855. Add(3);
  856. Add(2);
  857. end;
  858. // Leaf back
  859. fg2 := TFGVertexNormalTexIndexList.CreateOwned
  860. (GLBaseMesh.MeshObjects[1].FaceGroups);
  861. fg2.MaterialName := LeafBackMaterialName;
  862. fg2.Mode := fgmmTriangleStrip;
  863. with fg2.VertexIndices do
  864. begin
  865. Add(i * 4);
  866. Add(i * 4 + 3);
  867. Add(i * 4 + 1);
  868. Add(i * 4 + 2);
  869. end;
  870. for j := 0 to 3 do
  871. fg2.NormalIndices.Add(i);
  872. with fg2.TexCoordIndices do
  873. begin
  874. Add(0);
  875. Add(3);
  876. Add(1);
  877. Add(2);
  878. end;
  879. end;
  880. end;
  881. procedure TgxTree.Clear;
  882. begin
  883. FLeaves.Clear;
  884. FBranches.Clear;
  885. end;
  886. procedure TgxTree.SetBranchAngle(const Value: Single);
  887. begin
  888. if Value <> FBranchAngle then
  889. begin
  890. FBranchAngle := Value;
  891. if (FAutoRebuild) then
  892. RebuildTree;
  893. end;
  894. end;
  895. procedure TgxTree.SetBranchAngleBias(const Value: Single);
  896. begin
  897. if Value <> FBranchAngleBias then
  898. begin
  899. FBranchAngleBias := Value;
  900. if (FAutoRebuild) then
  901. RebuildTree;
  902. end;
  903. end;
  904. procedure TgxTree.SetBranchNoise(const Value: Single);
  905. begin
  906. if Value <> FBranchNoise then
  907. begin
  908. FBranchNoise := Value;
  909. if (FAutoRebuild) then
  910. RebuildTree;
  911. end;
  912. end;
  913. procedure TgxTree.SetBranchRadius(const Value: Single);
  914. begin
  915. if Value <> FBranchRadius then
  916. begin
  917. FBranchRadius := Value;
  918. if (FAutoRebuild) then
  919. RebuildTree;
  920. end;
  921. end;
  922. procedure TgxTree.SetBranchSize(const Value: Single);
  923. begin
  924. if Value <> FBranchSize then
  925. begin
  926. FBranchSize := Value;
  927. if (FAutoRebuild) then
  928. RebuildTree;
  929. end;
  930. end;
  931. procedure TgxTree.SetBranchTwist(const Value: Single);
  932. begin
  933. if Value <> FBranchTwist then
  934. begin
  935. FBranchTwist := Value;
  936. if (FAutoRebuild) then
  937. RebuildTree;
  938. end;
  939. end;
  940. procedure TgxTree.SetDepth(const Value: Integer);
  941. begin
  942. if Value <> FDepth then
  943. begin
  944. FDepth := Value;
  945. if (FAutoRebuild) then
  946. RebuildTree;
  947. end;
  948. end;
  949. procedure TgxTree.SetBranchFacets(const Value: Integer);
  950. begin
  951. if Value <> FBranchFacets then
  952. begin
  953. FBranchFacets := Value;
  954. if (FAutoRebuild) then
  955. RebuildTree;
  956. end;
  957. end;
  958. procedure TgxTree.SetLeafSize(const Value: Single);
  959. begin
  960. if Value <> FLeafSize then
  961. begin
  962. FLeafSize := Value;
  963. if (FAutoRebuild) then
  964. RebuildTree;
  965. end;
  966. end;
  967. procedure TgxTree.SetLeafThreshold(const Value: Single);
  968. begin
  969. if Value <> FLeafThreshold then
  970. begin
  971. FLeafThreshold := Value;
  972. if (FAutoRebuild) then
  973. RebuildTree;
  974. end;
  975. end;
  976. procedure TgxTree.SetCentralLeaderBias(const Value: Single);
  977. begin
  978. if Value <> FCentralLeaderBias then
  979. begin
  980. FCentralLeaderBias := Value;
  981. if (FAutoRebuild) then
  982. RebuildTree;
  983. end;
  984. end;
  985. procedure TgxTree.SetCentralLeader(const Value: Boolean);
  986. begin
  987. if Value <> FCentralLeader then
  988. begin
  989. FCentralLeader := Value;
  990. if (FAutoRebuild) then
  991. RebuildTree;
  992. end;
  993. end;
  994. procedure TgxTree.SetSeed(const Value: Integer);
  995. begin
  996. if Value <> FSeed then
  997. begin
  998. FSeed := Value;
  999. if (FAutoRebuild) then
  1000. ForceTotalRebuild;
  1001. end;
  1002. end;
  1003. procedure TgxTree.SetCenterBranchConstant(const Value: Single);
  1004. begin
  1005. if Value <> CenterBranchConstant then
  1006. begin
  1007. FCenterBranchConstant := Value;
  1008. if (FAutoRebuild) then
  1009. ForceTotalRebuild;
  1010. end;
  1011. end;
  1012. procedure TgxTree.SetBranchMaterialName(const Value: TgxLibMaterialName);
  1013. begin
  1014. if Value <> FBranchMaterialName then
  1015. begin
  1016. FBranchMaterialName := Value;
  1017. StructureChanged;
  1018. end;
  1019. end;
  1020. procedure TgxTree.SetLeafBackMaterialName(const Value: TgxLibMaterialName);
  1021. begin
  1022. if Value <> FLeafBackMaterialName then
  1023. begin
  1024. FLeafBackMaterialName := Value;
  1025. StructureChanged;
  1026. end;
  1027. end;
  1028. procedure TgxTree.SetLeafMaterialName(const Value: TgxLibMaterialName);
  1029. begin
  1030. if Value <> FLeafMaterialName then
  1031. begin
  1032. FLeafMaterialName := Value;
  1033. StructureChanged;
  1034. end;
  1035. end;
  1036. procedure TgxTree.SetMaterialLibrary(const Value: TgxMaterialLibrary);
  1037. begin
  1038. if Value <> FMaterialLibrary then
  1039. begin
  1040. FMaterialLibrary := Value;
  1041. StructureChanged;
  1042. end;
  1043. end;
  1044. procedure TgxTree.RebuildTree;
  1045. begin
  1046. if not FRebuildTree then
  1047. begin
  1048. Clear;
  1049. FRebuildTree := True;
  1050. StructureChanged;
  1051. end;
  1052. end;
  1053. procedure TgxTree.ForceTotalRebuild;
  1054. begin
  1055. Clear;
  1056. FNoise.Free;
  1057. RandSeed := FSeed;
  1058. FNoise := TgxTreeBranchNoise.Create;
  1059. FRebuildTree := False;
  1060. FBranches.BuildBranches;
  1061. StructureChanged;
  1062. end;
  1063. procedure TgxTree.LoadFromStream(aStream: TStream);
  1064. var
  1065. StrList, StrParse: TStringList;
  1066. str: String;
  1067. i: Integer;
  1068. begin
  1069. StrList := TStringList.Create;
  1070. StrParse := TStringList.Create;
  1071. StrList.LoadFromStream(aStream);
  1072. try
  1073. for i := 0 to StrList.Count - 1 do
  1074. begin
  1075. str := StrList[i];
  1076. if pos('#', str) > 0 then
  1077. str := Copy(str, 0, pos('#', str) - 1);
  1078. StrParse.CommaText := str;
  1079. if StrParse.Count >= 2 then
  1080. begin
  1081. str := LowerCase(StrParse[0]);
  1082. if str = 'depth' then
  1083. FDepth := StrToInt(StrParse[1])
  1084. else if str = 'branch_facets' then
  1085. FBranchFacets := StrToInt(StrParse[1])
  1086. else if str = 'leaf_size' then
  1087. FLeafSize := StrToFloat(StrParse[1])
  1088. else if str = 'branch_size' then
  1089. FBranchSize := StrToFloat(StrParse[1])
  1090. else if str = 'branch_noise' then
  1091. FBranchNoise := StrToFloat(StrParse[1])
  1092. else if str = 'branch_angle_bias' then
  1093. FBranchAngleBias := StrToFloat(StrParse[1])
  1094. else if str = 'branch_angle' then
  1095. FBranchAngle := StrToFloat(StrParse[1])
  1096. else if str = 'branch_twist' then
  1097. FBranchTwist := StrToFloat(StrParse[1])
  1098. else if str = 'branch_radius' then
  1099. FBranchRadius := StrToFloat(StrParse[1])
  1100. else if str = 'leaf_threshold' then
  1101. FLeafThreshold := StrToFloat(StrParse[1])
  1102. else if str = 'central_leader_bias' then
  1103. FCentralLeaderBias := StrToFloat(StrParse[1])
  1104. else if str = 'central_leader' then
  1105. FCentralLeader := LowerCase(StrParse[1]) = 'true'
  1106. else if str = 'seed' then
  1107. FSeed := StrToInt(StrParse[1])
  1108. else if str = 'leaf_front_material_name' then
  1109. FLeafMaterialName := StrParse[1]
  1110. else if str = 'leaf_back_material_name' then
  1111. FLeafBackMaterialName := StrParse[1]
  1112. else if str = 'branch_material_name' then
  1113. FBranchMaterialName := StrParse[1];
  1114. end;
  1115. end;
  1116. ForceTotalRebuild;
  1117. finally
  1118. StrList.Free;
  1119. StrParse.Free;
  1120. end;
  1121. end;
  1122. procedure TgxTree.SaveToStream(aStream: TStream);
  1123. var
  1124. StrList: TStringList;
  1125. begin
  1126. StrList := TStringList.Create;
  1127. StrList.Add(Format('depth, %d', [Depth]));
  1128. StrList.Add(Format('branch_facets, %d', [BranchFacets]));
  1129. StrList.Add(Format('leaf_size, %f', [LeafSize]));
  1130. StrList.Add(Format('branch_size, %f', [BranchSize]));
  1131. StrList.Add(Format('branch_noise, %f', [branchNoise]));
  1132. StrList.Add(Format('branch_angle_bias, %f', [BranchAngleBias]));
  1133. StrList.Add(Format('branch_angle, %f', [BranchAngle]));
  1134. StrList.Add(Format('branch_twist, %f', [BranchTwist]));
  1135. StrList.Add(Format('branch_radius, %f', [BranchRadius]));
  1136. StrList.Add(Format('leaf_threshold, %f', [LeafThreshold]));
  1137. StrList.Add(Format('central_leader_bias, %f', [CentralLeaderBias]));
  1138. if CentralLeader then
  1139. StrList.Add('central_leader, true')
  1140. else
  1141. StrList.Add('central_leader, false');
  1142. StrList.Add(Format('seed, %d', [Seed]));
  1143. StrList.Add('leaf_front_material_name, "' + LeafMaterialName + '"');
  1144. StrList.Add('leaf_back_material_name, "' + LeafBackMaterialName + '"');
  1145. StrList.Add('branch_material_name, "' + BranchMaterialName + '"');
  1146. StrList.SaveToStream(aStream);
  1147. StrList.Free;
  1148. end;
  1149. procedure TgxTree.LoadFromFile(aFileName: String);
  1150. var
  1151. stream: TStream;
  1152. begin
  1153. stream := TFileStream.Create(aFileName, fmOpenRead);
  1154. try
  1155. LoadFromStream(stream);
  1156. finally
  1157. stream.Free;
  1158. end;
  1159. end;
  1160. procedure TgxTree.SaveToFile(aFileName: String);
  1161. var
  1162. stream: TStream;
  1163. begin
  1164. stream := TFileStream.Create(aFileName, fmCreate);
  1165. try
  1166. SaveToStream(stream);
  1167. finally
  1168. stream.Free;
  1169. end;
  1170. end;
  1171. procedure TgxTree.GetExtents(var min, max: TAffineVector);
  1172. var
  1173. lmin, lmax, bmin, bmax: TAffineVector;
  1174. begin
  1175. if Branches.Vertices.Count = 0 then
  1176. begin
  1177. FBranches.BuildBranches;
  1178. FRebuildTree := False;
  1179. end;
  1180. if Leaves.Vertices.Count > 0 then
  1181. Leaves.Vertices.GetExtents(lmin, lmax)
  1182. else
  1183. begin
  1184. lmin := NullVector;
  1185. lmax := NullVector;
  1186. end;
  1187. if Branches.Vertices.Count > 0 then
  1188. Branches.Vertices.GetExtents(bmin, bmax)
  1189. else
  1190. begin
  1191. bmin := NullVector;
  1192. bmax := NullVector;
  1193. end;
  1194. min.X := MinFloat([lmin.X, lmax.X, bmin.X, bmax.X]);
  1195. min.Y := MinFloat([lmin.Y, lmax.Y, bmin.Y, bmax.Y]);
  1196. min.Z := MinFloat([lmin.Z, lmax.Z, bmin.Z, bmax.Z]);
  1197. max.X := MaxFloat([lmin.X, lmax.X, bmin.X, bmax.X]);
  1198. max.Y := MaxFloat([lmin.Y, lmax.Y, bmin.Y, bmax.Y]);
  1199. max.Z := MaxFloat([lmin.Z, lmax.Z, bmin.Z, bmax.Z]);
  1200. end;
  1201. function TgxTree.AxisAlignedDimensionsUnscaled: TVector4f;
  1202. var
  1203. dMin, dMax: TAffineVector;
  1204. begin
  1205. if FAxisAlignedDimensionsCache.X < 0 then
  1206. begin
  1207. GetExtents(dMin, dMax);
  1208. FAxisAlignedDimensionsCache.X := MaxFloat(Abs(dMin.X), Abs(dMax.X));
  1209. FAxisAlignedDimensionsCache.Y := MaxFloat(Abs(dMin.Y), Abs(dMax.Y));
  1210. FAxisAlignedDimensionsCache.Z := MaxFloat(Abs(dMin.Z), Abs(dMax.Z));
  1211. end;
  1212. SetVector(Result, FAxisAlignedDimensionsCache);
  1213. end;
  1214. procedure TgxTree.SetAutoCenter(const Value: Boolean);
  1215. begin
  1216. if Value <> FAutoCenter then
  1217. begin
  1218. FAutoCenter := Value;
  1219. if (FAutoRebuild) then
  1220. RebuildTree;
  1221. end;
  1222. end;
  1223. procedure TgxTree.SetAutoRebuild(const Value: Boolean);
  1224. begin
  1225. if Value <> FAutoRebuild then
  1226. begin
  1227. FAutoRebuild := Value;
  1228. end;
  1229. end;
  1230. //-----------------------------------------------------
  1231. initialization
  1232. //-----------------------------------------------------
  1233. RegisterClasses([TgxTree]);
  1234. end.