GLGraph.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. unit GLGraph;
  5. (* Graph plotting objects for GLScene *)
  6. interface
  7. {$I GLScene.inc}
  8. uses
  9. Winapi.OpenGL,
  10. System.Classes,
  11. System.SysUtils,
  12. GLScene,
  13. OpenGLTokens,
  14. GLContext,
  15. XOpenGL,
  16. GLVectorGeometry,
  17. GLMaterial,
  18. GLObjects,
  19. GLVectorLists,
  20. GLColor,
  21. GLBaseClasses,
  22. GLRenderContextInfo,
  23. GLState,
  24. GLVectorTypes;
  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: TColorVector; var TexPoint: TTexPoint) of object;
  58. TGLHeightFieldGetHeight2Event = procedure(Sender: TObject; const x, y: Single;
  59. var z: Single; var Color: TColorVector; 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: TColorVector; var TexPoint: TTexPoint);
  90. procedure Height2Field(const x, y: Single; var z: Single;
  91. var Color: TColorVector; 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).
  159. Obsolete, now maps to Antialiased property. *)
  160. property LinesSmoothing: Boolean write SetLinesSmoothing stored False;
  161. end;
  162. // ------------------------------------------------------------------
  163. implementation
  164. // ------------------------------------------------------------------
  165. // ------------------
  166. // ------------------ TGLSamplingScale ------------------
  167. // ------------------
  168. constructor TGLSamplingScale.Create(AOwner: TPersistent);
  169. begin
  170. inherited Create(AOwner);
  171. FStep := 0.1;
  172. end;
  173. destructor TGLSamplingScale.Destroy;
  174. begin
  175. inherited Destroy;
  176. end;
  177. procedure TGLSamplingScale.Assign(Source: TPersistent);
  178. begin
  179. if Source is TGLSamplingScale then
  180. begin
  181. FMin := TGLSamplingScale(Source).FMin;
  182. FMax := TGLSamplingScale(Source).FMax;
  183. FOrigin := TGLSamplingScale(Source).FOrigin;
  184. FStep := TGLSamplingScale(Source).FStep;
  185. NotifyChange(Self);
  186. end
  187. else
  188. inherited Assign(Source);
  189. end;
  190. procedure TGLSamplingScale.SetMin(const val: Single);
  191. begin
  192. FMin := val;
  193. if FMax < FMin then
  194. FMax := FMin;
  195. NotifyChange(Self);
  196. end;
  197. procedure TGLSamplingScale.SetMax(const val: Single);
  198. begin
  199. FMax := val;
  200. if FMin > FMax then
  201. FMin := FMax;
  202. NotifyChange(Self);
  203. end;
  204. procedure TGLSamplingScale.SetOrigin(const val: Single);
  205. begin
  206. FOrigin := val;
  207. NotifyChange(Self);
  208. end;
  209. procedure TGLSamplingScale.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 TGLSamplingScale.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 TGLSamplingScale.MaxStepCount: Integer;
  232. begin
  233. Result := Round(0.5 + (Max - Min) / Step);
  234. end;
  235. function TGLSamplingScale.IsValid: Boolean;
  236. begin
  237. Result := (Max <> Min);
  238. end;
  239. procedure TGLSamplingScale.SetBaseStepMaxToVars(var Base, Step, Max: Single;
  240. samplingEnabled: Boolean = True);
  241. begin
  242. Step := FStep;
  243. if samplingEnabled then
  244. begin
  245. Base := StepBase;
  246. Max := FMax + ((FMax - Base) / Step) * 1E-6; // add precision loss epsilon
  247. end
  248. else
  249. begin
  250. Base := FOrigin;
  251. Max := Base;
  252. end;
  253. end;
  254. // ------------------
  255. // ------------------ TGLHeightField ------------------
  256. // ------------------
  257. constructor TGLHeightField.Create(AOwner: TComponent);
  258. begin
  259. inherited Create(AOwner);
  260. FXSamplingScale := TGLSamplingScale.Create(Self);
  261. FYSamplingScale := TGLSamplingScale.Create(Self);
  262. FOptions := [hfoTwoSided];
  263. end;
  264. destructor TGLHeightField.Destroy;
  265. begin
  266. FXSamplingScale.Free;
  267. FYSamplingScale.Free;
  268. inherited Destroy;
  269. end;
  270. procedure TGLHeightField.Assign(Source: TPersistent);
  271. begin
  272. if Source is TGLHeightField then
  273. begin
  274. XSamplingScale := TGLHeightField(Source).XSamplingScale;
  275. YSamplingScale := TGLHeightField(Source).YSamplingScale;
  276. FOnGetHeight := TGLHeightField(Source).FOnGetHeight;
  277. FOptions := TGLHeightField(Source).FOptions;
  278. FColorMode := TGLHeightField(Source).FColorMode;
  279. end;
  280. inherited Assign(Source);
  281. end;
  282. procedure TGLHeightField.NotifyChange(Sender: TObject);
  283. begin
  284. if Sender is TGLSamplingScale then
  285. StructureChanged;
  286. inherited NotifyChange(Sender);
  287. end;
  288. procedure TGLHeightField.BuildList(var rci: TGLRenderContextInfo);
  289. type
  290. TRowData = packed record
  291. Color: TColorVector;
  292. Z: Single;
  293. TexPoint: TTexPoint;
  294. Normal: TAffineVector;
  295. end;
  296. TRowDataArray = array [0 .. Maxint shr 6] of TRowData;
  297. PRowData = ^TRowDataArray;
  298. const
  299. cHFCMtoEnum: array [hfcmEmission .. hfcmAmbientAndDiffuse] of Cardinal =
  300. (GL_EMISSION, GL_AMBIENT, GL_DIFFUSE, GL_AMBIENT_AND_DIFFUSE);
  301. var
  302. nx, m, k: Integer;
  303. x, y, x1, y1, y2, xStep, yStep, xBase, dx, dy: Single;
  304. invXStep, invYStep: Single;
  305. row: packed array [0 .. 2] of PRowData;
  306. rowTop, rowMid, rowBottom: PRowData;
  307. func: TGLHeightFieldGetHeightEvent;
  308. procedure IssuePoint(var x, y: Single; const pt: TRowData);
  309. begin
  310. with pt do
  311. begin
  312. gl.Normal3fv(@normal);
  313. if ColorMode <> hfcmNone then
  314. gl.Color4fv(@color);
  315. if hfoTextureCoordinates in Options then
  316. xgl.TexCoord2fv(@texPoint);
  317. gl.Vertex4f(x, y, z, 1);
  318. end;
  319. end;
  320. procedure RenderRow(pHighRow, pLowRow: PRowData);
  321. var
  322. k: Integer;
  323. begin
  324. gl.Begin_(GL_TRIANGLE_STRIP);
  325. x := xBase;
  326. IssuePoint(x, y1, pLowRow^[0]);
  327. for k := 0 to m - 2 do
  328. begin
  329. x1 := x + xStep;
  330. IssuePoint(x, y2, pHighRow^[k]);
  331. IssuePoint(x1, y1, pLowRow^[k + 1]);
  332. x := x1;
  333. end;
  334. IssuePoint(x, y2, pHighRow^[m - 1]);
  335. gl.End_;
  336. end;
  337. begin
  338. if not(XSamplingScale.IsValid and YSamplingScale.IsValid) then
  339. Exit;
  340. if Assigned(FOnGetHeight) and (not(csDesigning in ComponentState)) then
  341. func := FOnGetHeight
  342. else if Assigned(FOnGetHeight2) and (not(csDesigning in ComponentState)) then
  343. func := Height2Field
  344. else
  345. func := DefaultHeightField;
  346. // allocate row cache
  347. nx := (XSamplingScale.MaxStepCount + 1) * SizeOf(TRowData);
  348. for k := 0 to 2 do
  349. begin
  350. GetMem(row[k], nx);
  351. FillChar(row[k][0], nx, 0);
  352. end;
  353. try
  354. // precompute grid values
  355. xBase := XSamplingScale.StepBase;
  356. xStep := XSamplingScale.Step;
  357. invXStep := 1 / xStep;
  358. yStep := YSamplingScale.Step;
  359. invYStep := 1 / yStep;
  360. // get through the grid
  361. if (hfoTwoSided in Options) or (ColorMode <> hfcmNone) then
  362. begin
  363. // if we're not two-sided, we doesn't have to enable face-culling, it's
  364. // controled at the sceneviewer level
  365. if hfoTwoSided in Options then
  366. begin
  367. rci.GLStates.Disable(stCullFace);
  368. rci.GLStates.PolygonMode := Material.PolygonMode;
  369. end;
  370. if ColorMode <> hfcmNone then
  371. begin
  372. rci.GLStates.Enable(stColorMaterial);
  373. gl.ColorMaterial(GL_FRONT_AND_BACK, cHFCMtoEnum[ColorMode]);
  374. rci.GLStates.SetGLMaterialColors(cmFront, clrBlack, clrGray20,
  375. clrGray80, clrBlack, 0);
  376. rci.GLStates.SetGLMaterialColors(cmBack, clrBlack, clrGray20, clrGray80,
  377. clrBlack, 0);
  378. end;
  379. end;
  380. rowBottom := nil;
  381. rowMid := nil;
  382. nx := 0;
  383. y := YSamplingScale.StepBase;
  384. y1 := y;
  385. y2 := y;
  386. while y <= YSamplingScale.Max do
  387. begin
  388. rowTop := rowMid;
  389. rowMid := rowBottom;
  390. rowBottom := row[nx mod 3];
  391. x := xBase;
  392. m := 0;
  393. while x <= XSamplingScale.Max do
  394. begin
  395. with rowBottom^[m] do
  396. begin
  397. with texPoint do
  398. begin
  399. S := x;
  400. T := y;
  401. end;
  402. func(x, y, z, color, texPoint);
  403. end;
  404. Inc(m);
  405. x := x + xStep;
  406. end;
  407. if Assigned(rowMid) then
  408. begin
  409. for k := 0 to m - 1 do
  410. begin
  411. if k > 0 then
  412. dx := (rowMid^[k - 1].z - rowMid^[k].z) * invXStep
  413. else
  414. dx := 0;
  415. if k < m - 1 then
  416. dx := dx + (rowMid^[k].z - rowMid^[k + 1].z) * invXStep;
  417. if Assigned(rowTop) then
  418. dy := (rowTop^[k].z - rowMid^[k].z) * invYStep
  419. else
  420. dy := 0;
  421. if Assigned(rowBottom) then
  422. dy := dy + (rowMid^[k].z - rowBottom^[k].z) * invYStep;
  423. rowMid^[k].normal := VectorNormalize(AffineVectorMake(dx, dy, 1));
  424. end;
  425. end;
  426. if nx > 1 then
  427. begin
  428. RenderRow(rowTop, rowMid);
  429. end;
  430. Inc(nx);
  431. y2 := y1;
  432. y1 := y;
  433. y := y + yStep;
  434. end;
  435. for k := 0 to m - 1 do
  436. begin
  437. if k > 0 then
  438. dx := (rowBottom^[k - 1].z - rowBottom^[k].z) * invXStep
  439. else
  440. dx := 0;
  441. if k < m - 1 then
  442. dx := dx + (rowBottom^[k].z - rowBottom^[k + 1].z) * invXStep;
  443. if Assigned(rowMid) then
  444. dy := (rowMid^[k].z - rowBottom^[k].z) * invYStep
  445. else
  446. dy := 0;
  447. rowBottom^[k].normal := VectorNormalize(AffineVectorMake(dx, dy, 1));
  448. end;
  449. if Assigned(rowMid) and Assigned(rowBottom) then
  450. RenderRow(rowMid, rowBottom);
  451. FTriangleCount := 2 * (nx - 1) * (m - 1);
  452. finally
  453. FreeMem(row[0]);
  454. FreeMem(row[1]);
  455. FreeMem(row[2]);
  456. end;
  457. end;
  458. procedure TGLHeightField.SetXSamplingScale(const val: TGLSamplingScale);
  459. begin
  460. FXSamplingScale.Assign(val);
  461. end;
  462. procedure TGLHeightField.SetYSamplingScale(const val: TGLSamplingScale);
  463. begin
  464. FYSamplingScale.Assign(val);
  465. end;
  466. procedure TGLHeightField.SetOptions(const val: TGLHeightFieldOptions);
  467. begin
  468. if FOptions <> val then
  469. begin
  470. FOptions := val;
  471. StructureChanged;
  472. end;
  473. end;
  474. procedure TGLHeightField.SetOnGetHeight(const val: TGLHeightFieldGetHeightEvent);
  475. begin
  476. FOnGetHeight := val;
  477. StructureChanged;
  478. end;
  479. procedure TGLHeightField.SetOnGetHeight2(const val
  480. : TGLHeightFieldGetHeight2Event);
  481. begin
  482. FOnGetHeight2 := val;
  483. StructureChanged;
  484. end;
  485. procedure TGLHeightField.SetColorMode(const val: TGLHeightFieldColorMode);
  486. begin
  487. if val <> FColorMode then
  488. begin
  489. FColorMode := val;
  490. StructureChanged;
  491. end;
  492. end;
  493. procedure TGLHeightField.DefaultHeightField(const x, y: Single; var z: Single;
  494. var color: TColorVector; var texPoint: TTexPoint);
  495. begin
  496. z := VectorNorm(x, y);
  497. z := cos(z * 12) / (2 * (z * 6.28 + 1));
  498. color := clrGray80;
  499. end;
  500. procedure TGLHeightField.Height2Field(const x, y: Single; var z: Single;
  501. var color: TColorVector; var texPoint: TTexPoint);
  502. begin
  503. FOnGetHeight2(Self, x, y, z, color, texPoint);
  504. end;
  505. // ------------------
  506. // ------------------ TGLXYZGrid ------------------
  507. // ------------------
  508. constructor TGLXYZGrid.Create(AOwner: TComponent);
  509. begin
  510. inherited Create(AOwner);
  511. FXSamplingScale := TGLSamplingScale.Create(Self);
  512. FYSamplingScale := TGLSamplingScale.Create(Self);
  513. FZSamplingScale := TGLSamplingScale.Create(Self);
  514. FParts := [gpX, gpY];
  515. FLinesStyle := glsSegments;
  516. end;
  517. destructor TGLXYZGrid.Destroy;
  518. begin
  519. FXSamplingScale.Free;
  520. FYSamplingScale.Free;
  521. FZSamplingScale.Free;
  522. inherited Destroy;
  523. end;
  524. procedure TGLXYZGrid.Assign(Source: TPersistent);
  525. begin
  526. if Source is TGLXYZGrid then
  527. begin
  528. XSamplingScale := TGLXYZGrid(Source).XSamplingScale;
  529. YSamplingScale := TGLXYZGrid(Source).YSamplingScale;
  530. ZSamplingScale := TGLXYZGrid(Source).ZSamplingScale;
  531. FParts := TGLXYZGrid(Source).FParts;
  532. FLinesStyle := TGLXYZGrid(Source).FLinesStyle;
  533. end;
  534. inherited Assign(Source);
  535. end;
  536. procedure TGLXYZGrid.SetXSamplingScale(const val: TGLSamplingScale);
  537. begin
  538. FXSamplingScale.Assign(val);
  539. end;
  540. procedure TGLXYZGrid.SetYSamplingScale(const val: TGLSamplingScale);
  541. begin
  542. FYSamplingScale.Assign(val);
  543. end;
  544. procedure TGLXYZGrid.SetZSamplingScale(const val: TGLSamplingScale);
  545. begin
  546. FZSamplingScale.Assign(val);
  547. end;
  548. procedure TGLXYZGrid.SetParts(const val: TGLXYZGridParts);
  549. begin
  550. if FParts <> val then
  551. begin
  552. FParts := val;
  553. StructureChanged;
  554. end;
  555. end;
  556. procedure TGLXYZGrid.SetLinesStyle(const val: TGLXYZGridLinesStyle);
  557. begin
  558. if FLinesStyle <> val then
  559. begin
  560. FLinesStyle := val;
  561. StructureChanged;
  562. end;
  563. end;
  564. procedure TGLXYZGrid.SetLinesSmoothing(const val: Boolean);
  565. begin
  566. AntiAliased := val;
  567. end;
  568. procedure TGLXYZGrid.NotifyChange(Sender: TObject);
  569. begin
  570. if Sender is TGLSamplingScale then
  571. StructureChanged;
  572. inherited NotifyChange(Sender);
  573. end;
  574. procedure TGLXYZGrid.BuildList(var rci: TGLRenderContextInfo);
  575. var
  576. xBase, x, xStep, xMax, yBase, y, yStep, yMax, zBase, z, zStep, zMax: Single;
  577. begin
  578. SetupLineStyle(rci);
  579. // precache values
  580. XSamplingScale.SetBaseStepMaxToVars(xBase, xStep, xMax, (gpX in Parts));
  581. YSamplingScale.SetBaseStepMaxToVars(yBase, yStep, yMax, (gpY in Parts));
  582. ZSamplingScale.SetBaseStepMaxToVars(zBase, zStep, zMax, (gpZ in Parts));
  583. // render X parallel lines
  584. if gpX in Parts then
  585. begin
  586. y := yBase;
  587. while y <= yMax do
  588. begin
  589. z := zBase;
  590. while z <= zMax do
  591. begin
  592. gl.Begin_(GL_LINE_STRIP);
  593. if LinesStyle = glsSegments then
  594. begin
  595. x := xBase;
  596. while x <= xMax do
  597. begin
  598. gl.Vertex3f(x, y, z);
  599. x := x + xStep;
  600. end;
  601. end
  602. else
  603. begin
  604. gl.Vertex3f(XSamplingScale.Min, y, z);
  605. gl.Vertex3f(XSamplingScale.Max, y, z);
  606. end;
  607. gl.End_;
  608. z := z + zStep;
  609. end;
  610. y := y + yStep;
  611. end;
  612. end;
  613. // render Y parallel lines
  614. if gpY in Parts then
  615. begin
  616. x := xBase;
  617. while x <= xMax do
  618. begin
  619. z := zBase;
  620. while z <= zMax do
  621. begin
  622. gl.Begin_(GL_LINE_STRIP);
  623. if LinesStyle = glsSegments then
  624. begin
  625. y := yBase;
  626. while y <= yMax do
  627. begin
  628. gl.Vertex3f(x, y, z);
  629. y := y + yStep;
  630. end;
  631. end
  632. else
  633. begin
  634. gl.Vertex3f(x, YSamplingScale.Min, z);
  635. gl.Vertex3f(x, YSamplingScale.Max, z);
  636. end;
  637. gl.End_;
  638. z := z + zStep;
  639. end;
  640. x := x + xStep;
  641. end;
  642. end;
  643. // render Z parallel lines
  644. if gpZ in Parts then
  645. begin
  646. x := xBase;
  647. while x <= xMax do
  648. begin
  649. y := yBase;
  650. while y <= yMax do
  651. begin
  652. gl.Begin_(GL_LINE_STRIP);
  653. if LinesStyle = glsSegments then
  654. begin
  655. z := zBase;
  656. while z <= zMax do
  657. begin
  658. gl.Vertex3f(x, y, z);
  659. z := z + zStep;
  660. end;
  661. end
  662. else
  663. begin
  664. gl.Vertex3f(x, y, ZSamplingScale.Min);
  665. gl.Vertex3f(x, y, ZSamplingScale.Max);
  666. end;
  667. gl.End_;
  668. y := y + yStep;
  669. end;
  670. x := x + xStep;
  671. end;
  672. end;
  673. end;
  674. // -------------------------------------------------------------
  675. initialization
  676. // -------------------------------------------------------------
  677. RegisterClasses([TGLHeightField, TGLXYZGrid]);
  678. end.