GLS.ThorFX.pas 16 KB

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