GLS.Mesh.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. //
  2. // The graphics engine GLScene https://github.com/glscene
  3. //
  4. unit GLS.Mesh;
  5. (*
  6. The unit is for simple meshes and legacy support, while GLS.VectorFileObjects
  7. implements more efficient though more complex mesh tools.
  8. The registered class is:
  9. [TGLMesh]
  10. *)
  11. interface
  12. {$I GLScene.Defines.inc}
  13. uses
  14. Winapi.OpenGL,
  15. Winapi.OpenGLext,
  16. System.Classes,
  17. System.SysUtils,
  18. GLScene.OpenGLTokens,
  19. GLScene.Strings,
  20. GLScene.VectorGeometry,
  21. GLScene.VectorTypes,
  22. GLS.XOpenGL,
  23. GLS.Context,
  24. GLS.Scene,
  25. GLS.State,
  26. GLS.Color,
  27. GLS.BaseClasses,
  28. GLS.RenderContextInfo;
  29. type
  30. TGLMeshMode = (mmTriangleStrip, mmTriangleFan, mmTriangles, mmQuadStrip,
  31. mmQuads, mmPolygon);
  32. TGLVertexMode = (vmV, vmVN, vmVNC, vmVNCT, vmVNT, vmVT);
  33. const
  34. cMeshModeToGLEnum: array[Low(TGLMeshMode)..High(TGLMeshMode)
  35. ] of Cardinal = (GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES,
  36. GL_QUAD_STRIP, GL_QUADS, GL_POLYGON);
  37. cVertexModeToGLEnum: array[Low(TGLVertexMode)..High(TGLVertexMode)
  38. ] of Cardinal = (GL_V3F, GL_N3F_V3F, GL_C4F_N3F_V3F, GL_T2F_C4F_N3F_V3F,
  39. GL_T2F_N3F_V3F, GL_T2F_V3F);
  40. type
  41. TGLVertexData = packed record
  42. textCoord: TTexPoint;
  43. color: TGLVector;
  44. normal: TAffineVector;
  45. coord: TVertex;
  46. end;
  47. PGLVertexData = ^TGLVertexData;
  48. TGLVertexDataArray = array[0..(MAXINT shr 6)] of TGLVertexData;
  49. PGLVertexDataArray = ^TGLVertexDataArray;
  50. (* Stores an interlaced vertex list for direct use in OpenGL.
  51. Locking (hardware passthrough) is supported, see "Locked" property for details. *)
  52. TGLVertexList = class(TGLUpdateAbleObject)
  53. private
  54. FValues: PGLVertexDataArray;
  55. FCount: Integer;
  56. FCapacity, FGrowth: Integer;
  57. FLockedOldValues: PGLVertexDataArray;
  58. protected
  59. procedure SetCapacity(const val: Integer);
  60. procedure SetGrowth(const val: Integer);
  61. procedure Grow;
  62. procedure SetVertices(index: Integer; const val: TGLVertexData);
  63. function GetVertices(index: Integer): TGLVertexData;
  64. procedure SetVertexCoord(index: Integer; const val: TAffineVector);
  65. function GetVertexCoord(index: Integer): TAffineVector;
  66. procedure SetVertexNormal(index: Integer; const val: TAffineVector);
  67. function GetVertexNormal(index: Integer): TAffineVector;
  68. procedure SetVertexTexCoord(index: Integer; const val: TTexPoint);
  69. function GetVertexTexCoord(index: Integer): TTexPoint;
  70. procedure SetVertexColor(index: Integer; const val: TVector4f);
  71. function GetVertexColor(index: Integer): TVector4f;
  72. function GetFirstEntry: PGLFloat;
  73. function GetFirstColor: PGLFloat;
  74. function GetFirstNormal: PGLFloat;
  75. function GetFirstVertex: PGLFloat;
  76. function GetFirstTexPoint: PGLFloat;
  77. function GetLocked: Boolean;
  78. procedure SetLocked(val: Boolean);
  79. public
  80. constructor Create(AOwner: TPersistent); override;
  81. destructor Destroy; override;
  82. function CreateInterpolatedCoords(list2: TGLVertexList; lerpFactor: Single): TGLVertexList;
  83. // Adds a vertex to the list, fastest method.
  84. procedure AddVertex(const vertexData: TGLVertexData); overload;
  85. // Adds a vertex to the list, fastest method for adding a triangle.
  86. procedure AddVertex3(const vd1, vd2, vd3: TGLVertexData); overload;
  87. (* Adds a vertex to the list.
  88. Use the NullVector, NullHmgVector or NullTexPoint constants for
  89. params you don't want to set. *)
  90. procedure AddVertex(const aVertex: TVertex; const aNormal: TAffineVector;
  91. const aColor: TGLColorVector; const aTexPoint: TTexPoint); overload;
  92. // Adds a vertex to the list, no texturing version.
  93. procedure AddVertex(const vertex: TVertex; const normal: TAffineVector;
  94. const color: TGLColorVector); overload;
  95. // Adds a vertex to the list, no texturing, not color version.
  96. procedure AddVertex(const vertex: TVertex; const normal: TAffineVector); overload;
  97. // Duplicates the vertex of given index and adds it at the end of the list.
  98. procedure DuplicateVertex(index: Integer);
  99. procedure Assign(Source: TPersistent); override;
  100. procedure Clear;
  101. property Vertices[index: Integer]: TGLVertexData read GetVertices write SetVertices; default;
  102. property VertexCoord[index: Integer]: TAffineVector read GetVertexCoord write SetVertexCoord;
  103. property VertexNormal[index: Integer]: TAffineVector read GetVertexNormal write SetVertexNormal;
  104. property VertexTexCoord[index: Integer]: TTexPoint read GetVertexTexCoord write SetVertexTexCoord;
  105. property VertexColor[index: Integer]: TVector4f read GetVertexColor write SetVertexColor;
  106. property Count: Integer read FCount;
  107. (* Capacity of the list (nb of vertex).
  108. Use this to allocate memory quickly before calling AddVertex. *)
  109. property Capacity: Integer read FCapacity write SetCapacity;
  110. (* Vertex capacity that will be added each time the list needs to grow.
  111. default value is 256 (chunks of approx 13 kb). *)
  112. property Growth: Integer read FGrowth write SetGrowth;
  113. // Calculates the sum of all vertex coords
  114. function SumVertexCoords: TAffineVector;
  115. // Calculates the extents of the vertice coords.
  116. procedure GetExtents(var min, max: TAffineVector);
  117. // Normalizes all normals.
  118. procedure NormalizeNormals;
  119. // Translate all coords by given vector
  120. procedure Translate(const v: TAffineVector);
  121. procedure DefineOpenGLArrays;
  122. property FirstColor: PGLFloat read GetFirstColor;
  123. property FirstEntry: PGLFloat read GetFirstEntry;
  124. property FirstNormal: PGLFloat read GetFirstNormal;
  125. property FirstVertex: PGLFloat read GetFirstVertex;
  126. property FirstTexPoint: PGLFloat read GetFirstTexPoint;
  127. (* Locking state of the vertex list.
  128. You can "Lock" a list to increase rendering performance on some
  129. OpenGL implementations (NVidia's). A Locked list size shouldn't be
  130. changed and calculations should be avoided.
  131. Performance can only be gained from a lock for osDirectDraw object,
  132. ie. meshes that are updated for each frame (the default build list
  133. mode is faster on static meshes).
  134. Be aware that the "Locked" state enforcement is not very strict
  135. to avoid performance hits, and GLScene may not always notify you
  136. that you're doing things you shouldn't on a locked list! *)
  137. property Locked: Boolean read GetLocked write SetLocked;
  138. procedure EnterLockSection;
  139. procedure LeaveLockSection;
  140. end;
  141. (* Basic mesh object.
  142. Each mesh holds a set of vertices and a Mode value defines how they make
  143. up the mesh (triangles, strips...) *)
  144. TGLMesh = class(TGLSceneObject)
  145. private
  146. FVertices: TGLVertexList;
  147. FMode: TGLMeshMode;
  148. FVertexMode: TGLVertexMode;
  149. FAxisAlignedDimensionsCache: TGLVector;
  150. protected
  151. procedure SetMode(AValue: TGLMeshMode);
  152. procedure SetVertices(AValue: TGLVertexList);
  153. procedure SetVertexMode(AValue: TGLVertexMode);
  154. procedure VerticesChanged(Sender: TObject);
  155. public
  156. constructor Create(AOwner: TComponent); override;
  157. destructor Destroy; override;
  158. procedure Assign(Source: TPersistent); override;
  159. procedure BuildList(var rci: TGLRenderContextInfo); override;
  160. procedure CalcNormals(Frontface: TGLFaceWinding);
  161. property Vertices: TGLVertexList read FVertices write SetVertices;
  162. function AxisAlignedDimensionsUnscaled: TGLVector; override;
  163. procedure StructureChanged; override;
  164. function Length: Single;
  165. function Area: Single;
  166. function Volume: Single;
  167. published
  168. property Mode: TGLMeshMode read FMode write SetMode;
  169. property VertexMode: TGLVertexMode read FVertexMode write SetVertexMode
  170. default vmVNCT;
  171. end;
  172. // ------------------------------------------------------------------
  173. implementation
  174. // ------------------------------------------------------------------
  175. // ----------------- TGLVertexList ------------------------------------------------
  176. constructor TGLVertexList.Create(AOwner: TPersistent);
  177. begin
  178. inherited;
  179. FValues := nil;
  180. FCount := 0;
  181. FCapacity := 0;
  182. FGrowth := 256;
  183. end;
  184. destructor TGLVertexList.Destroy;
  185. begin
  186. Locked := False;
  187. FreeMem(FValues);
  188. inherited;
  189. end;
  190. function TGLVertexList.CreateInterpolatedCoords(list2: TGLVertexList;
  191. lerpFactor: Single): TGLVertexList;
  192. var
  193. i: Integer;
  194. begin
  195. Assert(Count = list2.Count);
  196. Result := TGLVertexList.Create(nil);
  197. Result.Capacity := Count;
  198. Move(FValues[0], Result.FValues[0], Count * SizeOf(TGLVertexData));
  199. // interpolate vertices
  200. for i := 0 to Count - 1 do
  201. VectorLerp(FValues^[i].coord, list2.FValues^[i].coord, lerpFactor,
  202. Result.FValues^[i].coord);
  203. end;
  204. procedure TGLVertexList.SetCapacity(const val: Integer);
  205. begin
  206. Assert(not Locked, 'Cannot change locked list capacity !');
  207. FCapacity := val;
  208. if FCapacity < FCount then
  209. FCapacity := FCount;
  210. ReallocMem(FValues, FCapacity * SizeOf(TGLVertexData));
  211. end;
  212. procedure TGLVertexList.SetGrowth(const val: Integer);
  213. begin
  214. if val > 16 then
  215. FGrowth := val
  216. else
  217. FGrowth := 16;
  218. end;
  219. procedure TGLVertexList.Grow;
  220. begin
  221. Assert(not Locked, 'Cannot add to a locked list !');
  222. FCapacity := FCapacity + FGrowth;
  223. ReallocMem(FValues, FCapacity * SizeOf(TGLVertexData));
  224. end;
  225. function TGLVertexList.GetFirstColor: PGLFloat;
  226. begin
  227. Result := @(FValues^[0].color);
  228. end;
  229. function TGLVertexList.GetFirstEntry: PGLFloat;
  230. begin
  231. Result := Pointer(FValues);
  232. end;
  233. function TGLVertexList.GetFirstNormal: PGLFloat;
  234. begin
  235. Result := @(FValues^[0].normal);
  236. end;
  237. function TGLVertexList.GetFirstVertex: PGLFloat;
  238. begin
  239. Result := @(FValues^[0].coord);
  240. end;
  241. function TGLVertexList.GetFirstTexPoint: PGLFloat;
  242. begin
  243. Result := @(FValues^[0].textCoord);
  244. end;
  245. function TGLVertexList.GetLocked: Boolean;
  246. begin
  247. Result := Assigned(FLockedOldValues);
  248. end;
  249. procedure TGLVertexList.SetLocked(val: Boolean);
  250. var
  251. size: Integer;
  252. begin
  253. if val <> Locked then
  254. begin
  255. // Only supported with NVidia's right now
  256. if GL.NV_vertex_array_range and (CurrentGLContext <> nil) then
  257. begin
  258. size := FCount * SizeOf(TGLVertexData);
  259. if val then
  260. begin
  261. // Lock
  262. FLockedOldValues := FValues;
  263. {$IFDEF MSWINDOWS}
  264. FValues := gl.WAllocateMemoryNV(size, 0, 0, 0.5);
  265. {$ENDIF}
  266. {$IFDEF LINUX}
  267. FValues := gl.XAllocateMemoryNV(size, 0, 0, 0.5);
  268. {$ENDIF}
  269. if FValues = nil then
  270. begin
  271. FValues := FLockedOldValues;
  272. FLockedOldValues := nil;
  273. end
  274. else
  275. Move(FLockedOldValues^, FValues^, size);
  276. end
  277. else
  278. begin
  279. // Unlock
  280. {$IFDEF MSWINDOWS}
  281. gl.WFreeMemoryNV(FValues);
  282. {$ENDIF}
  283. {$IFDEF LINUX}
  284. gl.XFreeMemoryNV(FValues);
  285. {$ENDIF}
  286. FValues := FLockedOldValues;
  287. FLockedOldValues := nil;
  288. end;
  289. end;
  290. end;
  291. end;
  292. procedure TGLVertexList.EnterLockSection;
  293. begin
  294. if Locked then
  295. begin
  296. gl.VertexArrayRangeNV(FCount * SizeOf(TGLVertexData), FValues);
  297. gl.EnableClientState(GL_VERTEX_ARRAY_RANGE_NV);
  298. end;
  299. end;
  300. procedure TGLVertexList.LeaveLockSection;
  301. begin
  302. if Locked then
  303. begin
  304. gl.DisableClientState(GL_VERTEX_ARRAY_RANGE_NV);
  305. gl.FlushVertexArrayRangeNV;
  306. end;
  307. end;
  308. procedure TGLVertexList.SetVertices(index: Integer; const val: TGLVertexData);
  309. begin
  310. Assert(Cardinal(index) < Cardinal(Count));
  311. FValues^[index] := val;
  312. NotifyChange(Self);
  313. end;
  314. function TGLVertexList.GetVertices(index: Integer): TGLVertexData;
  315. begin
  316. Assert(Cardinal(index) < Cardinal(Count));
  317. Result := FValues^[index];
  318. end;
  319. procedure TGLVertexList.SetVertexCoord(index: Integer; const val: TAffineVector);
  320. begin
  321. FValues^[index].coord := val;
  322. NotifyChange(Self);
  323. end;
  324. function TGLVertexList.GetVertexCoord(index: Integer): TAffineVector;
  325. begin
  326. Result := FValues^[index].coord;
  327. end;
  328. procedure TGLVertexList.SetVertexNormal(index: Integer; const val: TAffineVector);
  329. begin
  330. FValues^[index].normal := val;
  331. NotifyChange(Self);
  332. end;
  333. function TGLVertexList.GetVertexNormal(index: Integer): TAffineVector;
  334. begin
  335. Result := FValues^[index].normal;
  336. end;
  337. procedure TGLVertexList.SetVertexTexCoord(index: Integer; const val: TTexPoint);
  338. begin
  339. FValues^[index].textCoord := val;
  340. NotifyChange(Self);
  341. end;
  342. function TGLVertexList.GetVertexTexCoord(index: Integer): TTexPoint;
  343. begin
  344. Result := FValues^[index].textCoord;
  345. end;
  346. procedure TGLVertexList.SetVertexColor(index: Integer; const val: TVector4f);
  347. begin
  348. FValues^[index].color := val;
  349. NotifyChange(Self);
  350. end;
  351. function TGLVertexList.GetVertexColor(index: Integer): TVector4f;
  352. begin
  353. Result := FValues^[index].color;
  354. end;
  355. procedure TGLVertexList.AddVertex(const vertexData: TGLVertexData);
  356. begin
  357. if FCount = FCapacity then
  358. Grow;
  359. FValues^[FCount] := vertexData;
  360. Inc(FCount);
  361. NotifyChange(Self);
  362. end;
  363. procedure TGLVertexList.AddVertex3(const vd1, vd2, vd3: TGLVertexData);
  364. begin
  365. // extend memory space
  366. if FCount + 2 >= FCapacity then
  367. Grow;
  368. // calculate destination address for new vertex data
  369. FValues^[FCount] := vd1;
  370. FValues^[FCount + 1] := vd2;
  371. FValues^[FCount + 2] := vd3;
  372. Inc(FCount, 3);
  373. NotifyChange(Self);
  374. end;
  375. procedure TGLVertexList.AddVertex(const aVertex: TVertex;
  376. const aNormal: TAffineVector; const aColor: TGLColorVector;
  377. const aTexPoint: TTexPoint);
  378. begin
  379. if FCount = FCapacity then
  380. Grow;
  381. // calculate destination address for new vertex data
  382. with FValues^[FCount] do
  383. begin
  384. textCoord := aTexPoint;
  385. color := aColor;
  386. normal := aNormal;
  387. coord := aVertex;
  388. end;
  389. Inc(FCount);
  390. NotifyChange(Self);
  391. end;
  392. procedure TGLVertexList.AddVertex(const vertex: TVertex;
  393. const normal: TAffineVector; const color: TGLColorVector);
  394. begin
  395. AddVertex(vertex, normal, color, NullTexPoint);
  396. end;
  397. procedure TGLVertexList.AddVertex(const vertex: TVertex;
  398. const normal: TAffineVector);
  399. begin
  400. AddVertex(vertex, normal, clrBlack, NullTexPoint);
  401. end;
  402. procedure TGLVertexList.DuplicateVertex(index: Integer);
  403. begin
  404. Assert(Cardinal(index) < Cardinal(Count));
  405. if FCount = FCapacity then
  406. Grow;
  407. FValues[FCount] := FValues[index];
  408. Inc(FCount);
  409. NotifyChange(Self);
  410. end;
  411. procedure TGLVertexList.Clear;
  412. begin
  413. Assert(not Locked, 'Cannot clear a locked list !');
  414. FreeMem(FValues);
  415. FCount := 0;
  416. FCapacity := 0;
  417. FValues := nil;
  418. NotifyChange(Self);
  419. end;
  420. function TGLVertexList.SumVertexCoords: TAffineVector;
  421. var
  422. i: Integer;
  423. begin
  424. Result := NullVector;
  425. for i := 0 to Count - 1 do
  426. AddVector(Result, FValues^[i].coord);
  427. end;
  428. procedure TGLVertexList.GetExtents(var min, max: TAffineVector);
  429. var
  430. i, k: Integer;
  431. f: Single;
  432. const
  433. cBigValue: Single = 1E50;
  434. cSmallValue: Single = -1E50;
  435. begin
  436. SetVector(min, cBigValue, cBigValue, cBigValue);
  437. SetVector(max, cSmallValue, cSmallValue, cSmallValue);
  438. for i := 0 to Count - 1 do
  439. begin
  440. with FValues^[i] do
  441. for k := 0 to 2 do
  442. begin
  443. f := coord.V[k];
  444. if f < min.V[k] then
  445. min.V[k] := f;
  446. if f > max.V[k] then
  447. max.V[k] := f;
  448. end;
  449. end;
  450. end;
  451. procedure TGLVertexList.NormalizeNormals;
  452. var
  453. i: Integer;
  454. begin
  455. for i := 0 to Count - 1 do
  456. NormalizeVector(FValues^[i].coord);
  457. end;
  458. procedure TGLVertexList.Translate(const v: TAffineVector);
  459. var
  460. i: Integer;
  461. begin
  462. for i := 0 to Count - 1 do
  463. AddVector(FValues^[i].coord, v);
  464. end;
  465. procedure TGLVertexList.DefineOpenGLArrays;
  466. begin
  467. gl.EnableClientState(GL_VERTEX_ARRAY);
  468. gl.VertexPointer(3, GL_FLOAT, SizeOf(TGLVertexData) - SizeOf(TAffineVector),
  469. FirstVertex);
  470. gl.EnableClientState(GL_NORMAL_ARRAY);
  471. gl.NormalPointer(GL_FLOAT, SizeOf(TGLVertexData) - SizeOf(TAffineVector),
  472. FirstNormal);
  473. xgl.EnableClientState(GL_TEXTURE_COORD_ARRAY);
  474. xgl.TexCoordPointer(2, GL_FLOAT, SizeOf(TGLVertexData) - SizeOf(TTexPoint),
  475. FirstTexPoint);
  476. end;
  477. procedure TGLVertexList.Assign(Source: TPersistent);
  478. begin
  479. if Assigned(Source) and (Source is TGLVertexList) then
  480. begin
  481. FCount := TGLVertexList(Source).FCount;
  482. FCapacity := FCount;
  483. ReallocMem(FValues, FCount * SizeOf(TGLVertexData));
  484. Move(TGLVertexList(Source).FValues^, FValues^, FCount * SizeOf(TGLVertexData));
  485. end
  486. else
  487. inherited Assign(Source);
  488. end;
  489. // ----------------- TGLMesh ------------------------------------------------------
  490. constructor TGLMesh.Create(AOwner: TComponent);
  491. begin
  492. inherited Create(AOwner);
  493. // ObjectStyle:=ObjectStyle+[osDirectDraw];
  494. FVertices := TGLVertexList.Create(Self);
  495. FVertices.AddVertex(XVector, ZVector, NullHmgVector, NullTexPoint);
  496. FVertices.AddVertex(YVector, ZVector, NullHmgVector, NullTexPoint);
  497. FVertices.AddVertex(ZVector, ZVector, NullHmgVector, NullTexPoint);
  498. FVertices.OnNotifyChange := VerticesChanged;
  499. FAxisAlignedDimensionsCache.X := -1;
  500. FVertexMode := vmVNCT;
  501. // should change this later to default to vmVN. But need to
  502. end; // change GLMeshPropform so that it greys out unused vertex info
  503. destructor TGLMesh.Destroy;
  504. begin
  505. FVertices.Free;
  506. inherited Destroy;
  507. end;
  508. procedure TGLMesh.VerticesChanged(Sender: TObject);
  509. begin
  510. StructureChanged;
  511. end;
  512. function TGLMesh.Length: Single;
  513. begin
  514. Result := 0;
  515. end;
  516. function TGLMesh.Area: Single;
  517. begin
  518. Result := 0;
  519. end;
  520. function TGLMesh.Volume: Single;
  521. begin
  522. Result := 0;
  523. end;
  524. procedure TGLMesh.BuildList(var rci: TGLRenderContextInfo);
  525. var
  526. VertexCount: Longint;
  527. begin
  528. inherited;
  529. if osDirectDraw in ObjectStyle then
  530. FVertices.EnterLockSection;
  531. case FVertexMode of
  532. vmV:
  533. gl.InterleavedArrays(GL_V3F, SizeOf(TGLVertexData), FVertices.FirstVertex);
  534. vmVN:
  535. gl.InterleavedArrays(GL_N3F_V3F, SizeOf(TGLVertexData),
  536. FVertices.FirstNormal);
  537. vmVNC:
  538. gl.InterleavedArrays(GL_C4F_N3F_V3F, SizeOf(TGLVertexData),
  539. FVertices.FirstColor);
  540. vmVNT, vmVNCT:
  541. gl.InterleavedArrays(GL_T2F_C4F_N3F_V3F, 0, FVertices.FirstEntry);
  542. vmVT:
  543. gl.InterleavedArrays(GL_T2F_V3F, 0, FVertices.FirstEntry);
  544. else
  545. Assert(False, strInterleaveNotSupported);
  546. end;
  547. if FVertexMode in [vmVNC, vmVNCT] then
  548. begin
  549. rci.GLStates.Enable(stColorMaterial);
  550. gl.ColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
  551. rci.GLStates.SetGLMaterialColors(cmFront, clrBlack, clrGray20, clrGray80,
  552. clrBlack, 0);
  553. rci.GLStates.SetGLMaterialColors(cmBack, clrBlack, clrGray20, clrGray80,
  554. clrBlack, 0);
  555. end;
  556. VertexCount := FVertices.Count;
  557. case FMode of
  558. mmTriangleStrip:
  559. gl.DrawArrays(GL_TRIANGLE_STRIP, 0, VertexCount);
  560. mmTriangleFan:
  561. gl.DrawArrays(GL_TRIANGLE_FAN, 0, VertexCount);
  562. mmTriangles:
  563. gl.DrawArrays(GL_TRIANGLES, 0, VertexCount);
  564. mmQuadStrip:
  565. gl.DrawArrays(GL_QUAD_STRIP, 0, VertexCount);
  566. mmQuads:
  567. gl.DrawArrays(GL_QUADS, 0, VertexCount);
  568. mmPolygon:
  569. gl.DrawArrays(GL_POLYGON, 0, VertexCount);
  570. else
  571. Assert(False);
  572. end;
  573. if osDirectDraw in ObjectStyle then
  574. FVertices.LeaveLockSection;
  575. end;
  576. procedure TGLMesh.SetMode(AValue: TGLMeshMode);
  577. begin
  578. if AValue <> FMode then
  579. begin
  580. FMode := AValue;
  581. StructureChanged;
  582. end;
  583. end;
  584. procedure TGLMesh.SetVertices(AValue: TGLVertexList);
  585. begin
  586. if AValue <> FVertices then
  587. begin
  588. FVertices.Assign(AValue);
  589. StructureChanged;
  590. end;
  591. end;
  592. procedure TGLMesh.SetVertexMode(AValue: TGLVertexMode);
  593. begin
  594. if AValue <> FVertexMode then
  595. begin
  596. FVertexMode := AValue;
  597. StructureChanged;
  598. end;
  599. end;
  600. procedure TGLMesh.CalcNormals(Frontface: TGLFaceWinding);
  601. var
  602. vn: TAffineFltVector;
  603. i, j: Integer;
  604. begin
  605. case FMode of
  606. mmTriangleStrip:
  607. with Vertices do
  608. for i := 0 to Count - 3 do
  609. begin
  610. if (Frontface = fwCounterClockWise) xor ((i and 1) = 0) then
  611. vn := CalcPlaneNormal(FValues^[i + 0].coord, FValues^[i + 1].coord,
  612. FValues^[i + 2].coord)
  613. else
  614. vn := CalcPlaneNormal(FValues^[i + 2].coord, FValues^[i + 1].coord,
  615. FValues^[i + 0].coord);
  616. FValues^[i].normal := vn;
  617. end;
  618. mmTriangles:
  619. with Vertices do
  620. for i := 0 to ((Count - 3) div 3) do
  621. begin
  622. j := i * 3;
  623. if Frontface = fwCounterClockWise then
  624. vn := CalcPlaneNormal(FValues^[j + 0].coord, FValues^[j + 1].coord,
  625. FValues^[j + 2].coord)
  626. else
  627. vn := CalcPlaneNormal(FValues^[j + 2].coord, FValues^[j + 1].coord,
  628. FValues^[j + 0].coord);
  629. FValues^[j + 0].normal := vn;
  630. FValues^[j + 1].normal := vn;
  631. FValues^[j + 2].normal := vn;
  632. end;
  633. mmQuads:
  634. with Vertices do
  635. for i := 0 to ((Count - 4) div 4) do
  636. begin
  637. j := i * 4;
  638. if Frontface = fwCounterClockWise then
  639. vn := CalcPlaneNormal(FValues^[j + 0].coord, FValues^[j + 1].coord,
  640. FValues^[j + 2].coord)
  641. else
  642. vn := CalcPlaneNormal(FValues^[j + 2].coord, FValues^[j + 1].coord,
  643. FValues^[j + 0].coord);
  644. FValues^[j + 0].normal := vn;
  645. FValues^[j + 1].normal := vn;
  646. FValues^[j + 2].normal := vn;
  647. FValues^[j + 3].normal := vn;
  648. end;
  649. mmPolygon:
  650. with Vertices do
  651. if Count > 2 then
  652. begin
  653. if Frontface = fwCounterClockWise then
  654. vn := CalcPlaneNormal(FValues^[0].coord, FValues^[1].coord,
  655. FValues^[2].coord)
  656. else
  657. vn := CalcPlaneNormal(FValues^[2].coord, FValues^[1].coord,
  658. FValues^[0].coord);
  659. for i := 0 to Count - 1 do
  660. FValues^[i].normal := vn;
  661. end;
  662. else
  663. Assert(False);
  664. end;
  665. StructureChanged;
  666. end;
  667. procedure TGLMesh.Assign(Source: TPersistent);
  668. begin
  669. if Assigned(Source) and (Source is TGLMesh) then
  670. begin
  671. FVertices.Assign(TGLMesh(Source).Vertices);
  672. FMode := TGLMesh(Source).FMode;
  673. FVertexMode := TGLMesh(Source).FVertexMode;
  674. end
  675. else
  676. inherited Assign(Source);
  677. end;
  678. function TGLMesh.AxisAlignedDimensionsUnscaled: TGLVector;
  679. var
  680. dMin, dMax: TAffineVector;
  681. begin
  682. if FAxisAlignedDimensionsCache.X < 0 then
  683. begin
  684. Vertices.GetExtents(dMin, dMax);
  685. FAxisAlignedDimensionsCache.X := MaxFloat(Abs(dMin.X), Abs(dMax.X));
  686. FAxisAlignedDimensionsCache.Y := MaxFloat(Abs(dMin.Y), Abs(dMax.Y));
  687. FAxisAlignedDimensionsCache.Z := MaxFloat(Abs(dMin.Z), Abs(dMax.Z));
  688. end;
  689. SetVector(Result, FAxisAlignedDimensionsCache);
  690. end;
  691. procedure TGLMesh.StructureChanged;
  692. begin
  693. FAxisAlignedDimensionsCache.X := -1;
  694. inherited;
  695. end;
  696. // ------------------------------------------------------------------
  697. initialization
  698. // ------------------------------------------------------------------
  699. RegisterClasses([TGLMesh]);
  700. end.