GXS.Graph.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.Graph;
  5. (* Graph plotting objects for Scene *)
  6. interface
  7. {$I Stage.Defines.inc}
  8. uses
  9. System.Classes,
  10. System.SysUtils,
  11. Stage.OpenGL4,
  12. GXS.XOpenGL,
  13. GXS.Scene,
  14. GXS.Context,
  15. Stage.VectorGeometry,
  16. GXS.Material,
  17. GXS.Objects,
  18. GXS.VectorLists,
  19. GXS.Color,
  20. GXS.BaseClasses,
  21. GXS.RenderContextInfo,
  22. GXS.State,
  23. Stage.VectorTypes;
  24. type
  25. TgxSamplingScale = class(TgxUpdateAbleObject)
  26. private
  27. FMin: Single;
  28. FMax: Single;
  29. FOrigin: Single;
  30. FStep: Single;
  31. protected
  32. procedure SetMin(const val: Single);
  33. procedure SetMax(const val: Single);
  34. procedure SetOrigin(const val: Single);
  35. procedure SetStep(const val: Single);
  36. public
  37. constructor Create(AOwner: TPersistent); override;
  38. destructor Destroy; override;
  39. procedure Assign(Source: TPersistent); override;
  40. { Returns the Base value for Step browsing.
  41. ie. the lowest value (superior to Min) that verifies
  42. Frac((Origin-StepBase)/Step)=0.0, this value may be superior to Max. }
  43. function StepBase: Single;
  44. { Maximum number of steps that can occur between Min and Max. }
  45. function MaxStepCount: Integer;
  46. function IsValid: Boolean;
  47. procedure SetBaseStepMaxToVars(var Base, Step, Max: Single;
  48. SamplingEnabled: Boolean = True);
  49. published
  50. property Min: Single read FMin write SetMin;
  51. property Max: Single read FMax write SetMax;
  52. property Origin: Single read FOrigin write SetOrigin;
  53. property Step: Single read FStep write SetStep;
  54. end;
  55. TgxHeightFieldGetHeightEvent = procedure(const x, y: Single; var z: Single;
  56. var Color: TgxColorVector; var TexPoint: TTexPoint) of object;
  57. TgxHeightFieldGetHeight2Event = procedure(Sender: TObject; const x, y: Single;
  58. var z: Single; var Color: TgxColorVector; var TexPoint: TTexPoint) of object;
  59. TgxHeightFieldOption = (hfoTextureCoordinates, hfoTwoSided);
  60. TgxHeightFieldOptions = set of TgxHeightFieldOption;
  61. TgxHeightFieldColorMode = (hfcmNone, hfcmEmission, hfcmAmbient, hfcmDiffuse,
  62. hfcmAmbientAndDiffuse);
  63. { Renders a sampled height-field.
  64. HeightFields are used to materialize z=f(x, y) surfaces, you can use it to
  65. render anything from math formulas to statistics. Most important properties
  66. of an height field are its sampling scales (X & Y) that determine the extents
  67. and the resolution of the base grid.
  68. The component will then invoke it OnGetHeight event to retrieve Z values for
  69. all of the grid points (values are retrieved only once for each point). Each
  70. point may have an additionnal color and texture coordinate. }
  71. TgxHeightField = class(TgxSceneObject)
  72. private
  73. FOnGetHeight: TgxHeightFieldGetHeightEvent;
  74. FOnGetHeight2: TgxHeightFieldGetHeight2Event;
  75. FXSamplingScale: TgxSamplingScale;
  76. FYSamplingScale: TgxSamplingScale;
  77. FOptions: TgxHeightFieldOptions;
  78. FTriangleCount: Integer;
  79. FColorMode: TgxHeightFieldColorMode;
  80. protected
  81. procedure SetXSamplingScale(const val: TgxSamplingScale);
  82. procedure SetYSamplingScale(const val: TgxSamplingScale);
  83. procedure SetOptions(const val: TgxHeightFieldOptions);
  84. procedure SetOnGetHeight(const val: TgxHeightFieldGetHeightEvent);
  85. procedure SetOnGetHeight2(const val: TgxHeightFieldGetHeight2Event);
  86. procedure SetColorMode(const val: TgxHeightFieldColorMode);
  87. procedure DefaultHeightField(const x, y: Single; var z: Single;
  88. var Color: TgxColorVector; var TexPoint: TTexPoint);
  89. procedure Height2Field(const x, y: Single; var z: Single;
  90. var Color: TgxColorVector; var texPoint: TTexPoint);
  91. public
  92. constructor Create(AOwner: TComponent); override;
  93. destructor Destroy; override;
  94. procedure Assign(Source: TPersistent); override;
  95. procedure BuildList(var rci: TgxRenderContextInfo); override;
  96. procedure NotifyChange(Sender: TObject); override;
  97. property TriangleCount: Integer read FTriangleCount;
  98. published
  99. property XSamplingScale: TgxSamplingScale read FXSamplingScale
  100. write SetXSamplingScale;
  101. property YSamplingScale: TgxSamplingScale read FYSamplingScale
  102. write SetYSamplingScale;
  103. { Define if and how per vertex color is used. }
  104. property ColorMode: TgxHeightFieldColorMode read FColorMode write SetColorMode
  105. default hfcmNone;
  106. property Options: TgxHeightFieldOptions read FOptions write SetOptions
  107. default [hfoTwoSided];
  108. { Primary event to return heights. }
  109. property OnGetHeight: TgxHeightFieldGetHeightEvent read FOnGetHeight
  110. write SetOnGetHeight;
  111. { Alternate this event to return heights.
  112. This events passes an extra "Sender" parameter, it will be invoked
  113. only if OnGetHeight isn't defined. }
  114. property OnGetHeight2: TgxHeightFieldGetHeight2Event read FOnGetHeight2
  115. write SetOnGetHeight2;
  116. end;
  117. TXYZGridPart = (gpX, gpY, gpZ);
  118. TXYZGridParts = set of TXYZGridPart;
  119. { Rendering Style for grid lines.
  120. - glsLine : a single line is used for each grid line (from Min to Max),
  121. this provides the fastest rendering
  122. - glsSegments : line segments are used between each node of the grid,
  123. this enhances perspective and quality, at the expense of computing
  124. power. }
  125. TXYZGridLinesStyle = (strLine, glsSegments);
  126. { An XYZ Grid object.
  127. Renders an XYZ grid using lines. }
  128. TgxXYZGrid = class(TgxLineBase)
  129. private
  130. FXSamplingScale: TgxSamplingScale;
  131. FYSamplingScale: TgxSamplingScale;
  132. FZSamplingScale: TgxSamplingScale;
  133. FParts: TXYZGridParts;
  134. FLinesStyle: TXYZGridLinesStyle;
  135. protected
  136. procedure SetXSamplingScale(const val: TgxSamplingScale);
  137. procedure SetYSamplingScale(const val: TgxSamplingScale);
  138. procedure SetZSamplingScale(const val: TgxSamplingScale);
  139. procedure SetParts(const val: TXYZGridParts);
  140. procedure SetLinesStyle(const val: TXYZGridLinesStyle);
  141. procedure SetLinesSmoothing(const val: Boolean);
  142. public
  143. constructor Create(AOwner: TComponent); override;
  144. destructor Destroy; override;
  145. procedure Assign(Source: TPersistent); override;
  146. procedure BuildList(var rci: TgxRenderContextInfo); override;
  147. procedure NotifyChange(Sender: TObject); override;
  148. published
  149. property XSamplingScale: TgxSamplingScale read FXSamplingScale
  150. write SetXSamplingScale;
  151. property YSamplingScale: TgxSamplingScale read FYSamplingScale
  152. write SetYSamplingScale;
  153. property ZSamplingScale: TgxSamplingScale read FZSamplingScale
  154. write SetZSamplingScale;
  155. property Parts: TXYZGridParts read FParts write SetParts default [gpX, gpY];
  156. property LinesStyle: TXYZGridLinesStyle read FLinesStyle write SetLinesStyle
  157. default glsSegments;
  158. { Adjusts lines smoothing (or antialiasing).
  159. Obsolete, now maps to Antialiased property. }
  160. property LinesSmoothing: Boolean write SetLinesSmoothing stored False;
  161. end;
  162. //=====================================================================
  163. implementation
  164. //=====================================================================
  165. // ------------------
  166. // ------------------ TgxSamplingScale ------------------
  167. // ------------------
  168. constructor TgxSamplingScale.Create(AOwner: TPersistent);
  169. begin
  170. inherited Create(AOwner);
  171. FStep := 0.1;
  172. end;
  173. destructor TgxSamplingScale.Destroy;
  174. begin
  175. inherited Destroy;
  176. end;
  177. procedure TgxSamplingScale.Assign(Source: TPersistent);
  178. begin
  179. if Source is TgxSamplingScale then
  180. begin
  181. FMin := TgxSamplingScale(Source).FMin;
  182. FMax := TgxSamplingScale(Source).FMax;
  183. FOrigin := TgxSamplingScale(Source).FOrigin;
  184. FStep := TgxSamplingScale(Source).FStep;
  185. NotifyChange(Self);
  186. end
  187. else
  188. inherited Assign(Source);
  189. end;
  190. procedure TgxSamplingScale.SetMin(const val: Single);
  191. begin
  192. FMin := val;
  193. if FMax < FMin then
  194. FMax := FMin;
  195. NotifyChange(Self);
  196. end;
  197. procedure TgxSamplingScale.SetMax(const val: Single);
  198. begin
  199. FMax := val;
  200. if FMin > FMax then
  201. FMin := FMax;
  202. NotifyChange(Self);
  203. end;
  204. procedure TgxSamplingScale.SetOrigin(const val: Single);
  205. begin
  206. FOrigin := val;
  207. NotifyChange(Self);
  208. end;
  209. procedure TgxSamplingScale.SetStep(const val: Single);
  210. begin
  211. if val > 0 then
  212. FStep := val
  213. else
  214. FStep := 1;
  215. NotifyChange(Self);
  216. end;
  217. function TgxSamplingScale.StepBase: Single;
  218. begin
  219. if FOrigin <> FMin then
  220. begin
  221. Result := (FOrigin - FMin) / FStep;
  222. if Result >= 0 then
  223. Result := Trunc(Result)
  224. else
  225. Result := Trunc(Result) - 1;
  226. Result := FOrigin - FStep * Result;
  227. end
  228. else
  229. Result := FMin;
  230. end;
  231. function TgxSamplingScale.MaxStepCount: Integer;
  232. begin
  233. Result := Round(0.5 + (Max - Min) / Step);
  234. end;
  235. function TgxSamplingScale.IsValid: Boolean;
  236. begin
  237. Result := (Max <> Min);
  238. end;
  239. // SetBaseStepMaxToVars
  240. //
  241. procedure TgxSamplingScale.SetBaseStepMaxToVars(var Base, Step, Max: Single;
  242. samplingEnabled: Boolean = True);
  243. begin
  244. Step := FStep;
  245. if samplingEnabled then
  246. begin
  247. Base := StepBase;
  248. Max := FMax + ((FMax - Base) / Step) * 1E-6; // add precision loss epsilon
  249. end
  250. else
  251. begin
  252. Base := FOrigin;
  253. Max := Base;
  254. end;
  255. end;
  256. // ------------------
  257. // ------------------ TgxHeightField ------------------
  258. // ------------------
  259. constructor TgxHeightField.Create(AOwner: TComponent);
  260. begin
  261. inherited Create(AOwner);
  262. FXSamplingScale := TgxSamplingScale.Create(Self);
  263. FYSamplingScale := TgxSamplingScale.Create(Self);
  264. FOptions := [hfoTwoSided];
  265. end;
  266. // Destroy
  267. //
  268. destructor TgxHeightField.Destroy;
  269. begin
  270. FXSamplingScale.Free;
  271. FYSamplingScale.Free;
  272. inherited Destroy;
  273. end;
  274. // Assign
  275. //
  276. procedure TgxHeightField.Assign(Source: TPersistent);
  277. begin
  278. if Source is TgxHeightField then
  279. begin
  280. XSamplingScale := TgxHeightField(Source).XSamplingScale;
  281. YSamplingScale := TgxHeightField(Source).YSamplingScale;
  282. FOnGetHeight := TgxHeightField(Source).FOnGetHeight;
  283. FOptions := TgxHeightField(Source).FOptions;
  284. FColorMode := TgxHeightField(Source).FColorMode;
  285. end;
  286. inherited Assign(Source);
  287. end;
  288. // NotifyChange
  289. //
  290. procedure TgxHeightField.NotifyChange(Sender: TObject);
  291. begin
  292. if Sender is TgxSamplingScale then
  293. StructureChanged;
  294. inherited NotifyChange(Sender);
  295. end;
  296. // BuildList
  297. //
  298. procedure TgxHeightField.BuildList(var rci: TgxRenderContextInfo);
  299. type
  300. TRowData = packed record
  301. Color: TgxColorVector;
  302. Z: Single;
  303. TexPoint: TTexPoint;
  304. Normal: TAffineVector;
  305. end;
  306. TRowDataArray = array [0 .. Maxint shr 6] of TRowData;
  307. PRowData = ^TRowDataArray;
  308. const
  309. cHFCMtoEnum: array [hfcmEmission .. hfcmAmbientAndDiffuse] of GLEnum =
  310. (GL_EMISSION, GL_AMBIENT, GL_DIFFUSE, GL_AMBIENT_AND_DIFFUSE);
  311. var
  312. nx, m, k: Integer;
  313. x, y, x1, y1, y2, xStep, yStep, xBase, dx, dy: Single;
  314. invXStep, invYStep: Single;
  315. row: packed array [0 .. 2] of PRowData;
  316. rowTop, rowMid, rowBottom: PRowData;
  317. func: TgxHeightFieldGetHeightEvent;
  318. procedure IssuePoint(var x, y: Single; const pt: TRowData);
  319. begin
  320. with pt do
  321. begin
  322. glNormal3fv(@normal);
  323. if ColorMode <> hfcmNone then
  324. glColor4fv(@color);
  325. if hfoTextureCoordinates in Options then
  326. glTexCoord2fv(@texPoint);
  327. glVertex4f(x, y, z, 1);
  328. end;
  329. end;
  330. procedure RenderRow(pHighRow, pLowRow: PRowData);
  331. var
  332. k: Integer;
  333. begin
  334. glBegin(GL_TRIANGLE_STRIP);
  335. x := xBase;
  336. IssuePoint(x, y1, pLowRow^[0]);
  337. for k := 0 to m - 2 do
  338. begin
  339. x1 := x + xStep;
  340. IssuePoint(x, y2, pHighRow^[k]);
  341. IssuePoint(x1, y1, pLowRow^[k + 1]);
  342. x := x1;
  343. end;
  344. IssuePoint(x, y2, pHighRow^[m - 1]);
  345. glEnd;
  346. end;
  347. begin
  348. if not(XSamplingScale.IsValid and YSamplingScale.IsValid) then
  349. Exit;
  350. if Assigned(FOnGetHeight) and (not(csDesigning in ComponentState)) then
  351. func := FOnGetHeight
  352. else if Assigned(FOnGetHeight2) and (not(csDesigning in ComponentState)) then
  353. func := Height2Field
  354. else
  355. func := DefaultHeightField;
  356. // allocate row cache
  357. nx := (XSamplingScale.MaxStepCount + 1) * SizeOf(TRowData);
  358. for k := 0 to 2 do
  359. begin
  360. GetMem(row[k], nx);
  361. FillChar(row[k][0], nx, 0);
  362. end;
  363. try
  364. // precompute grid values
  365. xBase := XSamplingScale.StepBase;
  366. xStep := XSamplingScale.Step;
  367. invXStep := 1 / xStep;
  368. yStep := YSamplingScale.Step;
  369. invYStep := 1 / yStep;
  370. // get through the grid
  371. if (hfoTwoSided in Options) or (ColorMode <> hfcmNone) then
  372. begin
  373. // if we're not two-sided, we doesn't have to enable face-culling, it's
  374. // controled at the sceneviewer level
  375. if hfoTwoSided in Options then
  376. begin
  377. rci.gxStates.Disable(stCullFace);
  378. rci.gxStates.PolygonMode := Material.PolygonMode;
  379. end;
  380. if ColorMode <> hfcmNone then
  381. begin
  382. rci.gxStates.Enable(stColorMaterial);
  383. glColorMaterial(GL_FRONT_AND_BACK, cHFCMtoEnum[ColorMode]);
  384. rci.gxStates.SetMaterialColors(cmFront, clrBlack, clrGray20,
  385. clrGray80, clrBlack, 0);
  386. rci.gxStates.SetMaterialColors(cmBack, clrBlack, clrGray20, clrGray80,
  387. clrBlack, 0);
  388. end;
  389. end;
  390. rowBottom := nil;
  391. rowMid := nil;
  392. nx := 0;
  393. y := YSamplingScale.StepBase;
  394. y1 := y;
  395. y2 := y;
  396. while y <= YSamplingScale.Max do
  397. begin
  398. rowTop := rowMid;
  399. rowMid := rowBottom;
  400. rowBottom := row[nx mod 3];
  401. x := xBase;
  402. m := 0;
  403. while x <= XSamplingScale.Max do
  404. begin
  405. with rowBottom^[m] do
  406. begin
  407. with texPoint do
  408. begin
  409. S := x;
  410. T := y;
  411. end;
  412. func(x, y, z, color, texPoint);
  413. end;
  414. Inc(m);
  415. x := x + xStep;
  416. end;
  417. if Assigned(rowMid) then
  418. begin
  419. for k := 0 to m - 1 do
  420. begin
  421. if k > 0 then
  422. dx := (rowMid^[k - 1].z - rowMid^[k].z) * invXStep
  423. else
  424. dx := 0;
  425. if k < m - 1 then
  426. dx := dx + (rowMid^[k].z - rowMid^[k + 1].z) * invXStep;
  427. if Assigned(rowTop) then
  428. dy := (rowTop^[k].z - rowMid^[k].z) * invYStep
  429. else
  430. dy := 0;
  431. if Assigned(rowBottom) then
  432. dy := dy + (rowMid^[k].z - rowBottom^[k].z) * invYStep;
  433. rowMid^[k].normal := VectorNormalize(AffineVectorMake(dx, dy, 1));
  434. end;
  435. end;
  436. if nx > 1 then
  437. begin
  438. RenderRow(rowTop, rowMid);
  439. end;
  440. Inc(nx);
  441. y2 := y1;
  442. y1 := y;
  443. y := y + yStep;
  444. end;
  445. for k := 0 to m - 1 do
  446. begin
  447. if k > 0 then
  448. dx := (rowBottom^[k - 1].z - rowBottom^[k].z) * invXStep
  449. else
  450. dx := 0;
  451. if k < m - 1 then
  452. dx := dx + (rowBottom^[k].z - rowBottom^[k + 1].z) * invXStep;
  453. if Assigned(rowMid) then
  454. dy := (rowMid^[k].z - rowBottom^[k].z) * invYStep
  455. else
  456. dy := 0;
  457. rowBottom^[k].normal := VectorNormalize(AffineVectorMake(dx, dy, 1));
  458. end;
  459. if Assigned(rowMid) and Assigned(rowBottom) then
  460. RenderRow(rowMid, rowBottom);
  461. FTriangleCount := 2 * (nx - 1) * (m - 1);
  462. finally
  463. FreeMem(row[0]);
  464. FreeMem(row[1]);
  465. FreeMem(row[2]);
  466. end;
  467. end;
  468. // SetXSamplingScale
  469. //
  470. procedure TgxHeightField.SetXSamplingScale(const val: TgxSamplingScale);
  471. begin
  472. FXSamplingScale.Assign(val);
  473. end;
  474. // SetYSamplingScale
  475. //
  476. procedure TgxHeightField.SetYSamplingScale(const val: TgxSamplingScale);
  477. begin
  478. FYSamplingScale.Assign(val);
  479. end;
  480. // SetOptions
  481. //
  482. procedure TgxHeightField.SetOptions(const val: TgxHeightFieldOptions);
  483. begin
  484. if FOptions <> val then
  485. begin
  486. FOptions := val;
  487. StructureChanged;
  488. end;
  489. end;
  490. // SetOnGetHeight
  491. //
  492. procedure TgxHeightField.SetOnGetHeight(const val: TgxHeightFieldGetHeightEvent);
  493. begin
  494. FOnGetHeight := val;
  495. StructureChanged;
  496. end;
  497. // SetOnGetHeight2
  498. //
  499. procedure TgxHeightField.SetOnGetHeight2(const val
  500. : TgxHeightFieldGetHeight2Event);
  501. begin
  502. FOnGetHeight2 := val;
  503. StructureChanged;
  504. end;
  505. // SetColorMode
  506. //
  507. procedure TgxHeightField.SetColorMode(const val: TgxHeightFieldColorMode);
  508. begin
  509. if val <> FColorMode then
  510. begin
  511. FColorMode := val;
  512. StructureChanged;
  513. end;
  514. end;
  515. // DefaultHeightField
  516. //
  517. procedure TgxHeightField.DefaultHeightField(const x, y: Single; var z: Single;
  518. var color: TgxColorVector; var texPoint: TTexPoint);
  519. begin
  520. z := VectorNorm(x, y);
  521. z := cos(z * 12) / (2 * (z * 6.28 + 1));
  522. color := clrGray80;
  523. end;
  524. // Height2Field
  525. //
  526. procedure TgxHeightField.Height2Field(const x, y: Single; var z: Single;
  527. var color: TgxColorVector; var texPoint: TTexPoint);
  528. begin
  529. FOnGetHeight2(Self, x, y, z, color, texPoint);
  530. end;
  531. // ------------------
  532. // ------------------ TgxXYZGrid ------------------
  533. // ------------------
  534. // Create
  535. //
  536. constructor TgxXYZGrid.Create(AOwner: TComponent);
  537. begin
  538. inherited Create(AOwner);
  539. FXSamplingScale := TgxSamplingScale.Create(Self);
  540. FYSamplingScale := TgxSamplingScale.Create(Self);
  541. FZSamplingScale := TgxSamplingScale.Create(Self);
  542. FParts := [gpX, gpY];
  543. FLinesStyle := glsSegments;
  544. end;
  545. // Destroy
  546. //
  547. destructor TgxXYZGrid.Destroy;
  548. begin
  549. FXSamplingScale.Free;
  550. FYSamplingScale.Free;
  551. FZSamplingScale.Free;
  552. inherited Destroy;
  553. end;
  554. // Assign
  555. //
  556. procedure TgxXYZGrid.Assign(Source: TPersistent);
  557. begin
  558. if Source is TgxXYZGrid then
  559. begin
  560. XSamplingScale := TgxXYZGrid(Source).XSamplingScale;
  561. YSamplingScale := TgxXYZGrid(Source).YSamplingScale;
  562. ZSamplingScale := TgxXYZGrid(Source).ZSamplingScale;
  563. FParts := TgxXYZGrid(Source).FParts;
  564. FLinesStyle := TgxXYZGrid(Source).FLinesStyle;
  565. end;
  566. inherited Assign(Source);
  567. end;
  568. // SetXSamplingScale
  569. //
  570. procedure TgxXYZGrid.SetXSamplingScale(const val: TgxSamplingScale);
  571. begin
  572. FXSamplingScale.Assign(val);
  573. end;
  574. // SetYSamplingScale
  575. //
  576. procedure TgxXYZGrid.SetYSamplingScale(const val: TgxSamplingScale);
  577. begin
  578. FYSamplingScale.Assign(val);
  579. end;
  580. // SetZSamplingScale
  581. //
  582. procedure TgxXYZGrid.SetZSamplingScale(const val: TgxSamplingScale);
  583. begin
  584. FZSamplingScale.Assign(val);
  585. end;
  586. // SetParts
  587. //
  588. procedure TgxXYZGrid.SetParts(const val: TXYZGridParts);
  589. begin
  590. if FParts <> val then
  591. begin
  592. FParts := val;
  593. StructureChanged;
  594. end;
  595. end;
  596. // SetLinesStyle
  597. //
  598. procedure TgxXYZGrid.SetLinesStyle(const val: TXYZGridLinesStyle);
  599. begin
  600. if FLinesStyle <> val then
  601. begin
  602. FLinesStyle := val;
  603. StructureChanged;
  604. end;
  605. end;
  606. // SetLinesSmoothing
  607. //
  608. procedure TgxXYZGrid.SetLinesSmoothing(const val: Boolean);
  609. begin
  610. AntiAliased := val;
  611. end;
  612. // NotifyChange
  613. //
  614. procedure TgxXYZGrid.NotifyChange(Sender: TObject);
  615. begin
  616. if Sender is TgxSamplingScale then
  617. StructureChanged;
  618. inherited NotifyChange(Sender);
  619. end;
  620. // BuildList
  621. //
  622. procedure TgxXYZGrid.BuildList(var rci: TgxRenderContextInfo);
  623. var
  624. xBase, x, xStep, xMax, yBase, y, yStep, yMax, zBase, z, zStep, zMax: Single;
  625. begin
  626. SetupLineStyle(rci);
  627. // precache values
  628. XSamplingScale.SetBaseStepMaxToVars(xBase, xStep, xMax, (gpX in Parts));
  629. YSamplingScale.SetBaseStepMaxToVars(yBase, yStep, yMax, (gpY in Parts));
  630. ZSamplingScale.SetBaseStepMaxToVars(zBase, zStep, zMax, (gpZ in Parts));
  631. // render X parallel lines
  632. if gpX in Parts then
  633. begin
  634. y := yBase;
  635. while y <= yMax do
  636. begin
  637. z := zBase;
  638. while z <= zMax do
  639. begin
  640. glBegin(GL_LINE_STRIP);
  641. if LinesStyle = glsSegments then
  642. begin
  643. x := xBase;
  644. while x <= xMax do
  645. begin
  646. glVertex3f(x, y, z);
  647. x := x + xStep;
  648. end;
  649. end
  650. else
  651. begin
  652. glVertex3f(XSamplingScale.Min, y, z);
  653. glVertex3f(XSamplingScale.Max, y, z);
  654. end;
  655. glEnd;
  656. z := z + zStep;
  657. end;
  658. y := y + yStep;
  659. end;
  660. end;
  661. // render Y parallel lines
  662. if gpY in Parts then
  663. begin
  664. x := xBase;
  665. while x <= xMax do
  666. begin
  667. z := zBase;
  668. while z <= zMax do
  669. begin
  670. glBegin(GL_LINE_STRIP);
  671. if LinesStyle = glsSegments then
  672. begin
  673. y := yBase;
  674. while y <= yMax do
  675. begin
  676. glVertex3f(x, y, z);
  677. y := y + yStep;
  678. end;
  679. end
  680. else
  681. begin
  682. glVertex3f(x, YSamplingScale.Min, z);
  683. glVertex3f(x, YSamplingScale.Max, z);
  684. end;
  685. glEnd;
  686. z := z + zStep;
  687. end;
  688. x := x + xStep;
  689. end;
  690. end;
  691. // render Z parallel lines
  692. if gpZ in Parts then
  693. begin
  694. x := xBase;
  695. while x <= xMax do
  696. begin
  697. y := yBase;
  698. while y <= yMax do
  699. begin
  700. glBegin(GL_LINE_STRIP);
  701. if LinesStyle = glsSegments then
  702. begin
  703. z := zBase;
  704. while z <= zMax do
  705. begin
  706. glVertex3f(x, y, z);
  707. z := z + zStep;
  708. end;
  709. end
  710. else
  711. begin
  712. glVertex3f(x, y, ZSamplingScale.Min);
  713. glVertex3f(x, y, ZSamplingScale.Max);
  714. end;
  715. glEnd;
  716. y := y + yStep;
  717. end;
  718. x := x + xStep;
  719. end;
  720. end;
  721. end;
  722. // -------------------------------------------------------------
  723. // -------------------------------------------------------------
  724. // -------------------------------------------------------------
  725. initialization
  726. // -------------------------------------------------------------
  727. // -------------------------------------------------------------
  728. // -------------------------------------------------------------
  729. RegisterClasses([TgxHeightField, TgxXYZGrid]);
  730. end.