GLMesh.pas 23 KB

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