GLS.Graph.pas 20 KB

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