Physics.ODEUtils.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. //
  2. // The graphics platform GLScene https://github.com/glscene
  3. //
  4. unit Physics.ODEUtils;
  5. (* Open Dynamic Engine Utils
  6. Here is the collection of random functions and procedures that useful when
  7. integrating ODE into GLScene. If you don't use GLS.Scene, this unit won't be
  8. very useful to you. The unit is not intended as a sorted toolbox, but more
  9. as a place to put stuff until we figure out how to organize the integration.
  10. *)
  11. interface
  12. uses
  13. Winapi.OpenGL,
  14. System.SysUtils,
  15. System.Classes,
  16. ODE.Import,
  17. GLS.OpenGLTokens,
  18. GLS.Context,
  19. GLS.VectorGeometry,
  20. GLS.Scene,
  21. GLS.PersistentClasses,
  22. GLS.VectorTypes,
  23. GLS.VectorLists,
  24. GLS.Coordinates,
  25. GLS.Objects,
  26. GLS.VerletClothify,
  27. GLS.VectorFileObjects;
  28. procedure DrawBox(Sides: TdVector3);
  29. procedure setTransform(pos: TdVector3; R: TdMatrix3);
  30. procedure dsDrawBox(pos: PdVector3; R: PdMatrix3; Sides: TdVector3); overload;
  31. procedure dsDrawBox(pos: TdVector3; R: TdMatrix3; Sides: TdVector3); overload;
  32. procedure ODERToGLSceneMatrix(var m: TGLMatrix; R: TdMatrix3; pos: TdVector3); overload;
  33. procedure ODERToGLSceneMatrix(var m: TGLMatrix; R: PdMatrix3; pos: PdVector3); overload;
  34. procedure ODERToGLSceneMatrix(var m: TGLMatrix; R: TdMatrix3_As3x4; pos: TdVector3); overload;
  35. function GLSceneMatrixToODER(m: TGLMatrix): TdMatrix3;
  36. // Converting between ODE and GLScene formats
  37. function ConvertdVector3ToVector3f(R: TdVector3): TVector3f; overload;
  38. function ConvertdVector3ToVector3f(R: PdVector3): TVector3f; overload;
  39. function ConvertdVector3ToVector4f(R: TdVector3): TVector4f; overload;
  40. function ConvertdVector3ToVector4f(R: PdVector3): TVector4f; overload;
  41. function ConvertdVector3ToAffineVector(R: PdVector3): TAffineVector; overload;
  42. function ConvertdVector3ToAffineVector(R: TdVector3): TAffineVector; overload;
  43. function GetBodyPositionAsAffineVector(Body: PdxBody): TAffineVector;
  44. // Converting between GLScene and ODE formats
  45. function ConvertVector3fTodVector3(R: TVector3f): TdVector3;
  46. function ConvertVector3fToPdVector3(R: TVector3f): PdVector3;
  47. function ConvertVector4fTodVector3(R: TVector4f): TdVector3;
  48. function ConvertVector4fToPdVector3(R: TVector4f): PdVector3;
  49. function dVector3Length(R: TdVector3): single; overload;
  50. function dVector3Length(R: PdVector3): single; overload;
  51. function dBodyToBodyDistance(Body1, Body2: PdxBody): TdReal;
  52. procedure CopyPosFromGeomToGL(Geom: PdxGeom; GLBaseSceneObject: TGLBaseSceneObject);
  53. procedure PositionSceneObject(GLBaseSceneObject: TGLBaseSceneObject; Geom: PdxGeom);
  54. procedure PositionSceneObjectForGeom(Geom: PdxGeom);
  55. procedure CopyCubeSizeFromBox(Cube: TGLCube; Geom: PdxGeom);
  56. procedure CopyBodyFromCube(Body: PdxBody; var Geom: PdxGeom; Cube: TGLCube; Space: PdxSpace);
  57. function CreateGeomFromCube(Cube: TGLCube; Space: PdxSpace): PdxGeom;
  58. function CreateBodyFromCube(var Geom: PdxGeom; Cube: TGLCube; World: PdxWorld; Space: PdxSpace): PdxBody;
  59. (* This method requires you to manually deallocate vertices and
  60. indices when you're done with the trimesh *)
  61. function CreateTriMeshFromBaseMesh(
  62. GLBaseMesh: TGLBaseMesh;
  63. Space: PdxSpace;
  64. var Vertices: PdVector3Array;
  65. var Indices: PdIntegerArray): PdxGeom;
  66. function GLMatrixFromGeom(Geom: PdxGeom): TGLMatrix;
  67. function GLDirectionFromGeom(Geom: PdxGeom): TGLVector;
  68. function CreateODEPlaneFromGLPlane(Plane: TGLPlane; Space: PdxSpace): PdxGeom;
  69. procedure RenderGeomList(GeomList: TGeomList);
  70. function RandomColorVector: TGLVector;
  71. {.$ EXTERNALSYM GL_ZERO}
  72. //---------------------------------------------------------------------------
  73. implementation
  74. //---------------------------------------------------------------------------
  75. procedure ODERToGLSceneMatrix(var m: TGLMatrix; R: TdMatrix3_As3x4; pos: TdVector3); overload;
  76. begin
  77. m.X.X := r[0][0];
  78. m.X.Y := r[0][1];
  79. m.X.Z := r[0][2];
  80. m.X.W := 0;
  81. m.Y.X := r[1][0];
  82. m.Y.Y := r[1][1];
  83. m.Y.Z := r[1][2];
  84. m.Y.W := 0;
  85. m.Z.X := r[2][0];
  86. m.Z.Y := r[2][1];
  87. m.Z.Z := r[2][2];
  88. m.Z.W := 0;
  89. m.W := NullHmgPoint;
  90. TransposeMatrix(m);
  91. m.W.X := pos[0];
  92. m.W.Y := pos[1];
  93. m.W.Z := pos[2];
  94. m.W.W := 1; //}
  95. end;
  96. //----------------------------------------------------
  97. procedure ODERToGLSceneMatrix(var m: TGLMatrix; R: PdMatrix3; pos: PdVector3);
  98. begin
  99. ODERToGLSceneMatrix(m, TdMatrix3_As3x4(R^), pos^);
  100. end;
  101. //----------------------------------------------------
  102. procedure ODERToGLSceneMatrix(var m: TGLMatrix; R: TdMatrix3; pos: TdVector3);
  103. begin
  104. ODERToGLSceneMatrix(m, TdMatrix3_As3x4(R), pos);
  105. end;
  106. //----------------------------------------------------
  107. procedure DrawBox(Sides: TdVector3);
  108. var
  109. lx, ly, lz: single;
  110. begin
  111. lx := Sides[0] * 0.5;
  112. ly := Sides[1] * 0.5;
  113. lz := Sides[2] * 0.5;
  114. // sides
  115. gl.Begin_(GL_TRIANGLE_STRIP);
  116. gl.Normal3f(-1, 0, 0);
  117. gl.Vertex3f(-lx, -ly, -lz);
  118. gl.Vertex3f(-lx, -ly, lz);
  119. gl.Vertex3f(-lx, ly, -lz);
  120. gl.Vertex3f(-lx, ly, lz);
  121. gl.Normal3f(0, 1, 0);
  122. gl.Vertex3f(lx, ly, -lz);
  123. gl.Vertex3f(lx, ly, lz);
  124. gl.Normal3f(1, 0, 0);
  125. gl.Vertex3f(lx, -ly, -lz);
  126. gl.Vertex3f(lx, -ly, lz);
  127. gl.Normal3f(0, -1, 0);
  128. gl.Vertex3f(-lx, -ly, -lz);
  129. gl.Vertex3f(-lx, -ly, lz);
  130. gl.End_();
  131. // top face
  132. gl.Begin_(GL_TRIANGLE_FAN);
  133. gl.Normal3f(0, 0, 1);
  134. gl.Vertex3f(-lx, -ly, lz);
  135. gl.Vertex3f(lx, -ly, lz);
  136. gl.Vertex3f(lx, ly, lz);
  137. gl.Vertex3f(-lx, ly, lz);
  138. gl.End_();
  139. // bottom face
  140. gl.Begin_(GL_TRIANGLE_FAN);
  141. gl.Normal3f(0, 0, -1);
  142. gl.Vertex3f(-lx, -ly, -lz);
  143. gl.Vertex3f(-lx, ly, -lz);
  144. gl.Vertex3f(lx, ly, -lz);
  145. gl.Vertex3f(lx, -ly, -lz);
  146. gl.End_();
  147. end;
  148. //----------------------------------------------------
  149. function GLSceneMatrixToODER(m: TGLMatrix): TdMatrix3;
  150. begin
  151. TransposeMatrix(m);
  152. Result[0] := m.X.X;
  153. Result[1] := m.X.Y;
  154. Result[2] := m.X.Z;
  155. Result[4] := m.Y.X;
  156. Result[5] := m.Y.Y;
  157. Result[6] := m.Y.Z;
  158. Result[8] := m.Z.X;
  159. Result[9] := m.Z.Y;
  160. Result[10] := m.Z.Z;
  161. end;
  162. //----------------------------------------------------
  163. procedure dsDrawBox(pos: PdVector3; R: PdMatrix3; Sides: TdVector3);
  164. begin
  165. dsDrawBox(pos^, r^, Sides);
  166. end;
  167. //----------------------------------------------------
  168. procedure dsDrawBox(pos: TdVector3; R: TdMatrix3; Sides: TdVector3);
  169. begin
  170. setTransform(pos, R);
  171. drawBox(sides);
  172. gl.PopMatrix();
  173. end;
  174. procedure setTransform(pos: TdVector3; R: TdMatrix3);
  175. var
  176. matrix: array[0..15] of Single;
  177. begin
  178. matrix[0] := R[0];
  179. matrix[1] := R[4];
  180. matrix[2] := R[8];
  181. matrix[3] := 0;
  182. matrix[4] := R[1];
  183. matrix[5] := R[5];
  184. matrix[6] := R[9];
  185. matrix[7] := 0;
  186. matrix[8] := R[2];
  187. matrix[9] := R[6];
  188. matrix[10] := R[10];
  189. matrix[11] := 0;
  190. matrix[12] := pos[0];
  191. matrix[13] := pos[1];
  192. matrix[14] := pos[2];
  193. matrix[15] := 1;
  194. gl.PushMatrix();
  195. gl.MultMatrixf(@matrix);
  196. end;
  197. (*$WARNINGS OFF*)
  198. //----------------------------------------------------
  199. function ConvertdVector3ToVector3f(R: TdVector3): TVector3f;
  200. begin
  201. result.X := R[0];
  202. result.Y := R[1];
  203. result.Z := R[2];
  204. end;
  205. //----------------------------------------------------
  206. function ConvertdVector3ToVector3f(R: PdVector3): TVector3f;
  207. begin
  208. result.X := R[0];
  209. result.Y := R[1];
  210. result.Z := R[2];
  211. end;
  212. //----------------------------------------------------
  213. function ConvertdVector3ToVector4f(R: TdVector3): TVector4f; overload;
  214. begin
  215. result.X := R[0];
  216. result.Y := R[1];
  217. result.Z := R[2];
  218. result.W := 0;
  219. end;
  220. //----------------------------------------------------
  221. function ConvertdVector3ToVector4f(R: PdVector3): TVector4f; overload;
  222. begin
  223. result.X := R[0];
  224. result.Y := R[1];
  225. result.Z := R[2];
  226. result.W := 0;
  227. end;
  228. //----------------------------------------------------
  229. function ConvertdVector3ToAffineVector(R: PdVector3): TAffineVector; overload;
  230. begin
  231. result.X := R[0];
  232. result.Y := R[1];
  233. result.Z := R[2];
  234. end;
  235. //----------------------------------------------------
  236. function ConvertdVector3ToAffineVector(R: TdVector3): TAffineVector; overload;
  237. begin
  238. result.X := R[0];
  239. result.Y := R[1];
  240. result.Z := R[2];
  241. end;
  242. //----------------------------------------------------
  243. function ConvertVector3fTodVector3(R: TVector3f): TdVector3;
  244. begin
  245. result[0] := R.X;
  246. result[1] := R.Y;
  247. result[2] := R.Z;
  248. end;
  249. //----------------------------------------------------
  250. function ConvertVector3fToPdVector3(R: TVector3f): PdVector3;
  251. begin
  252. result[0] := R.X;
  253. result[1] := R.Y;
  254. result[2] := R.Z;
  255. end;
  256. //----------------------------------------------------
  257. function ConvertVector4fTodVector3(R: TVector4f): TdVector3;
  258. begin
  259. result[0] := R.X;
  260. result[1] := R.Y;
  261. result[2] := R.Z;
  262. result[3] := 0;
  263. end;
  264. //----------------------------------------------------
  265. function ConvertVector4fToPdVector3(R: TVector4f): PdVector3;
  266. begin
  267. result[0] := R.X;
  268. result[1] := R.Y;
  269. result[2] := R.Z;
  270. result[3] := 0;
  271. end;
  272. (*$WARNINGS ON*)
  273. function GetBodyPositionAsAffineVector(Body: PdxBody): TAffineVector;
  274. begin
  275. result := ConvertdVector3ToVector3f(dBodyGetPosition(Body));
  276. end;
  277. //----------------------------------------------------
  278. procedure PositionSceneObjectForGeom(Geom: PdxGeom);
  279. begin
  280. if Assigned(Geom.Data) then
  281. PositionSceneObject(TGLBaseSceneObject(Geom.Data), Geom);
  282. end;
  283. //----------------------------------------------------
  284. function GLMatrixFromGeom(Geom: PdxGeom): TGLMatrix;
  285. var
  286. pos, Pos2: PdVector3;
  287. R, R2: PdMatrix3;
  288. actual_pos: TdVector3;
  289. actual_R: TdMatrix3;
  290. TransformedGeom: PdxGeom;
  291. GeomClass: integer;
  292. begin
  293. // Retrieve the position and rotation of the geom
  294. pos := dGeomGetPosition(geom);
  295. R := dGeomGetRotation(geom);
  296. // if the geom is a transform geom, it should be treated differently
  297. GeomClass := dGeomGetClass(Geom);
  298. if GeomClass = dGeomTransformClass then
  299. begin
  300. TransformedGeom := dGeomTransformGetGeom(Geom);
  301. // No transformed geom!?
  302. if TransformedGeom = nil then
  303. exit;
  304. // Retrieve the position and rotation of the transformed geom
  305. pos2 := dGeomGetPosition(TransformedGeom);
  306. R2 := dGeomGetRotation(TransformedGeom);
  307. dMULTIPLY0_331(actual_pos, R^, pos2^);
  308. actual_pos := Vector3ADD(actual_pos, pos^);
  309. dMULTIPLY0_333(actual_R, R^, R2^);
  310. ODERToGLSceneMatrix(result, actual_R, actual_pos);
  311. end
  312. else
  313. begin
  314. ODERToGLSceneMatrix(result, R, pos);
  315. end;
  316. end;
  317. //----------------------------------------------------
  318. function GLDirectionFromGeom(Geom: PdxGeom): TGLVector;
  319. var
  320. m: TGLMatrix;
  321. begin
  322. m := GLMatrixFromGeom(Geom);
  323. result := VectorNormalize(m.Z);
  324. end;
  325. //----------------------------------------------------
  326. procedure PositionSceneObject(GLBaseSceneObject: TGLBaseSceneObject; Geom: PdxGeom);
  327. var
  328. Scale: TAffineVector;
  329. begin
  330. Scale := GLBaseSceneObject.Scale.AsAffineVector;
  331. GLBaseSceneObject.SetMatrix(GLMatrixFromGeom(Geom));
  332. GLBaseSceneObject.Scale.AsAffineVector := Scale;
  333. end;
  334. procedure CopyCubeSizeFromBox(Cube: TGLCube; Geom: PdxGeom);
  335. var
  336. Sides: TdVector3;
  337. begin
  338. dGeomBoxGetLengths(Geom, Sides);
  339. Cube.CubeWidth := Sides[0]; // 0
  340. Cube.CubeHeight := Sides[1]; // 1
  341. Cube.CubeDepth := Sides[2]; // 2
  342. end;
  343. //----------------------------------------------------
  344. procedure CopyPosFromGeomToGL(Geom: PdxGeom; GLBaseSceneObject: TGLBaseSceneObject);
  345. var
  346. v: TGLVector;
  347. m: TGLMatrix;
  348. R: PdMatrix3;
  349. pos: PdVector3;
  350. begin
  351. v := GLBaseSceneObject.AbsolutePosition;
  352. dGeomSetPosition(Geom, v.X, v.Y, v.Z);
  353. R := dGeomGetRotation(Geom);
  354. pos := dgeomGetPosition(Geom);
  355. m := GLBaseSceneObject.AbsoluteMatrix;
  356. R[0] := m.X.X;
  357. R[4] := m.X.Y;
  358. R[8] := m.X.Z;
  359. R[1] := m.Y.X;
  360. R[5] := m.Y.Y;
  361. R[9] := m.Y.Z;
  362. R[2] := m.Z.X;
  363. R[6] := m.Z.Y;
  364. R[10] := m.Z.Z;
  365. pos[0] := m.W.X;
  366. pos[1] := m.W.Y;
  367. pos[2] := m.W.Z; //}
  368. dGeomSetRotation(Geom, R^);
  369. end;
  370. //----------------------------------------------------
  371. function CreateGeomFromCube(Cube: TGLCube; Space: PdxSpace): PdxGeom;
  372. var
  373. Geom: PdxGeom;
  374. begin
  375. Geom := dCreateBox(Space, Cube.CubeWidth, Cube.CubeHeight, Cube.CubeDepth);
  376. CopyPosFromGeomToGL(Geom, Cube);
  377. result := Geom;
  378. end;
  379. //----------------------------------------------------
  380. function CreateBodyFromCube(var Geom: PdxGeom; Cube: TGLCube; World: PdxWorld; Space: PdxSpace): PdxBody;
  381. var
  382. Body: PdxBody;
  383. begin
  384. Body := dBodyCreate(World);
  385. try
  386. dBodySetLinearVel(Body, 0, 0, 0);
  387. CopyBodyFromCube(Body, Geom, Cube, Space);
  388. finally
  389. result := Body;
  390. end;
  391. end;
  392. //----------------------------------------------------
  393. function CreateTriMeshFromBaseMesh(
  394. GLBaseMesh: TGLBaseMesh;
  395. Space: PdxSpace;
  396. var Vertices: PdVector3Array;
  397. var Indices: PdIntegerArray): PdxGeom;
  398. var
  399. i, j, p: integer;
  400. FaceExtractor: TGLFaceExtractor;
  401. VertexCount: integer;
  402. Vertex: TAffineVector;
  403. OffsetList: TGLIntegerList;
  404. Face: TGLFace;
  405. iMO: integer;
  406. TriMeshData: PdxTriMeshData;
  407. begin
  408. OffsetList := nil;
  409. FaceExtractor := TGLFaceExtractor.Create(GLBaseMesh);
  410. try
  411. OffsetList := TGLIntegerList.Create;
  412. FaceExtractor.ProcessMesh;
  413. VertexCount := 0;
  414. for i := 0 to GLBaseMesh.MeshObjects.Count - 1 do
  415. VertexCount := VertexCount + GLBaseMesh.MeshObjects[i].Vertices.Count;
  416. Vertices := AllocMem(sizeOf(TdVector3) * VertexCount);
  417. Indices := AllocMem(sizeOf(integer) * FaceExtractor.FaceList.Count * 3);
  418. // Copy all vertices
  419. p := 0;
  420. for i := 0 to GLBaseMesh.MeshObjects.Count - 1 do
  421. begin
  422. OffsetList.Add(p);
  423. for j := 0 to GLBaseMesh.MeshObjects[i].Vertices.Count - 1 do
  424. begin
  425. Vertex :=
  426. GLBaseMesh.LocalToAbsolute(GLBaseMesh.MeshObjects[i].Vertices[j]);
  427. Vertices^[p, 0] := Vertex.X;
  428. Vertices^[p, 1] := Vertex.Y;
  429. Vertices^[p, 2] := Vertex.Z;
  430. Vertices^[p, 3] := 0;
  431. inc(p);
  432. end;
  433. end;
  434. // Copy all triangles
  435. p := 0;
  436. for i := 0 to FaceExtractor.FaceList.Count - 1 do
  437. begin
  438. Face := FaceExtractor.FaceList[i];
  439. iMO := GLBaseMesh.MeshObjects.IndexOf(Face.MeshObject);
  440. Indices^[p] := Face.Vertices[0] + OffsetList[iMO];
  441. inc(p);
  442. Indices^[p] := Face.Vertices[1] + OffsetList[iMO];
  443. inc(p);
  444. Indices^[p] := Face.Vertices[2] + OffsetList[iMO];
  445. inc(p);
  446. end;
  447. TriMeshData := dGeomTriMeshDataCreate;
  448. dGeomTriMeshDataBuildSimple(
  449. TriMeshData,
  450. Vertices, VertexCount,
  451. Indices, FaceExtractor.FaceList.Count * 3);
  452. result := dCreateTriMesh(space, TriMeshData, nil, nil, nil);
  453. finally
  454. FaceExtractor.Free;
  455. if OffsetList <> nil then
  456. OffsetList.Free;
  457. end;
  458. end;
  459. //----------------------------------------------------
  460. procedure CopyBodyFromCube(Body: PdxBody; var Geom: PdxGeom; Cube: TGLCube;
  461. Space: PdxSpace);
  462. var
  463. m: TdMass;
  464. begin
  465. // Stup the body
  466. dMassSetBox(m, 1, Cube.CubeWidth, Cube.CubeHeight, Cube.CubeDepth);
  467. if m.mass>0 then dBodySetMass(Body, @m);
  468. // Setup the geom
  469. Geom := CreateGeomFromCube(Cube, Space);
  470. dGeomSetBody(Geom, Body);
  471. CopyPosFromGeomToGL(Geom, Cube);
  472. Geom.data := Cube;
  473. end;
  474. //----------------------------------------------------
  475. function dBodyToBodyDistance(Body1, Body2: PdxBody): TdReal;
  476. begin
  477. result := dVector3Length(Vector3SUB(Body1.posr.pos, Body2.posr.pos));
  478. end;
  479. function dVector3Length(R: TdVector3): single;
  480. begin
  481. result := Sqrt(sqr(R[0]) + sqr(R[1]) + sqr(R[2]));
  482. end;
  483. function dVector3Length(R: PdVector3): single;
  484. begin
  485. result := Sqrt(sqr(R[0]) + sqr(R[1]) + sqr(R[2]));
  486. end;
  487. procedure RenderGeomList(GeomList: TGeomList);
  488. var
  489. i: integer;
  490. begin
  491. for i := 0 to GeomList.Count - 1 do
  492. if Assigned(GeomList[i].data) then
  493. PositionSceneObject(TGLBaseSceneObject(GeomList[i].data), GeomList[i]);
  494. end;
  495. //----------------------------------------------------
  496. function CreateODEPlaneFromGLPlane(Plane: TGLPlane; Space: PdxSpace): PdxGeom;
  497. var
  498. Pos, Direction: TGLVector;
  499. d: single;
  500. begin
  501. Direction := Plane.AbsoluteDirection;
  502. Pos := Plane.AbsolutePosition;
  503. d := (Direction.X * Pos.X +
  504. Direction.Y * Pos.Y +
  505. Direction.Z * Pos.Z);
  506. result := dCreatePlane(space, Direction.X, Direction.Y, Direction.Z, d);
  507. end;
  508. function RandomColorVector: TGLVector;
  509. begin
  510. result := VectorMake(Random, Random, Random, 1);
  511. end;
  512. end.