GXS.Mesh.pas 22 KB

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