GXS.ThorFX.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.ThorFX;
  5. (* ThorFX for Scene *)
  6. interface
  7. {$I Stage.Defines.inc}
  8. uses
  9. Winapi.OpenGL,
  10. System.Classes,
  11. System.SysUtils,
  12. System.Math,
  13. GXS.XCollection,
  14. GXS.Scene,
  15. Stage.PipelineTransform,
  16. Stage.VectorGeometry,
  17. GXS.Context,
  18. GXS.VectorLists,
  19. Stage.VectorTypes,
  20. GXS.Cadencer,
  21. GXS.Color,
  22. GXS.BaseClasses,
  23. GXS.Coordinates,
  24. GXS.RenderContextInfo,
  25. Stage.Manager,
  26. GXS.State,
  27. Stage.TextureFormat;
  28. type
  29. PThorpoint = ^TThorpoint;
  30. TThorpoint = record
  31. Position: TVector4f; // Position
  32. Size: single; // particle size
  33. end;
  34. PThorpointArray = ^TThorpointArray;
  35. TThorpointArray = array [0 .. MAXINT shr 6] of TThorpoint;
  36. TgxBThorFX = class;
  37. TCalcPointEvent = procedure(Sender: TObject; PointNo: integer; var x: single;
  38. var y: single; var z: single) of object;
  39. // Thor special effect manager.
  40. TgxThorFXManager = class(TgxCadenceAbleComponent)
  41. private
  42. FClients: TList;
  43. FThorpoints: PThorpointArray;
  44. FTarget: TgxCoordinates;
  45. FCadencer: TgxCadencer;
  46. FMaxpoints: integer;
  47. FGlowSize: single;
  48. FVibrate: single;
  49. FWildness: single;
  50. NP: integer;
  51. FInnerColor, FOuterColor, FCoreColor: TgxColor;
  52. FDisabled, FCore, FGlow: boolean;
  53. FOnCalcPoint: TCalcPointEvent;
  54. protected
  55. procedure RegisterClient(aClient: TgxBThorFX);
  56. procedure DeRegisterClient(aClient: TgxBThorFX);
  57. procedure DeRegisterAllClients;
  58. procedure SetTarget(const val: TgxCoordinates);
  59. procedure SetCadencer(const val: TgxCadencer);
  60. procedure SetMaxpoints(const val: integer);
  61. function StoreGlowSize: boolean;
  62. function StoreVibrate: boolean;
  63. procedure SetInnerColor(const val: TgxColor);
  64. procedure SetOuterColor(const val: TgxColor);
  65. procedure SetCoreColor(const val: TgxColor);
  66. procedure Notification(AComponent: TComponent;
  67. Operation: TOperation); override;
  68. procedure ThorInit;
  69. procedure CalcThor;
  70. procedure CalcFrac(left, right: integer; lh, rh: single; xyz: integer);
  71. public
  72. constructor Create(AOwner: TComponent); override;
  73. destructor Destroy; override;
  74. procedure DoProgress(const progressTime: TgxProgressTimes); override;
  75. published
  76. property Target: TgxCoordinates read FTarget write SetTarget;
  77. property Cadencer: TgxCadencer read FCadencer write SetCadencer;
  78. property Maxpoints: integer read FMaxpoints write SetMaxpoints default 256;
  79. property GlowSize: single read FGlowSize write FGlowSize
  80. stored StoreGlowSize;
  81. property Vibrate: single read FVibrate write FVibrate stored StoreVibrate;
  82. property InnerColor: TgxColor read FInnerColor write SetInnerColor;
  83. property OuterColor: TgxColor read FOuterColor write SetOuterColor;
  84. // default clrWhite;
  85. property CoreColor: TgxColor read FCoreColor write SetCoreColor;
  86. // default clrWhite;
  87. property Disabled: boolean read FDisabled write FDisabled;
  88. property Core: boolean read FCore write FCore;
  89. property Glow: boolean read FGlow write FGlow;
  90. property Wildness: single read FWildness write FWildness;
  91. property OnCalcPoint: TCalcPointEvent read FOnCalcPoint write FOnCalcPoint;
  92. end;
  93. // Thor special effect
  94. TgxBThorFX = class(TgxObjectPostEffect)
  95. private
  96. FManager: TgxThorFXManager;
  97. FManagerName: String; // NOT persistent, temporarily used for persistence
  98. FTarget: TgxCoordinates;
  99. protected
  100. procedure SetManager(const val: TgxThorFXManager);
  101. procedure WriteToFiler(writer: TWriter); override;
  102. procedure ReadFromFiler(reader: TReader); override;
  103. procedure Loaded; override;
  104. procedure SetTarget(const val: TgxCoordinates);
  105. public
  106. constructor Create(AOwner: TXCollection); override;
  107. destructor Destroy; override;
  108. procedure Assign(Source: TPersistent); override;
  109. class function FriendlyName: String; override;
  110. class function FriendlyDescription: String; override;
  111. procedure Render(var rci: TgxRenderContextInfo); override;
  112. published
  113. { Refers the collision manager. }
  114. property Manager: TgxThorFXManager read FManager write SetManager;
  115. end;
  116. { Returns or creates the TgxBThorFX within the given object's effects. }
  117. function GetOrCreateThorFX(obj: TgxBaseSceneObject; const name: String = '')
  118. : TgxBThorFX;
  119. // ------------------------------------------------------------------
  120. implementation
  121. // ------------------------------------------------------------------
  122. // ------------------
  123. // ------------------ TgxThorFXManager ------------------
  124. // ------------------
  125. constructor TgxThorFXManager.Create(AOwner: TComponent);
  126. begin
  127. inherited Create(AOwner);
  128. FClients := TList.Create;
  129. RegisterManager(Self);
  130. FTarget := TgxCoordinates.CreateInitialized(Self, VectorMake(0, 1, 0));
  131. FTarget.Style := csPoint;
  132. FMaxpoints := 64;
  133. FGlowSize := 0.2;
  134. FVibrate := 0;
  135. FWildness := 1;
  136. FInnerColor := TgxColor.Create(Self);
  137. FInnerColor.Initialize(clrWhite);
  138. FOuterColor := TgxColor.Create(Self);
  139. FOuterColor.Initialize(clrBlue);
  140. FOuterColor.Alpha := 0;
  141. FCoreColor := TgxColor.Create(Self);
  142. FCoreColor.Initialize(clrWhite);
  143. FCore := True;
  144. FGlow := True;
  145. ThorInit;
  146. end;
  147. destructor TgxThorFXManager.Destroy;
  148. begin
  149. DeRegisterAllClients;
  150. DeRegisterManager(Self);
  151. FreeMem(FThorpoints);
  152. FreeAndNil(FClients);
  153. FreeAndNil(FInnerColor);
  154. FreeAndNil(FOuterColor);
  155. FreeAndNil(FCoreColor);
  156. FreeAndNil(FTarget);
  157. inherited Destroy;
  158. end;
  159. procedure TgxThorFXManager.RegisterClient(aClient: TgxBThorFX);
  160. begin
  161. if Assigned(aClient) then
  162. if FClients.IndexOf(aClient) < 0 then
  163. begin
  164. FClients.Add(aClient);
  165. aClient.FManager := Self;
  166. end;
  167. end;
  168. procedure TgxThorFXManager.DeRegisterClient(aClient: TgxBThorFX);
  169. begin
  170. if Assigned(aClient) then
  171. begin
  172. aClient.FManager := nil;
  173. FClients.Remove(aClient);
  174. end;
  175. end;
  176. procedure TgxThorFXManager.DeRegisterAllClients;
  177. var
  178. i: integer;
  179. begin
  180. // Fast deregistration
  181. for i := 0 to FClients.Count - 1 do
  182. TgxBThorFX(FClients[i]).FManager := nil;
  183. FClients.Clear;
  184. end;
  185. procedure TgxThorFXManager.SetTarget(const val: TgxCoordinates);
  186. begin
  187. FTarget.Assign(val);
  188. ThorInit;
  189. end;
  190. procedure TgxThorFXManager.SetCadencer(const val: TgxCadencer);
  191. begin
  192. if FCadencer <> val then
  193. begin
  194. if Assigned(FCadencer) then
  195. FCadencer.UnSubscribe(Self);
  196. FCadencer := val;
  197. if Assigned(FCadencer) then
  198. FCadencer.Subscribe(Self);
  199. end;
  200. end;
  201. procedure TgxThorFXManager.SetMaxpoints(const val: integer);
  202. begin
  203. if FMaxpoints <> val then
  204. begin
  205. FMaxpoints := val;
  206. ThorInit;
  207. end;
  208. end;
  209. function TgxThorFXManager.StoreGlowSize: boolean;
  210. begin
  211. Result := (FGlowSize <> 1);
  212. end;
  213. function TgxThorFXManager.StoreVibrate: boolean;
  214. begin
  215. Result := (FVibrate <> 1);
  216. end;
  217. procedure TgxThorFXManager.SetInnerColor(const val: TgxColor);
  218. begin
  219. if FInnerColor <> val then
  220. begin
  221. FInnerColor.color := val.color;
  222. ThorInit;
  223. end;
  224. end;
  225. procedure TgxThorFXManager.SetOuterColor(const val: TgxColor);
  226. begin
  227. if FOuterColor <> val then
  228. begin
  229. FOuterColor.color := val.color;
  230. ThorInit;
  231. end;
  232. end;
  233. procedure TgxThorFXManager.SetCoreColor(const val: TgxColor);
  234. begin
  235. if FCoreColor <> val then
  236. begin
  237. FCoreColor.color := val.color;
  238. ThorInit;
  239. end;
  240. end;
  241. procedure TgxThorFXManager.Notification(AComponent: TComponent;
  242. Operation: TOperation);
  243. begin
  244. if (Operation = opRemove) and (AComponent = FCadencer) then
  245. Cadencer := nil;
  246. inherited;
  247. end;
  248. procedure TgxThorFXManager.DoProgress(const progressTime: TgxProgressTimes);
  249. var
  250. i: integer;
  251. begin
  252. if not FDisabled then
  253. CalcThor;
  254. // Invalidate all clients
  255. for i := 0 to FClients.Count - 1 do
  256. TgxBThorFX(FClients[i]).OwnerBaseSceneObject.NotifyChange
  257. (TgxBThorFX(FClients[i]));
  258. end;
  259. procedure TgxThorFXManager.ThorInit;
  260. begin
  261. ReallocMem(FThorpoints, FMaxpoints * Sizeof(TThorpoint));
  262. end;
  263. procedure TgxThorFXManager.CalcThor;
  264. var
  265. N: integer;
  266. vec, axs, nvec: TVector4f;
  267. dist: single;
  268. a, b: single;
  269. len: single;
  270. begin
  271. // initialise all points with valid data
  272. for N := 0 to Maxpoints - 1 do
  273. SetVector(FThorpoints^[N].Position, 0, 0, 0);
  274. // ------------------Calculate fractal (wildness)---------------
  275. // SetVector(FThorpoints[0].Position,0,0,0);
  276. SetVector(FThorpoints^[Maxpoints - 1].Position, 0, 0, 0);
  277. CalcFrac(0, Maxpoints - 1, 0, 0, 0);
  278. CalcFrac(0, Maxpoints - 1, 0, 0, 1);
  279. // CalcFrac(0,maxpoints-1,0,FTarget.z,2);
  280. // ---------------Rotate Vector to target-------------
  281. SetVector(nvec, FTarget.x, FTarget.y, FTarget.z);
  282. len := VectorLength(nvec);
  283. NormalizeVector(nvec);
  284. a := ArcCos(nvec.Z);
  285. b := ArcTan2(nvec.X, nvec.Y);
  286. N := 0;
  287. While (N < Maxpoints) do
  288. begin
  289. dist := N / Maxpoints * len;
  290. vec := FThorpoints^[N].Position;
  291. vec.Z := dist;
  292. if Assigned(OnCalcPoint) then
  293. OnCalcPoint(Self, N, vec.X, vec.Y, vec.Z);
  294. // Let user mess around with point position
  295. SetVector(axs, 1, 0, 0); // Rotate up
  296. RotateVector(vec, axs, a);
  297. SetVector(axs, 0, 0, 1); // Rotate to the sides
  298. RotateVector(vec, axs, b);
  299. FThorpoints^[N].Position := vec;
  300. inc(N);
  301. end;
  302. // ----------------------------------------------------
  303. NP := Maxpoints;
  304. end;
  305. procedure TgxThorFXManager.CalcFrac(left, right: integer; lh, rh: single;
  306. xyz: integer);
  307. var
  308. midh: single;
  309. mid: integer;
  310. res: integer;
  311. fracScale: single;
  312. begin
  313. mid := (left + right) div 2;
  314. res := (left + right) mod 2;
  315. fracScale := (right - left) / Maxpoints;
  316. midh := (lh + rh) / 2 + (fracScale * FWildness * random) -
  317. (fracScale * FWildness) / 2;
  318. FThorpoints^[mid].Position.V[xyz] := midh +
  319. (FVibrate * random - (FVibrate / 2));
  320. // if res=1 then FThorpoints[right-1].Position[xyz]:=
  321. // (FThorpoints[right].Position[xyz]+midh)/(right-mid)*(right-mid-1);
  322. if res = 1 then
  323. FThorpoints^[right - 1].Position.V[xyz] := FThorpoints^[right].Position.V[xyz];
  324. if (mid - left) > 1 then
  325. CalcFrac(left, mid, lh, midh, xyz);
  326. if (right - mid) > 1 then
  327. CalcFrac(mid, right, midh, rh, xyz);
  328. end;
  329. // ------------------
  330. // ------------------ TgxBThorFX ------------------
  331. // ------------------
  332. constructor TgxBThorFX.Create(AOwner: TXCollection);
  333. begin
  334. inherited Create(AOwner);
  335. FTarget := TgxCoordinates.CreateInitialized(Self, VectorMake(0, 1, 0));
  336. FTarget.Style := csPoint;
  337. end;
  338. destructor TgxBThorFX.Destroy;
  339. begin
  340. Manager := nil;
  341. FreeAndNil(FTarget);
  342. inherited Destroy;
  343. end;
  344. class function TgxBThorFX.FriendlyName: String;
  345. begin
  346. Result := 'ThorFX';
  347. end;
  348. class function TgxBThorFX.FriendlyDescription: String;
  349. begin
  350. Result := 'Thor FX';
  351. end;
  352. procedure TgxBThorFX.WriteToFiler(writer: TWriter);
  353. begin
  354. with writer do
  355. begin
  356. // ArchiveVersion 1, added inherited call
  357. WriteInteger(1);
  358. inherited;
  359. if Assigned(FManager) then
  360. WriteString(FManager.GetNamePath)
  361. else
  362. WriteString('');
  363. end;
  364. end;
  365. procedure TgxBThorFX.ReadFromFiler(reader: TReader);
  366. var
  367. archiveVersion: integer;
  368. begin
  369. with reader do
  370. begin
  371. archiveVersion := ReadInteger;
  372. Assert(archiveVersion in [0 .. 1]);
  373. if archiveVersion >= 1 then
  374. inherited;
  375. FManagerName := ReadString;
  376. Manager := nil;
  377. end;
  378. end;
  379. // Loaded
  380. //
  381. procedure TgxBThorFX.Loaded;
  382. var
  383. mng: TComponent;
  384. begin
  385. inherited;
  386. if FManagerName <> '' then
  387. begin
  388. mng := FindManager(TgxThorFXManager, FManagerName);
  389. if Assigned(mng) then
  390. Manager := TgxThorFXManager(mng);
  391. FManagerName := '';
  392. end;
  393. end;
  394. procedure TgxBThorFX.Assign(Source: TPersistent);
  395. begin
  396. if Source is TgxBThorFX then
  397. begin
  398. Manager := TgxBThorFX(Source).Manager;
  399. end;
  400. inherited Assign(Source);
  401. end;
  402. procedure TgxBThorFX.SetTarget(const val: TgxCoordinates);
  403. begin
  404. FTarget.Assign(val);
  405. end;
  406. procedure TgxBThorFX.SetManager(const val: TgxThorFXManager);
  407. begin
  408. if val <> FManager then
  409. begin
  410. if Assigned(FManager) then
  411. FManager.DeRegisterClient(Self);
  412. if Assigned(val) then
  413. val.RegisterClient(Self);
  414. end;
  415. end;
  416. procedure TgxBThorFX.Render(var rci: TgxRenderContextInfo);
  417. var
  418. N: integer;
  419. i: integer;
  420. // absPos :TVector4f;
  421. InnerColor: TVector4f;
  422. distList: TgxSingleList;
  423. objList: TList;
  424. fp: PThorpoint;
  425. mat: TMatrix4f;
  426. vx, vy: TVector4f;
  427. m: integer;
  428. Icol, Ocol, Ccol: TgxColorVector;
  429. Ppos, Ppos2: TAffineVector;
  430. begin
  431. if Manager = nil then
  432. Exit;
  433. rci.PipelineTransformation.Push;
  434. // we get the object position and apply translation...
  435. // absPos:=OwnerBaseSceneObject.AbsolutePosition;
  436. // ...should be removed when absolute coords will be handled directly
  437. // in the point system (and will also make a better flame effect)
  438. rci.gxStates.Disable(stCullFace);
  439. rci.gxStates.ActiveTextureEnabled[ttTexture2D] := False;
  440. rci.gxStates.Disable(stLighting);
  441. rci.gxStates.SetBlendFunc(bfSrcAlpha, bfOne);
  442. rci.gxStates.Enable(stBlend);
  443. N := Manager.NP;
  444. if N > 1 then
  445. begin
  446. distList := TgxSingleList.Create;
  447. objList := TList.Create;
  448. for i := 0 to N - 1 do
  449. begin
  450. fp := @(Manager.FThorpoints[i]);
  451. distList.Add(VectorDotProduct(rci.cameraDirection, fp^.Position));
  452. objList.Add(fp);
  453. end;
  454. QuickSortLists(0, N - 1, distList, objList);
  455. mat := rci.PipelineTransformation.ModelViewMatrix^;
  456. for m := 0 to 2 do
  457. begin
  458. vx.V[m] := mat.V[m].X * Manager.GlowSize;
  459. vy.V[m] := mat.V[m].Y * Manager.GlowSize;
  460. end;
  461. SetVector(InnerColor, Manager.FInnerColor.color);
  462. // ---------------
  463. rci.gxStates.SetBlendFunc(bfSrcAlpha, bfOne);
  464. rci.gxStates.Enable(stBlend);
  465. rci.gxStates.Enable(stLineSmooth);
  466. rci.gxStates.Disable(stLighting);
  467. // Stops particles at same distanceform overwriting each-other
  468. rci.gxStates.DepthFunc := cfLEqual;
  469. rci.gxStates.LineWidth := 3;
  470. Icol := Manager.FInnerColor.color;
  471. Ocol := Manager.FOuterColor.color;
  472. Ccol := Manager.FCoreColor.color;
  473. // ---Core Line---
  474. if Manager.FCore then
  475. begin
  476. rci.gxStates.Disable(stBlend);
  477. glColor4fv(@Ccol);
  478. glBegin(GL_LINE_STRIP);
  479. for i := 0 to N - 1 do
  480. begin
  481. fp := @(Manager.FThorpoints[i]);
  482. SetVector(Ppos, fp^.Position);
  483. glVertex3f(Ppos.X, Ppos.Y, Ppos.Z);
  484. end;
  485. glEnd;
  486. end; // Core;
  487. // ---Point Glow---
  488. if Manager.FGlow then
  489. begin
  490. rci.gxStates.Enable(stBlend);
  491. for i := N - 1 downto 0 do
  492. begin
  493. fp := PThorpoint(objList[i]);
  494. SetVector(Ppos, fp^.Position);
  495. fp := @(Manager.FThorpoints[i]);
  496. SetVector(Ppos2, fp^.Position);
  497. glBegin(GL_TRIANGLE_FAN);
  498. glColor4fv(@Icol);
  499. glVertex3f(Ppos.X, Ppos.Y, Ppos.Z); // middle1
  500. glColor4fv(@Ocol);
  501. glVertex3f(Vx.X + Vy.X + Ppos.X,
  502. Vx.Y + Vy.Y + Ppos.Y, Vx.Z + Vy.Z +
  503. Ppos.Z); // TopRight
  504. glVertex3f(Vx.X * 1.4 + Ppos.X,
  505. Vx.Y * 1.4 + Ppos.Y, Vx.Z * 1.4 + Ppos.Z);
  506. // Right1
  507. glVertex3f(Vx.X - Vy.X + Ppos.X,
  508. Vx.Y - Vy.Y + Ppos.Y, Vx.Z - Vy.Z +
  509. Ppos.Z); // BottomRight
  510. glVertex3f(-Vy.X * 1.4 + Ppos.X,
  511. -Vy.Y * 1.4 + Ppos.Y, -Vy.Z * 1.4 + Ppos.Z
  512. ); // bottom1
  513. glVertex3f(-Vx.X - Vy.X + Ppos.X,
  514. -Vx.Y - Vy.Y + Ppos.Y, -Vx.Z - Vy.Z
  515. + Ppos.Z); // BottomLeft
  516. glVertex3f(-Vx.X * 1.4 + Ppos.X,
  517. -Vx.Y * 1.4 + Ppos.Y, -Vx.Z * 1.4 + Ppos.Z); // left1
  518. glVertex3f(-Vx.X + Vy.X + Ppos.X,
  519. -Vx.Y + Vy.Y + Ppos.Y, -Vx.Z + Vy.Z
  520. + Ppos.Z); // TopLeft
  521. glVertex3f(Vy.X * 1.4 + Ppos.X,
  522. Vy.Y * 1.4 + Ppos.Y, Vy.Z * 1.4 + Ppos.Z);
  523. // top1
  524. glVertex3f(Vx.X + Vy.X + Ppos.X,
  525. Vx.Y + Vy.Y + Ppos.Y, Vx.Z + Vy.Z +
  526. Ppos.Z); // TopRight
  527. glEnd;
  528. end; // Glow
  529. end;
  530. objList.Free;
  531. distList.Free;
  532. end;
  533. rci.PipelineTransformation.Pop;
  534. end;
  535. function GetOrCreateThorFX(obj: TgxBaseSceneObject; const name: String = '')
  536. : TgxBThorFX;
  537. var
  538. i: integer;
  539. begin
  540. with obj.Effects do
  541. begin
  542. if name = '' then
  543. begin
  544. i := IndexOfClass(TgxBThorFX);
  545. if i >= 0 then
  546. Result := TgxBThorFX(Items[i])
  547. else
  548. Result := TgxBThorFX.Create(obj.Effects);
  549. end
  550. else
  551. begin
  552. i := IndexOfName(name);
  553. if i >= 0 then
  554. Result := (Items[i] as TgxBThorFX)
  555. else
  556. begin
  557. Result := TgxBThorFX.Create(obj.Effects);
  558. Result.name := name;
  559. end;
  560. end;
  561. end;
  562. end;
  563. // ------------------------------------------------------------------
  564. initialization
  565. // ------------------------------------------------------------------
  566. RegisterXCollectionItemClass(TgxBThorFX);
  567. finalization
  568. UnregisterXCollectionItemClass(TgxBThorFX);
  569. end.