GXS.DCEMisc.pas 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. // *
  2. // The graphics engine GXScene https://github.com/glscene
  3. //
  4. unit GXS.DCEMisc;
  5. (* Miscelaneous functions used by DCE (Dynamic Collision Engine) *)
  6. interface
  7. {$I Stage.Defines.inc}
  8. uses
  9. GXS.Coordinates,
  10. GXS.VectorFileObjects,
  11. GXS.EllipseCollision,
  12. Stage.VectorGeometry,
  13. GXS.VectorLists,
  14. GXS.Scene,
  15. GXS.TerrainRenderer,
  16. GXS.ProxyObjects,
  17. GXS.MultiProxy,
  18. Stage.VectorTypes;
  19. //Calculate and set the collision range
  20. procedure ECSetCollisionRange(var MovePack: TECMovePack);
  21. //Set the collider lists to null
  22. procedure ECResetColliders(var MovePack: TECMovePack);
  23. //Add freeform's octree data
  24. procedure ECAddFreeForm(var MovePack: TECMovePack; FreeForm: TgxBaseSceneObject;
  25. Solid: Boolean; ObjectID: Integer);
  26. //Add a TriMesh box
  27. procedure ECAddBox(var MovePack: TECMovePack;
  28. BoxObj: TgxBaseSceneObject; BoxSize: TAffineVector;
  29. Solid: Boolean; ObjectID: Integer);
  30. //Add the terrain as a TriMesh
  31. procedure ECAddTerrain(var MovePack: TECMovePack;
  32. TerrainRenderer: TgxTerrainRenderer; Resolution: Single;
  33. Solid: Boolean; ObjectID: Integer);
  34. //Add a static ellipsoid
  35. procedure ECAddEllipsoid(var MovePack: TECMovePack;
  36. ePos, eRadius: TAffineVector;
  37. Solid: Boolean; ObjectID: Integer);
  38. const
  39. DCEBox: array [0..35] of TAffineVector = (
  40. (X: 1; Y:-1; Z:-1), (X: 1; Y: 1; Z:-1), (X: 1; Y:-1; Z: 1),
  41. (X: 1; Y: 1; Z:-1), (X: 1; Y: 1; Z: 1), (X: 1; Y:-1; Z: 1),
  42. (X: 1; Y: 1; Z:-1), (X:-1; Y: 1; Z:-1), (X:-1; Y: 1; Z: 1),
  43. (X: 1; Y: 1; Z: 1), (X: 1; Y: 1; Z:-1), (X:-1; Y: 1; Z: 1),
  44. (X:-1; Y: 1; Z: 1), (X:-1; Y:-1; Z: 1), (X: 1; Y:-1; Z: 1),
  45. (X: 1; Y: 1; Z: 1), (X:-1; Y: 1; Z: 1), (X: 1; Y:-1; Z: 1),
  46. (X:-1; Y:-1; Z: 1), (X:-1; Y: 1; Z: 1), (X:-1; Y: 1; Z:-1),
  47. (X:-1; Y:-1; Z:-1), (X:-1; Y:-1; Z: 1), (X:-1; Y: 1; Z:-1),
  48. (X: 1; Y:-1; Z: 1), (X:-1; Y:-1; Z: 1), (X: 1; Y:-1; Z:-1),
  49. (X:-1; Y:-1; Z: 1), (X:-1; Y:-1; Z:-1), (X: 1; Y:-1; Z:-1),
  50. (X: 1; Y: 1; Z:-1), (X: 1; Y:-1; Z:-1), (X:-1; Y: 1; Z:-1),
  51. (X: 1; Y:-1; Z:-1), (X:-1; Y:-1; Z:-1), (X:-1; Y: 1; Z:-1)
  52. );
  53. implementation //-------------------------------------------------------------
  54. procedure ECSetCollisionRange(var MovePack: TECMovePack);
  55. var N: TAffineVector;
  56. begin
  57. N.X := Abs(MovePack.Velocity.X) + Abs(MovePack.Gravity.X) + (MovePack.Radius.X);
  58. N.Y := Abs(MovePack.Velocity.Y) + Abs(MovePack.Gravity.Y) + (MovePack.Radius.Y);
  59. N.Z := Abs(MovePack.Velocity.Z) + Abs(MovePack.Gravity.Z) + (MovePack.Radius.Z);
  60. MovePack.CollisionRange := MaxXYZComponent(N);
  61. end;
  62. procedure ECResetColliders(var MovePack: TECMovePack);
  63. begin
  64. SetLength(MovePack.TriMeshes,0);
  65. SetLength(MovePack.Freeforms,0);
  66. SetLength(MovePack.Colliders,0);
  67. end;
  68. procedure ECAddFreeForm(var MovePack: TECMovePack; FreeForm: TgxBaseSceneObject;
  69. Solid: Boolean; ObjectID: Integer);
  70. var
  71. i, count : Integer;
  72. Pos: TVector4f;
  73. Master: TgxBaseSceneObject;
  74. d1,d2: Single;
  75. begin
  76. Master := FreeForm;
  77. if Master is TgxFreeFormProxy then
  78. Master := TgxFreeFormProxy(Master).MasterObject;
  79. if Master is TgxMultiProxy then
  80. if TgxMultiProxy(Master).MasterObjects.Count > 0 then
  81. Master := TgxMultiProxy(Master).MasterObjects[0].MasterObject;
  82. Assert((Master is TgxFreeForm), 'Object must be freeform, freeformproxy or freeformbased Multiproxy.');
  83. Assert(Assigned(TgxFreeForm(Master).Octree), 'Octree must have been prepared and setup before use.');
  84. SetVector(Pos, FreeForm.AbsoluteToLocal(MovePack.Position));
  85. //Is in boundingsphere?
  86. d1 := VectorDistance2(MovePack.Position,AffineVectorMake(FreeForm.AbsolutePosition));
  87. d2 := sqr(MovePack.CollisionRange + Freeform.BoundingSphereRadius);
  88. if d1 > d2 then exit;
  89. count := Length(MovePack.Freeforms);
  90. with TgxFreeForm(Master).Octree do
  91. begin
  92. WalkSphereToLeaf(RootNode, Pos, MovePack.CollisionRange);
  93. if not Assigned(resultarray) then exit;
  94. //Copy the result array
  95. SetLength(MovePack.Freeforms,count+1);
  96. SetLength(MovePack.Freeforms[count].OctreeNodes, Length(resultarray));
  97. for i := 0 to High(resultarray) do
  98. MovePack.Freeforms[count].OctreeNodes[i] := resultarray[i];
  99. //Reference to this octree
  100. MovePack.Freeforms[count].triangleFiler := @triangleFiler;
  101. MovePack.Freeforms[count].ObjectInfo.AbsoluteMatrix := Freeform.AbsoluteMatrix;
  102. MovePack.Freeforms[count].ObjectInfo.Solid := Solid;
  103. MovePack.Freeforms[count].ObjectInfo.ObjectID := ObjectID;
  104. MovePack.Freeforms[count].InvertedNormals := TgxFreeForm(Master).NormalsOrientation = mnoInvert;
  105. end;
  106. end;
  107. procedure ECAddBox(var MovePack: TECMovePack;
  108. BoxObj: TgxBaseSceneObject; BoxSize: TAffineVector;
  109. Solid: Boolean; ObjectID: Integer);
  110. var t,count,i : Integer;
  111. p1, p2, p3: TAffineVector;
  112. BoxRadius,d1,d2: Single;
  113. begin
  114. BoxRadius := MaxXYZComponent(BoxSize)*MaxXYZComponent(BoxObj.Scale.AsAffineVector);
  115. d1 := VectorDistance2(MovePack.Position,AffineVectorMake(BoxObj.AbsolutePosition));
  116. d2 := sqr(MovePack.CollisionRange + BoxRadius);
  117. if d1 > d2 then exit;
  118. //Add the box to the triangle list
  119. t := Length(MovePack.TriMeshes);
  120. SetLength(MovePack.TriMeshes,t+1);
  121. ScaleVector(BoxSize,0.5);
  122. count := 0;
  123. i := 0;
  124. while i < 36 do
  125. begin
  126. count := count + 1;
  127. SetLength(MovePack.TriMeshes[t].Triangles,count);
  128. with MovePack.TriMeshes[t] do
  129. begin
  130. p1 := DCEBox[i]; ScaleVector(p1,BoxSize); p1 := BoxObj.LocalToAbsolute(p1);
  131. p2 := DCEBox[i+1]; ScaleVector(p2,BoxSize); p2 := BoxObj.LocalToAbsolute(p2);
  132. p3 := DCEBox[i+2]; ScaleVector(p3,BoxSize); p3 := BoxObj.LocalToAbsolute(p3);
  133. i := i + 3;
  134. SetVector(Triangles[count-1].p1, p1);
  135. SetVector(Triangles[count-1].p2, p2);
  136. SetVector(Triangles[count-1].p3, p3);
  137. ObjectInfo.Solid := Solid;
  138. ObjectInfo.ObjectID := ObjectID;
  139. end;
  140. end;
  141. end;
  142. procedure ECAddTerrain(var MovePack: TECMovePack;
  143. TerrainRenderer: TgxTerrainRenderer; Resolution: Single;
  144. Solid: Boolean; ObjectID: Integer);
  145. function intvec(x,z: Single): TAffineVector;
  146. begin
  147. result.X := x + MovePack.Position.X;
  148. result.Y := 0 + MovePack.Position.Y;
  149. result.Z := z + MovePack.Position.Z;
  150. end;
  151. function locabs(x,y,z: Single): TAffineVector;
  152. begin
  153. //result := TerrainRenderer.LocalToAbsolute(AffineVectorMake(x,y,z));
  154. //result := AffineVectorMake(x,y,z);
  155. result.X := x + MovePack.Position.X;
  156. result.Y := y + TerrainRenderer.AbsolutePosition.Y;
  157. result.Z := z + MovePack.Position.Z;
  158. end;
  159. var count,t : Integer;
  160. x,y,z: Single;
  161. begin
  162. //Add the terrain to the list
  163. count := Length(MovePack.TriMeshes);
  164. SetLength(MovePack.TriMeshes,count+1);
  165. with MovePack.TriMeshes[count] do
  166. begin
  167. ObjectInfo.Solid := Solid;
  168. ObjectInfo.ObjectID := ObjectID;
  169. t := 0;
  170. x := - MovePack.CollisionRange;
  171. while x < MovePack.CollisionRange do
  172. begin
  173. z := - MovePack.CollisionRange;
  174. while z < MovePack.CollisionRange do
  175. begin
  176. //Add 2 triangles
  177. t := t + 2;
  178. SetLength(Triangles, t);
  179. //Tri 1
  180. y := TerrainRenderer.InterpolatedHeight(intvec(x,z));
  181. Triangles[t-2].p1 := locabs(x,y,z);
  182. y := TerrainRenderer.InterpolatedHeight(intvec(x,z+Resolution));
  183. Triangles[t-2].p2 := locabs(x,y,z+Resolution);
  184. y := TerrainRenderer.InterpolatedHeight(intvec(x+Resolution,z));
  185. Triangles[t-2].p3 := locabs(x+Resolution,y,z);
  186. //Tri 2
  187. y := TerrainRenderer.InterpolatedHeight(intvec(x+Resolution,z+Resolution));
  188. Triangles[t-1].p1 := locabs(x+Resolution,y,z+Resolution);
  189. y := TerrainRenderer.InterpolatedHeight(intvec(x+Resolution,z));
  190. Triangles[t-1].p2 := locabs(x+Resolution,y,z);
  191. y := TerrainRenderer.InterpolatedHeight(intvec(x,z+Resolution));
  192. Triangles[t-1].p3 := locabs(x,y,z+Resolution);
  193. z := z + Resolution;
  194. end;
  195. x := x + Resolution;
  196. end;
  197. end;
  198. end;
  199. procedure ECAddEllipsoid(var MovePack: TECMovePack; ePos, eRadius: TAffineVector;
  200. Solid: Boolean; ObjectID: Integer);
  201. var count : Integer;
  202. d1, d2, r: single;
  203. begin
  204. r := MaxXYZComponent(eRadius);
  205. d1 := VectorDistance2(MovePack.Position,ePos);
  206. d2 := sqr(MovePack.CollisionRange + r);
  207. if d1 > d2 then exit;
  208. //Add possible collider
  209. count := Length(MovePack.Colliders);
  210. SetLength(MovePack.Colliders,count+1);
  211. with MovePack.Colliders[count] do
  212. begin
  213. Position := ePos;
  214. Radius := eRadius;
  215. ObjectInfo.Solid := Solid;
  216. ObjectInfo.ObjectID := ObjectID;
  217. end;
  218. end;
  219. // ---------------------------------------------------------------------------
  220. end.