GLS.ODEUtils.pas 16 KB

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