GXS.ExplosionFx.pas 8.8 KB

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