GLS.Graph.pas 20 KB

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