GLS.ExplosionFx.pas 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. //
  2. // The graphics engine GLXEngine. The unit of GLScene for Delphi
  3. //
  4. unit GLS.ExplosionFx;
  5. (*
  6. Description: this effect explodes a mesh object into triangles
  7. that fly over. You can define a default direction, in wich case
  8. the pieces of the mesh will follow that direction, only rotating,
  9. or if you define a null vector as the direction, a vector will be
  10. calculated for each triangle, based on the normal vector of that
  11. triangle, with a little random addition so things look better.
  12. Pretty neat :)
  13. Note: the owner of this behaviour should be any class that derives
  14. from TGLBaseMesh class or any other class derived from TGLBaseMesh.
  15. Also, the structure of the mesh is lost after the caching of information,
  16. so if you'll need the mesh after exploding it, you'll have to save the
  17. MeshObjects property of the mesh, OR load it again.
  18. *)
  19. interface
  20. {$I Stage.Defines.inc}
  21. uses
  22. Winapi.OpenGL,
  23. Stage.OpenGLTokens,
  24. Stage.VectorGeometry,
  25. Stage.VectorTypes,
  26. GLS.Scene,
  27. GLS.VectorFileObjects,
  28. GLS.VectorLists,
  29. GLS.XCollection,
  30. GLS.Coordinates,
  31. GLS.RenderContextInfo,
  32. GLS.Context,
  33. GLS.State;
  34. type
  35. TGLBExplosionFX = class(TGLObjectPreEffect)
  36. private
  37. FTriList: TGLAffineVectorList;
  38. FRotList: TGLAffineVectorList;
  39. FDirList: TGLAffineVectorList;
  40. FPosList: TGLAffineVectorList;
  41. FEnabled: boolean;
  42. FFaceCount: integer;
  43. FSpeed: single;
  44. FDirection: TGLCoordinates;
  45. FMaxSteps: integer;
  46. FStep: integer;
  47. procedure SetTriList(Value: TGLAffineVectorList);
  48. procedure SetRotList(Value: TGLAffineVectorList);
  49. procedure SetDirList(Value: TGLAffineVectorList);
  50. procedure SetPosList(Value: TGLAffineVectorList);
  51. procedure SetDirection(value: TGLCoordinates);
  52. procedure SetEnabled(value: boolean);
  53. protected
  54. property TriList: TGLAffineVectorList read FTriList write SetTriList;
  55. property RotList: TGLAffineVectorList read FRotList write SetRotList;
  56. property DirList: TGLAffineVectorList read FDirList write SetDirList;
  57. property PosList: TGLAffineVectorList read FPosList write SetPosList;
  58. property FaceCount: integer read FFAceCount write FFaceCount;
  59. procedure CacheInfo;
  60. public
  61. property Enabled: boolean read FEnabled write SetEnabled;
  62. property Step: integer read FStep;
  63. constructor Create(aOwner : TXCollection); override;
  64. destructor Destroy; override;
  65. procedure Render(var rci : TGLRenderContextInfo); override;
  66. (* Resets the behaviour, so the information can be re-cached and
  67. the mesh can be exploded again *)
  68. procedure Reset;
  69. class function FriendlyName : String; override;
  70. class function FriendlyDescription : String; override;
  71. published
  72. property MaxSteps: integer read FMaxSteps write FMaxSteps;
  73. property Speed: single read FSpeed write FSpeed;
  74. property Direction: TGLCoordinates read FDirection write SetDirection;
  75. end;
  76. //-------------------------------------------------------------------------
  77. implementation
  78. //-------------------------------------------------------------------------
  79. //----------------------------------
  80. // TGLBExplosionFx
  81. //----------------------------------
  82. constructor TGLBExplosionFx.Create(aOwner: TXCollection);
  83. begin
  84. inherited Create(AOwner);
  85. FTriList := TGLAffineVectorList.Create;
  86. FRotList := TGLAffineVectorList.Create;
  87. FDirList := TGLAffineVectorList.Create;
  88. FPosList := TGLAffineVectorList.Create;
  89. FDirection := TGLCoordinates.CreateInitialized(Self, NullHmgVector, csPoint);
  90. end;
  91. destructor TGLBExplosionFX.Destroy;
  92. begin
  93. FEnabled := False;
  94. FTriList.Free;
  95. FRotList.Free;
  96. FDirList.Free;
  97. FPosList.Free;
  98. FDirection.Free;
  99. inherited Destroy;
  100. end;
  101. class function TGLBExplosionFX.FriendlyName: string;
  102. begin
  103. Result := 'ExplosionFx';
  104. end;
  105. class function TGLBExplosionFX.FriendlyDescription: string;
  106. begin
  107. Result := 'Explosion FX';
  108. end;
  109. procedure TGLBExplosionFx.SetTriList(Value: TGLAffineVectorList);
  110. begin
  111. FTriList.Assign(Value);
  112. end;
  113. procedure TGLBExplosionFx.SetRotList(Value: TGLAffineVectorList);
  114. begin
  115. FRotList.Assign(Value);
  116. end;
  117. procedure TGLBExplosionFx.SetDirList(Value: TGLAffineVectorList);
  118. begin
  119. FDirList.Assign(Value);
  120. end;
  121. procedure TGLBExplosionFx.SetPosList(Value: TGLAffineVectorList);
  122. begin
  123. FPosList.Assign(Value);
  124. end;
  125. procedure TGLBExplosionFx.SetDirection(Value: TGLCoordinates);
  126. begin
  127. Value.Normalize;
  128. FDirection.Assign(Value);
  129. end;
  130. procedure TGLBExplosionFx.SetEnabled(Value: boolean);
  131. begin
  132. FEnabled := Value;
  133. end;
  134. procedure TGLBExplosionFx.Reset;
  135. begin
  136. FEnabled := False;
  137. FStep := 0;
  138. FTriList.Clear;
  139. FRotList.Clear;
  140. FDirList.Clear;
  141. FPosList.Clear;
  142. FFaceCount := 0;
  143. end;
  144. procedure TGLBExplosionFx.CacheInfo;
  145. var
  146. Face: integer;
  147. p1, p2, p3, v1, v2, posi: TAffineVector;
  148. Normal: TGLVector;
  149. begin
  150. // make sure we can explode this object
  151. if not OwnerBaseSceneObject.InheritsFrom(TGLBaseMesh) then begin
  152. FEnabled := False;
  153. Exit;
  154. end;
  155. FTriList.Free;
  156. // get all the triangles of all the meshObjects
  157. FTriList := TGLBaseMesh(OwnerBaseSceneObject).MeshObjects.ExtractTriangles;
  158. FaceCount := FTriList.Count div 3;
  159. // set initial direction, rotation and position
  160. for Face := 0 to Facecount - 1 do begin
  161. // get the vertices of the triangle
  162. SetVector(p1, FTriList.Items[Face * 3]);
  163. SetVector(p2, FTriList.Items[Face * 3 + 1]);
  164. SetVector(p3, FTriList.Items[Face * 3 + 2]);
  165. // if the direction property is a null vector, than the direction is
  166. // given by the normal of the face
  167. if VectorEquals(FDirection.AsVector, NullHmgVector) then begin
  168. v1 := VectorSubtract(p2, p1);
  169. v2 := VectorSubtract(p2, p3);
  170. NormalizeVector(v1); // use of procedure is faster: PhP
  171. NormalizeVector(v2); // use of procedure is faster: PhP
  172. SetVector(Normal, VectorCrossProduct(v1, v2)); // use of procedure is faster: PhP
  173. // randomly rotate the normal vector so the faces are somewhat scattered
  174. case Random(3) of
  175. 0: RotateVector(Normal, XVector, DegToRadian(45.0*Random));
  176. 1: RotateVector(Normal, YVector, DegToRadian(45.0*Random));
  177. 2: RotateVector(Normal, ZVector, DegToRadian(45.0*Random));
  178. end;
  179. NormalizeVector(Normal);
  180. FDirList.Add(Normal);
  181. end
  182. else
  183. FDirList.Add(FDirection.AsVector);
  184. // calculate the center (position) of the triangle so it rotates around its center
  185. posi.X := (p1.X + p2.X + p3.X) / 3;
  186. posi.Y := (p1.Y + p2.Y + p3.Y) / 3;
  187. posi.Z := (p1.Z + p2.Z + p3.Z) / 3;
  188. FPosList.add(posi);
  189. // random rotation (in degrees)
  190. FRotList.Add(DegToRadian(3.0*Random), DegToRadian(3.0*Random), DegToRadian(3.0*Random));
  191. end;
  192. // Dispose the struture of the mesh
  193. TGLBaseMesh(OwnerBaseSceneObject).MeshObjects.Clear;
  194. TGLBaseMesh(OwnerBaseSceneObject).StructureChanged;
  195. end;
  196. procedure TGLBExplosionFX.Render(var rci : TGLRenderContextInfo);
  197. var
  198. Face: integer;
  199. dir, p1, p2, p3: TAffineVector;
  200. mat: TGLMatrix;
  201. begin
  202. if not FEnabled then
  203. Exit;
  204. // cache de list of vertices
  205. if FTriList.Count <= 0 then begin
  206. CacheInfo;
  207. if not FEnabled then
  208. Exit;
  209. end;
  210. // render explosion
  211. rci.GLStates.Disable(stCullFace);
  212. gl.Begin_(GL_TRIANGLES);
  213. for Face := 0 to FaceCount - 1 do begin
  214. SetVector(p1, FTriList.Items[Face * 3]);
  215. SetVector(p2, FTriList.Items[Face * 3 + 1]);
  216. SetVector(p3, FTriList.Items[Face * 3 + 2]);
  217. // rotate the face
  218. mat := IdentityHmgMatrix;
  219. mat := MatrixMultiply(mat, CreateRotationMatrixX(FRotList.Items[face].X));
  220. mat := MatrixMultiply(mat, CreateRotationMatrixY(FRotList.Items[face].Y));
  221. mat := MatrixMultiply(mat, CreateRotationMatrixZ(FRotList.Items[face].Z));
  222. SubtractVector(p1, FPosList.Items[Face]); // use of procedure is faster: PhP
  223. SubtractVector(p2, FPosList.Items[Face]); // -''-
  224. SubtractVector(p3, FPosList.Items[Face]); // -''-
  225. p1 := VectorTransform(p1, mat);
  226. p2 := VectorTransform(p2, mat);
  227. p3 := VectorTransform(p3, mat);
  228. AddVector(p1, FPosList.Items[Face]); // use of procedure is faster: PhP
  229. AddVector(p2, FPosList.Items[Face]); // -''-
  230. AddVector(p3, FPosList.Items[Face]); // -''-
  231. // move the face in the direction it is heading
  232. SetVector(dir, FDirList.Items[Face]);
  233. gl.Normal3f(dir.X, dir.Y, dir.Z);
  234. ScaleVector(dir, Speed);
  235. AddVector(p1, dir);
  236. AddVector(p2, dir);
  237. AddVector(p3, dir);
  238. // also, move the center of the face
  239. FPosList.Items[Face] := VectorAdd(FPosList.Items[Face], dir);
  240. // save the changes
  241. FTrilist.Items[face * 3] := p1;
  242. FTrilist.Items[face * 3 +1] := p2;
  243. FTrilist.Items[face * 3 +2] := p3;
  244. gl.Vertex3f(p1.X, p1.Y, p1.Z);
  245. gl.Vertex3f(p2.X, p2.Y, p2.Z);
  246. gl.Vertex3f(p3.X, p3.Y, p3.Z);
  247. end;
  248. gl.End_;
  249. rci.GLStates.Enable(stCullFace);
  250. if FMaxSteps <> 0 then begin
  251. Inc(FStep);
  252. if FStep = FMaxSteps then
  253. FEnabled := False;
  254. end;
  255. end;
  256. //-------------------------------
  257. initialization
  258. //-------------------------------
  259. RegisterXCollectionItemClass(TGLBExplosionFX);
  260. finalization
  261. UnregisterXCollectionItemClass(TGLBExplosionFX);
  262. end.