GLMultiPolygon.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. {
  5. Object with support for complex polygons.
  6. }
  7. (*
  8. When the tesselator finds an intersection of edges it wants us to give him some storage
  9. for this new vertex, and he wants a pointer (see tessCombine). The pointers taken from
  10. TAffineVectorList become invalid after enlarging the capacity (makes a ReAllocMem), which
  11. can happen implicitly while adding. The TGLVectorPool keeps all pointers valid until the
  12. destruction itself.
  13. Reactivated the TGLVectorPool object. The GLVectorLists are not suitable for this job.
  14. If anyone feels responsible: it would be fine to have a method ImportFromFile (dxf?) in
  15. the TGLContour and TGLMultiPolygonBase objects...
  16. *)
  17. unit GLMultiPolygon;
  18. interface
  19. {$I GLScene.inc}
  20. uses
  21. System.Classes,
  22. System.SysUtils,
  23. OpenGLTokens,
  24. OpenGLAdapter,
  25. GLSpline,
  26. XOpenGL,
  27. GLContext,
  28. GLVectorTypes,
  29. GLVectorGeometry,
  30. GLVectorLists,
  31. GLPersistentClasses,
  32. GLScene,
  33. GLObjects,
  34. GLGeomObjects,
  35. GLNodes,
  36. GLBaseClasses,
  37. GLCoordinates,
  38. GLRenderContextInfo;
  39. type
  40. TGLContourNodes = class(TGLNodes)
  41. public
  42. procedure NotifyChange; override;
  43. end;
  44. TGLContour = class(TCollectionItem)
  45. private
  46. FNodes: TGLContourNodes;
  47. FDivision: Integer;
  48. FSplineMode: TGLLineSplineMode;
  49. FDescription: string;
  50. procedure SetNodes(const Value: TGLContourNodes);
  51. procedure SetDivision(Value: Integer);
  52. procedure SetSplineMode(const Value: TGLLineSplineMode);
  53. procedure SetDescription(const Value: string);
  54. protected
  55. procedure CreateNodes;
  56. procedure NodesChanged(Sender: TObject);
  57. function GetDisplayName: string; override;
  58. public
  59. constructor Create(Collection: TCollection); override;
  60. destructor Destroy; override;
  61. procedure Assign(Source: TPersistent); override;
  62. published
  63. property Description: string read FDescription write SetDescription;
  64. // The nodes list
  65. property Nodes: TGLContourNodes read FNodes write SetNodes;
  66. (* Number of divisions for each segment in spline modes.
  67. Minimum 1 (disabled), ignored in lsmLines mode. *)
  68. property Division: Integer read FDivision write SetDivision default 10;
  69. (* Default spline drawing mode.
  70. This mode is used only for the curve, not for the rotation path. *)
  71. property SplineMode: TGLLineSplineMode read FSplineMode write SetSplineMode default lsmLines;
  72. end;
  73. TGLContourClass = class of TGLContour;
  74. TGLContours = class(TGLNotifyCollection)
  75. private
  76. function GetItems(index: Integer): TGLContour;
  77. procedure SetItems(index: Integer; const Value: TGLContour);
  78. protected
  79. public
  80. constructor Create(AOwner: TComponent); overload;
  81. function Add: TGLContour; inline;
  82. function FindItemID(ID: Integer): TGLContour; inline;
  83. property Items[index: Integer]: TGLContour read GetItems write SetItems; default;
  84. procedure GetExtents(var min, max: TAffineVector);
  85. end;
  86. TGLPolygonList = class(TPersistentObjectList)
  87. private
  88. FAktList: TAffineVectorList;
  89. function GetList(I: Integer): TAffineVectorList;
  90. public
  91. procedure Add;
  92. property AktList: TAffineVectorList read FAktList;
  93. property List[I: Integer]: TAffineVectorList read GetList;
  94. end;
  95. (* Multipolygon is defined with multiple contours.
  96. The contours have to be in the X-Y plane, otherwise they are projected
  97. to it (this is done automatically by the tesselator).
  98. The plane normal is pointing in +Z. All contours are automatically closed,
  99. so there is no need to specify the last node equal to the first one.
  100. Contours should be defined counterclockwise, the first contour (index = 0)
  101. is taken as is, all following are reversed. This means you can define the
  102. outer contour first and the holes and cutouts after that. If you give the
  103. following contours in clockwise order, the first contour is extended.
  104. TGLMultiPolygonBase will take the input contours and let the tesselator
  105. make an outline from it (this is done in RetreiveOutline). This outline is
  106. used for Rendering. Only when there are changes in the contours, the
  107. outline will be recalculated. The ouline in fact is a list of GLVectorLists. *)
  108. TGLMultiPolygonBase = class(TGLSceneObject)
  109. private
  110. FContours: TGLContours;
  111. FOutline: TGLPolygonList;
  112. FContoursNormal: TAffineVector;
  113. FAxisAlignedDimensionsCache: TVector;
  114. procedure SetContours(const Value: TGLContours);
  115. function GetPath(i: Integer): TGLContourNodes;
  116. procedure SetPath(i: Integer; const value: TGLContourNodes);
  117. function GetOutline: TGLPolygonList;
  118. procedure SetContoursNormal(const Value: TAffineVector);
  119. protected
  120. procedure RenderTesselatedPolygon(textured: Boolean;
  121. normal: PAffineVector; invertNormals: Boolean);
  122. procedure RetrieveOutline(List: TGLPolygonList);
  123. procedure ContourChanged(Sender: TObject); virtual;
  124. //property PNormal:PAffineVector read FPNormal;
  125. public
  126. constructor Create(AOwner: TComponent); override;
  127. destructor Destroy; override;
  128. procedure Assign(Source: TPersistent); override;
  129. procedure AddNode(const i: Integer; const coords: TGLCoordinates); overload;
  130. procedure AddNode(const i: Integer; const X, Y, Z: TGLfloat); overload;
  131. procedure AddNode(const i: Integer; const value: TVector); overload;
  132. procedure AddNode(const i: Integer; const value: TAffineVector); overload;
  133. property Path[i: Integer]: TGLContourNodes read GetPath write SetPath;
  134. property Outline: TGLPolygonList read GetOutline;
  135. property ContoursNormal: TAffineVector read FContoursNormal write SetContoursNormal;
  136. function AxisAlignedDimensionsUnscaled: TVector; override;
  137. procedure StructureChanged; override;
  138. published
  139. property Contours: TGLContours read FContours write SetContours;
  140. end;
  141. (* A polygon that can have holes and multiple contours.
  142. Use the Path property to access a contour or one of the AddNode methods
  143. to add a node to a contour (contours are allocated automatically). *)
  144. TGLMultiPolygon = class(TGLMultiPolygonBase)
  145. private
  146. FParts: TGLPolygonParts;
  147. protected
  148. procedure SetParts(const value: TGLPolygonParts);
  149. public
  150. constructor Create(AOwner: TComponent); override;
  151. procedure Assign(Source: TPersistent); override;
  152. procedure BuildList(var rci: TGLRenderContextInfo); override;
  153. published
  154. property Parts: TGLPolygonParts read FParts write SetParts default [ppTop, ppBottom];
  155. end;
  156. (* Page oriented pointer array, with persistent pointer target memory.
  157. In TVectorList a pointer to a vector will not be valid any more after
  158. a call to SetCapacity, which might be done implicitely during Add.
  159. The TGLVectorPool keeps memory in its original position during its
  160. whole lifetime. *)
  161. TGLVectorPool = class(TList)
  162. private
  163. FEntrySize: Integer; // size of each entry
  164. FPageSize: Integer; // number of entries per page
  165. FArrSize: Integer; // size of one page
  166. FUsedEntries: Integer; // used entries in actual page
  167. FAktArray: GLVectorGeometry.PByteArray; // pointer to actual page
  168. procedure CreatePage; // creates new page
  169. public
  170. constructor Create(APageSize, AEntrySize: Integer);
  171. destructor Destroy; override;
  172. { retrieve pointer to new entry. will create new page if needed }
  173. procedure GetNewVector(var P: Pointer);
  174. end;
  175. //-------------------------------------------------------------
  176. implementation
  177. //-------------------------------------------------------------
  178. //----------------------------------------
  179. // TGLVectorPool
  180. //----------------------------------------
  181. constructor TGLVectorPool.Create(APageSize, AEntrySize: Integer);
  182. begin
  183. inherited Create;
  184. Assert(APageSize > 0);
  185. Assert(AEntrySize > 0);
  186. FPageSize := APageSize;
  187. FEntrySize := AEntrySize;
  188. FArrSize := FPageSize * FEntrySize;
  189. CreatePage;
  190. end;
  191. procedure TGLVectorPool.CreatePage;
  192. begin
  193. GetMem(FAktArray, FArrSize);
  194. Add(FAktArray);
  195. FUsedEntries := 0;
  196. end;
  197. destructor TGLVectorPool.Destroy;
  198. var
  199. i: Integer;
  200. begin
  201. for i := Count - 1 downto 0 do
  202. FreeMem(Items[i], FArrSize);
  203. inherited;
  204. end;
  205. procedure TGLVectorPool.GetNewVector(var P: Pointer);
  206. begin
  207. if FUsedEntries >= FPageSize then
  208. CreatePage;
  209. Inc(FUsedEntries);
  210. P := @(FAktArray[(FUsedEntries - 1) * FEntrySize]);
  211. end;
  212. // ------------------
  213. // ------------------ TGLPolygonList ------------------
  214. // ------------------
  215. procedure TGLPolygonList.Add;
  216. begin
  217. FAktList := TAffineVectorList.Create;
  218. inherited Add(FAktList);
  219. end;
  220. function TGLPolygonList.GetList(i: Integer): TAffineVectorList;
  221. begin
  222. Result := TAffineVectorList(Items[i]);
  223. end;
  224. // ------------------
  225. // ------------------ TGLContour ------------------
  226. // ------------------
  227. constructor TGLContour.Create(Collection: TCollection);
  228. begin
  229. inherited;
  230. CreateNodes;
  231. FDivision := 10;
  232. FSplineMode := lsmLines;
  233. end;
  234. procedure TGLContour.CreateNodes;
  235. begin
  236. FNodes := TGLContourNodes.Create(Self);
  237. end;
  238. destructor TGLContour.Destroy;
  239. begin
  240. FNodes.Free;
  241. inherited;
  242. end;
  243. procedure TGLContour.Assign(Source: TPersistent);
  244. begin
  245. if Source is TGLContour then
  246. begin
  247. FNodes.Assign(TGLContour(Source).FNodes);
  248. FDivision := TGLContour(Source).FDivision;
  249. FSplineMode := TGLContour(Source).FSplineMode;
  250. FDescription := TGLContour(Source).FDescription;
  251. end
  252. else
  253. inherited;
  254. end;
  255. function TGLContour.GetDisplayName: string;
  256. begin
  257. result := Description;
  258. if result = '' then
  259. result := Format('GLContour: %d nodes', [Nodes.Count]);
  260. end;
  261. procedure TGLContour.NodesChanged(Sender: TObject);
  262. begin
  263. Changed(false);
  264. end;
  265. procedure TGLContour.SetDescription(const Value: string);
  266. begin
  267. FDescription := Value;
  268. end;
  269. procedure TGLContour.SetDivision(Value: Integer);
  270. begin
  271. if Value < 1 then
  272. Value := 1;
  273. if Value <> FDivision then
  274. begin
  275. FDivision := value;
  276. Changed(false);
  277. end;
  278. end;
  279. procedure TGLContour.SetNodes(const Value: TGLContourNodes);
  280. begin
  281. FNodes.Assign(Value);
  282. Changed(false);
  283. end;
  284. procedure TGLContour.SetSplineMode(const Value: TGLLineSplineMode);
  285. begin
  286. if FSplineMode <> value then
  287. begin
  288. FSplineMode := value;
  289. Changed(false);
  290. end;
  291. end;
  292. //-----------------------------
  293. // TGLContours
  294. //-----------------------------
  295. function TGLContours.Add: TGLContour;
  296. begin
  297. Result := TGLContour(inherited Add);
  298. end;
  299. constructor TGLContours.Create(AOwner: TComponent);
  300. begin
  301. Create(AOwner, TGLContour);
  302. end;
  303. function TGLContours.FindItemID(ID: Integer): TGLContour;
  304. begin
  305. result := TGLContour(inherited FindItemId(Id));
  306. end;
  307. function TGLContours.GetItems(index: Integer): TGLContour;
  308. begin
  309. result := TGLContour(inherited Items[index]);
  310. end;
  311. procedure TGLContours.SetItems(index: Integer; const Value: TGLContour);
  312. begin
  313. inherited Items[index] := value;
  314. end;
  315. procedure TGLContours.GetExtents(var min, max: TAffineVector);
  316. var
  317. i, k: Integer;
  318. lMin, lMax: TAffineVector;
  319. const
  320. cBigValue: Single = 1e30;
  321. cSmallValue: Single = -1e30;
  322. begin
  323. SetVector(min, cBigValue, cBigValue, cBigValue);
  324. SetVector(max, cSmallValue, cSmallValue, cSmallValue);
  325. for i := 0 to Count - 1 do
  326. begin
  327. GetItems(i).Nodes.GetExtents(lMin, lMax);
  328. for k := 0 to 2 do
  329. begin
  330. if lMin.V[k] < min.V[k] then min.V[k] := lMin.V[k];
  331. if lMax.V[k] > max.V[k] then max.V[k] := lMax.V[k];
  332. end;
  333. end;
  334. end;
  335. //---------------------------------
  336. // TGLMultiPolygonBase
  337. //---------------------------------
  338. constructor TGLMultiPolygonBase.Create(AOwner: TComponent);
  339. begin
  340. inherited;
  341. FContours := TGLContours.Create(Self);
  342. FContours.OnNotifyChange := ContourChanged;
  343. FContoursNormal := AffineVectorMake(0, 0, 1);
  344. FAxisAlignedDimensionsCache.X := -1;
  345. end;
  346. destructor TGLMultiPolygonBase.Destroy;
  347. begin
  348. if FOutline <> nil then
  349. begin
  350. FOutline.Clean;
  351. FreeAndNil(FOutline);
  352. end;
  353. FContours.Free;
  354. inherited;
  355. end;
  356. procedure TGLMultiPolygonBase.Assign(Source: TPersistent);
  357. begin
  358. if Source is TGLMultiPolygonBase then
  359. begin
  360. FContours.Assign(TGLMultiPolygonBase(Source).FContours);
  361. end;
  362. inherited;
  363. end;
  364. procedure TGLMultiPolygonBase.ContourChanged(Sender: TObject);
  365. begin
  366. if Assigned(FOutline) then
  367. begin
  368. // force a RetrieveOutline with next Render
  369. FOutline.Clean;
  370. FreeAndNil(FOutline);
  371. StructureChanged;
  372. end;
  373. end;
  374. procedure TGLMultiPolygonBase.AddNode(const i: Integer; const value: TVector);
  375. begin
  376. Path[i].AddNode(value);
  377. end;
  378. procedure TGLMultiPolygonBase.AddNode(const i: Integer; const x, y, z: TGLfloat);
  379. begin
  380. Path[i].AddNode(x, y, z);
  381. end;
  382. procedure TGLMultiPolygonBase.AddNode(const i: Integer; const coords: TGLCoordinates);
  383. begin
  384. Path[i].AddNode(coords);
  385. end;
  386. procedure TGLMultiPolygonBase.AddNode(const I: Integer; const value: TAffineVector);
  387. begin
  388. Path[i].AddNode(value);
  389. end;
  390. procedure TGLMultiPolygonBase.SetContours(const Value: TGLContours);
  391. begin
  392. FContours.Assign(Value);
  393. end;
  394. function TGLMultiPolygonBase.GetOutline: TGLPolygonList;
  395. begin
  396. if not Assigned(FOutline) then
  397. begin
  398. FOutline := TGLPolygonList.Create;
  399. RetrieveOutline(FOutline);
  400. end;
  401. Result := FOutline;
  402. end;
  403. function TGLMultiPolygonBase.GetPath(i: Integer): TGLContourNodes;
  404. begin
  405. Assert(i >= 0);
  406. while i >= Contours.Count do
  407. Contours.Add;
  408. Result := Contours[i].Nodes;
  409. end;
  410. procedure TGLMultiPolygonBase.SetPath(i: Integer; const value: TGLContourNodes);
  411. begin
  412. Assert(i >= 0);
  413. while i >= Contours.Count do
  414. Contours.Add;
  415. Contours[i].Nodes.Assign(value);
  416. end;
  417. //
  418. // Tessellation routines (OpenGL callbacks)
  419. //
  420. var
  421. vVertexPool: TGLVectorPool;
  422. procedure tessError(errno: Cardinal);
  423. {$IFDEF MSWINDOWS} stdcall;{$ELSE}cdecl;{$ENDIF}
  424. begin
  425. Assert(False, IntToStr(errno) + ' : ' + string(gluErrorString(errno)));
  426. end;
  427. procedure tessIssueVertex(vertexData: Pointer);
  428. {$IFDEF MSWINDOWS} stdcall;{$ELSE}cdecl;{$ENDIF}
  429. begin
  430. xgl.TexCoord2fv(vertexData);
  431. gl.Vertex3fv(vertexData);
  432. end;
  433. procedure tessCombine(coords: PDoubleVector; vertex_data: Pointer;
  434. weight: PGLFloat; var outData: Pointer);
  435. {$IFDEF MSWINDOWS} stdcall;{$ELSE}cdecl;{$ENDIF}
  436. begin
  437. vVertexPool.GetNewVector(outData);
  438. SetVector(PAffineVector(outData)^, coords^[0], coords^[1], coords^[2]);
  439. end;
  440. procedure tessBeginList(typ: Cardinal; polygonData: Pointer);
  441. {$IFDEF MSWINDOWS} stdcall;{$ELSE}cdecl;{$ENDIF}
  442. begin
  443. TGLPolygonList(polygonData).Add;
  444. end;
  445. procedure tessIssueVertexList(vertexData: Pointer; polygonData: Pointer);
  446. {$IFDEF MSWINDOWS} stdcall;{$ELSE}cdecl;{$ENDIF}
  447. begin
  448. TGLPolygonList(polygonData).AktList.Add(PAffineVector(vertexData)^);
  449. end;
  450. procedure TGLMultiPolygonBase.RetrieveOutline(List: TGLPolygonList);
  451. var
  452. i, n: Integer;
  453. tess: PGLUTesselator;
  454. procedure TesselatePath(contour: TGLContour; inverted: Boolean);
  455. procedure IssueVertex(v: TAffineVector);
  456. var
  457. dblVector: TAffineDblVector;
  458. p: PAffineVector;
  459. begin
  460. vVertexPool.GetNewVector(Pointer(p));
  461. p^ := v;
  462. SetVector(dblVector, v);
  463. gluTessVertex(tess, dblVector, p);
  464. end;
  465. var
  466. i, n: Integer;
  467. spline: TCubicSpline;
  468. f: Single;
  469. splineDivisions: Integer;
  470. nodes: TGLContourNodes;
  471. begin
  472. gluTessBeginContour(tess);
  473. nodes := contour.Nodes;
  474. if contour.SplineMode = lsmLines then
  475. splineDivisions := 0
  476. else
  477. splineDivisions := contour.Division;
  478. if splineDivisions > 1 then
  479. begin
  480. spline := nodes.CreateNewCubicSpline;
  481. try
  482. f := 1 / splineDivisions;
  483. n := splineDivisions * (nodes.Count - 1);
  484. if inverted then
  485. begin
  486. for i := n downto 0 do
  487. IssueVertex(spline.SplineAffineVector(i * f))
  488. end
  489. else
  490. begin
  491. for i := 0 to n do
  492. IssueVertex(spline.SplineAffineVector(i * f));
  493. end;
  494. finally
  495. spline.Free;
  496. end;
  497. end
  498. else
  499. begin
  500. n := nodes.Count - 1;
  501. if inverted then
  502. begin
  503. for i := n downto 0 do
  504. IssueVertex(nodes[i].AsAffineVector)
  505. end
  506. else
  507. begin
  508. for i := 0 to n do
  509. IssueVertex(nodes[i].AsAffineVector);
  510. end;
  511. end;
  512. gluTessEndContour(tess);
  513. end;
  514. begin
  515. List.Clear;
  516. if (Contours.Count > 0) and (Path[0].Count > 2) then
  517. begin
  518. // Vertex count
  519. n := 0;
  520. for i := 0 to Contours.Count - 1 do
  521. n := n + Path[i].Count;
  522. // Creates and initialize the GLU tesselator
  523. vVertexPool := TGLVectorPool.Create(n, SizeOf(TAffineVector));
  524. tess := gluNewTess;
  525. try
  526. // register callbacks
  527. gluTessCallback(tess, GLU_TESS_BEGIN_DATA, @tessBeginList);
  528. gluTessCallback(tess, GLU_TESS_END_DATA, nil);
  529. gluTessCallback(tess, GLU_TESS_VERTEX_DATA, @tessIssueVertexList);
  530. gluTessCallback(tess, GLU_TESS_ERROR, @tessError);
  531. gluTessCallback(tess, GLU_TESS_COMBINE, @tessCombine);
  532. // issue normal
  533. gluTessNormal(tess, FContoursNormal.X, FContoursNormal.Y, FContoursNormal.Z);
  534. // set properties
  535. gluTessProperty(Tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE);
  536. gluTessProperty(Tess, GLU_TESS_BOUNDARY_ONLY, GL_TRUE);
  537. gluTessBeginPolygon(tess, List);
  538. // outside contour
  539. TesselatePath(Contours[0], False);
  540. // inside contours
  541. for n := 1 to Contours.Count - 1 do
  542. TesselatePath(Contours[n], True);
  543. gluTessEndPolygon(tess);
  544. finally
  545. gluDeleteTess(tess);
  546. vVertexPool.Free;
  547. vVertexPool := nil;
  548. end;
  549. end;
  550. end;
  551. procedure TGLMultiPolygonBase.RenderTesselatedPolygon(textured: Boolean;
  552. normal: PAffineVector;
  553. invertNormals: Boolean);
  554. var
  555. tess: PGLUTesselator;
  556. procedure IssueVertex(v: TAffineVector);
  557. var
  558. dblVector: TAffineDblVector;
  559. p: PAffineVector;
  560. begin
  561. vVertexPool.GetNewVector(Pointer(p));
  562. p^ := v;
  563. SetVector(dblVector, v);
  564. gluTessVertex(tess, dblVector, p);
  565. end;
  566. var
  567. i, n: Integer;
  568. begin
  569. // call to Outline will call RetrieveOutline if necessary
  570. if (Outline.Count = 0) or (Outline.List[0].Count < 2) then
  571. Exit;
  572. // Vertex count
  573. n := 0;
  574. for i := 0 to Outline.Count - 1 do
  575. n := n + Outline.List[i].Count;
  576. // Creates and initialize a vertex pool and the GLU tesselator
  577. vVertexPool := TGLVectorPool.Create(n, Sizeof(TAffineVector));
  578. tess := gluNewTess;
  579. try
  580. gluTessCallback(tess, GLU_TESS_BEGIN, @gl.Begin_);
  581. if textured then
  582. gluTessCallback(tess, GLU_TESS_VERTEX, @tessIssueVertex)
  583. else
  584. gluTessCallback(tess, GLU_TESS_VERTEX, @gl.Vertex3fv);
  585. gluTessCallback(tess, GLU_TESS_END, @gl.End_);
  586. gluTessCallback(tess, GLU_TESS_ERROR, @tessError);
  587. gluTessCallback(tess, GLU_TESS_COMBINE, @tessCombine);
  588. // Issue normal
  589. if Assigned(normal) then
  590. begin
  591. gl.Normal3fv(PGLFloat(normal));
  592. gluTessNormal(tess, normal^.X, normal^.Y, normal^.Z);
  593. end;
  594. gluTessProperty(Tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE);
  595. // Issue polygon
  596. gluTessBeginPolygon(tess, nil);
  597. for n := 0 to Outline.Count - 1 do
  598. begin
  599. with Outline.List[n] do
  600. begin
  601. gluTessBeginContour(tess);
  602. if invertNormals then
  603. for i := Count - 1 downto 0 do
  604. IssueVertex(Items[i])
  605. else
  606. for i := 0 to Count - 1 do
  607. IssueVertex(Items[i]);
  608. gluTessEndContour(tess);
  609. end;
  610. end;
  611. gluTessEndPolygon(tess);
  612. finally
  613. gluDeleteTess(tess);
  614. vVertexPool.Free;
  615. vVertexPool := nil;
  616. end;
  617. end;
  618. // ------------------
  619. // ------------------ TGLMultiPolygon ------------------
  620. // ------------------
  621. constructor TGLMultiPolygon.Create(AOwner: TComponent);
  622. begin
  623. inherited;
  624. FParts := [ppTop, ppBottom];
  625. end;
  626. procedure TGLMultiPolygon.Assign(Source: TPersistent);
  627. begin
  628. if Source is TGLMultiPolygon then
  629. begin
  630. FParts := TGLMultiPolygon(Source).FParts;
  631. end;
  632. inherited;
  633. end;
  634. procedure TGLMultiPolygon.BuildList(var rci: TGLRenderContextInfo);
  635. var
  636. normal: TAffineVector;
  637. begin
  638. if (Outline.Count < 1) then
  639. Exit;
  640. normal := ContoursNormal;
  641. // Render
  642. // tessellate top polygon
  643. if ppTop in FParts then
  644. RenderTesselatedPolygon(True, @normal, False);
  645. // tessellate bottom polygon
  646. if ppBottom in FParts then
  647. begin
  648. NegateVector(normal);
  649. RenderTesselatedPolygon(True, @normal, True)
  650. end;
  651. end;
  652. procedure TGLMultiPolygon.SetParts(const value: TGLPolygonParts);
  653. begin
  654. if FParts <> value then
  655. begin
  656. FParts := value;
  657. StructureChanged;
  658. end;
  659. end;
  660. procedure TGLMultiPolygonBase.SetContoursNormal(const Value: TAffineVector);
  661. begin
  662. FContoursNormal := Value;
  663. end;
  664. function TGLMultiPolygonBase.AxisAlignedDimensionsUnscaled: TVector;
  665. var
  666. dMin, dMax: TAffineVector;
  667. begin
  668. if FAxisAlignedDimensionsCache.X < 0 then
  669. begin
  670. Contours.GetExtents(dMin, dMax);
  671. FAxisAlignedDimensionsCache.X := MaxFloat(Abs(dMin.X), Abs(dMax.X));
  672. FAxisAlignedDimensionsCache.Y := MaxFloat(Abs(dMin.Y), Abs(dMax.Y));
  673. FAxisAlignedDimensionsCache.Z := MaxFloat(Abs(dMin.Z), Abs(dMax.Z));
  674. end;
  675. SetVector(Result, FAxisAlignedDimensionsCache);
  676. end;
  677. procedure TGLMultiPolygonBase.StructureChanged;
  678. begin
  679. FAxisAlignedDimensionsCache.X := -1;
  680. inherited;
  681. end;
  682. // ------------------
  683. // ------------------ TGLContourNodes ------------------
  684. // ------------------
  685. procedure TGLContourNodes.NotifyChange;
  686. begin
  687. if (GetOwner <> nil) then
  688. (GetOwner as TGLContour).Changed(False);
  689. end;
  690. //-------------------------------------------------------------
  691. initialization
  692. //-------------------------------------------------------------
  693. RegisterClass(TGLMultiPolygon);
  694. end.