GXS.EParticleMasksManager.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831
  1. //
  2. // The graphics engine GXScene https://github.com/glscene
  3. //
  4. unit GXS.EParticleMasksManager;
  5. (*
  6. A pretty particle mask effect manager.
  7. Original Header:
  8. This unit is part of GLE - GLScene Game Utilities Engine set by Kenneth Poulter [email protected]
  9. Module Number: 37
  10. Description: This is merely an addon to GXS.Scene, since i don't want to edit GLScene's source code directly
  11. and make changes (since GXScene's source code constantly changes). What the manager does
  12. is to provide a basic tool for newly created particles to be modified (their position currently).
  13. Their position is set from 3 different masks, which create a "virtual" 3d object... meaning,
  14. an actual 3d object is not created, but an outline for particles or any other objects are positioned.
  15. ActualUsage: Create the component, create a new ParticleMask, set the material library, set the materials,
  16. and use the procedures provided in the managers root. positioning and scaling applicable as well.
  17. The images should be
  18. Licenses: Removed. Donated to GXScene's Code Base as long as the author (Kenneth Poulter) is not altered in this file.
  19. Theft of code also is not allowed, although alterations are allowed.
  20. *)
  21. interface
  22. {$I Stage.Defines.inc}
  23. uses
  24. System.Types,
  25. System.SysUtils,
  26. System.Classes,
  27. System.UITypes,
  28. FMX.Graphics,
  29. GXS.Color,
  30. GXS.Texture,
  31. GXS.Material,
  32. GXS.Scene,
  33. Stage.VectorGeometry,
  34. Stage.VectorTypes,
  35. GXS.ParticleFX,
  36. GXS.Coordinates;
  37. type
  38. TgxEProjectedParticleMask = (pptXMask, pptYMask, pptZMask);
  39. TgxEParticleMask = class;
  40. TgxEParticleMasks = class;
  41. TgxEParticleMask = class(TCollectionItem, IgxMaterialLibrarySupported)
  42. private
  43. FName: string;
  44. FScale: TgxCoordinates;
  45. FPosition: TgxCoordinates;
  46. FYMask: TgxLibMaterialName;
  47. FZMask: TgxLibMaterialName;
  48. FXMask: TgxLibMaterialName;
  49. FMaterialLibrary: TgxMaterialLibrary;
  50. FBackgroundColor: TColor;
  51. FMaskColor: TColor;
  52. FMaxX, FMaxY, FMaxZ, FMinX, FMinY, FMinZ: Integer;
  53. IXW, IXH, IYW, IYH, IZW, IZH: Integer;
  54. LX, LY, LZ: Integer;
  55. MX, MY: Integer;
  56. BogusMask, BogusMaskX, BogusMaskY, BogusMaskZ: Boolean;
  57. // we might have a pitch mask
  58. FRollAngle: Single;
  59. FPitchAngle: Single;
  60. FTurnAngle: Single;
  61. procedure SetName(const Value: string);
  62. procedure SetXMask(const Value: TgxLibMaterialName);
  63. procedure SetYMask(const Value: TgxLibMaterialName);
  64. procedure SetZMask(const Value: TgxLibMaterialName);
  65. procedure SetMaterialLibrary(const Value: TgxMaterialLibrary);
  66. function XCan: TBitmap;
  67. function YCan: TBitmap;
  68. function ZCan: TBitmap;
  69. //implementing IGLMaterialLibrarySupported
  70. function GetMaterialLibrary: TgxAbstractMaterialLibrary;
  71. //implementing IInterface
  72. function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  73. function _AddRef: Integer; stdcall;
  74. function _Release: Integer; stdcall;
  75. protected
  76. function GetDisplayName: string; override;
  77. public
  78. constructor Create(Collection: TCollection); override;
  79. destructor Destroy; override;
  80. procedure Assign(Source: TPersistent); override;
  81. procedure UpdateExtents;
  82. procedure Roll(Angle: Single);
  83. procedure Turn(Angle: Single);
  84. procedure Pitch(Angle: Single);
  85. // this generates a xmask from another mask just to fill gaps,
  86. // depth is dependant on frommask width and height
  87. procedure GenerateMaskFromProjection(FromMask, ToMask:
  88. TgxEProjectedParticleMask; Depth: Integer);
  89. published
  90. // scales and positions
  91. property Scale: TgxCoordinates read FScale write FScale;
  92. property Position: TgxCoordinates read FPosition write FPosition;
  93. // the reference name of the particle mask
  94. property Name: string read FName write SetName;
  95. property MaterialLibrary: TgxMaterialLibrary read FMaterialLibrary write
  96. SetMaterialLibrary;
  97. // mask images, make sure materiallibrary is assigned
  98. property XMask: TgxLibMaterialName read FXMask write SetXMask;
  99. property YMask: TgxLibMaterialName read FYMask write SetYMask;
  100. property ZMask: TgxLibMaterialName read FZMask write SetZMask;
  101. // background color is the color that prevents particles from being positioned there
  102. property BackgroundColor: TColor read FBackgroundColor write
  103. FBackgroundColor;
  104. // maskcolor is where particles are allowed to be positioned
  105. property MaskColor: TColor read FMaskColor write FMaskColor;
  106. // just the average angles for orientation
  107. property RollAngle: Single read FRollAngle write FRollAngle;
  108. property PitchAngle: Single read FPitchAngle write FPitchAngle;
  109. property TurnAngle: Single read FTurnAngle write FTurnAngle;
  110. end;
  111. TgxEParticleMasks = class(TCollection)
  112. protected
  113. Owner: TComponent;
  114. function GetOwner: TPersistent; override;
  115. procedure SetItems(Index: Integer; const Val: TgxEParticleMask);
  116. function GetItems(Index: Integer): TgxEParticleMask;
  117. public
  118. function Add: TgxEParticleMask;
  119. constructor Create(AOwner: TComponent);
  120. property Items[Index: Integer]: TgxEParticleMask read GetItems write
  121. SetItems; default;
  122. end;
  123. TgxEParticleMasksManager = class(TComponent)
  124. private
  125. FParticleMasks: TgxEParticleMasks;
  126. protected
  127. procedure ApplyOrthoGraphic(var Vec: TVector3f; Mask: TgxEParticleMask);
  128. procedure ApplyRotation(var Vec: TVector3f; Mask: TgxEParticleMask);
  129. procedure ApplyRotationTarget(var Vec: TVector3f; Mask: TgxEParticleMask;
  130. TargetObject: TgxBaseSceneObject);
  131. procedure ApplyScaleAndPosition(var Vec: TVector3f; Mask: TgxEParticleMask);
  132. procedure ApplyScaleAndPositionTarget(var Vec: TVector3f; Mask:
  133. TgxEParticleMask; TargetObject: TgxBaseSceneObject);
  134. procedure FindParticlePosition(var Vec: TVector3f; Mask: TgxEParticleMask);
  135. public
  136. constructor Create(AOwner: TComponent); override;
  137. destructor Destroy; override;
  138. function CreateParticlePositionFromMask(MaskName: string): TVector3f;
  139. function TargetParticlePositionFromMask(TargetObject: TgxBaseSceneObject;
  140. MaskName: string): TVector3f;
  141. procedure SetParticlePositionFromMask(Particle: TgxParticle; MaskName:
  142. string);
  143. procedure SetParticlePositionFromMaskTarget(Particle: TgxParticle; MaskName:
  144. string; TargetObject: TgxBaseSceneObject);
  145. function ParticleMaskByName(MaskName: string): TgxEParticleMask;
  146. published
  147. property ParticleMasks: TgxEParticleMasks read FParticleMasks write
  148. FParticleMasks;
  149. end;
  150. //----------------------------------------
  151. implementation
  152. //----------------------------------------
  153. //----------------------------------------
  154. // TgxEParticleMasks
  155. //----------------------------------------
  156. function TgxEParticleMasks.Add: TgxEParticleMask;
  157. begin
  158. Result := (inherited Add) as TgxEParticleMask;
  159. end;
  160. constructor TgxEParticleMasks.Create(AOwner: TComponent);
  161. begin
  162. inherited Create(TgxEParticleMask);
  163. Owner := AOwner;
  164. end;
  165. function TgxEParticleMasks.GetItems(Index: Integer): TgxEParticleMask;
  166. begin
  167. Result := TgxEParticleMask(inherited Items[Index]);
  168. end;
  169. function TgxEParticleMasks.GetOwner: TPersistent;
  170. begin
  171. Result := Owner;
  172. end;
  173. procedure TgxEParticleMasks.SetItems(Index: Integer; const Val:
  174. TgxEParticleMask);
  175. begin
  176. inherited Items[Index] := Val;
  177. end;
  178. //----------------------------------------
  179. // TgxEParticleMask
  180. //----------------------------------------
  181. procedure TgxEParticleMask.Assign(Source: TPersistent);
  182. begin
  183. if Source is TgxEParticleMask then
  184. begin
  185. FScale.Assign(TgxEParticleMask(Source).FScale);
  186. FPosition.Assign(TgxEParticleMask(Source).FPosition);
  187. FMaterialLibrary := TgxEParticleMask(Source).FMaterialLibrary;
  188. FXMask := TgxEParticleMask(Source).FXMask;
  189. FYMask := TgxEParticleMask(Source).FYMask;
  190. FZMask := TgxEParticleMask(Source).FZMask;
  191. end
  192. else
  193. inherited Assign(Source);
  194. end;
  195. constructor TgxEParticleMask.Create(Collection: TCollection);
  196. begin
  197. inherited Create(Collection);
  198. FName := 'ParticleMask' + IntToStr(ID);
  199. FScale := TgxCoordinates.CreateInitialized(Self, XYZHMGVector, csPoint);
  200. FPosition := TgxCoordinates.CreateInitialized(Self, NullHmgPoint, csPoint);
  201. FMaterialLibrary := nil;
  202. FMaskColor := TColorRec.White;
  203. FBackGroundColor := TColorRec.Black;
  204. FTurnAngle := 0;
  205. FRollAngle := 0;
  206. FPitchAngle := 0;
  207. FXMask := '';
  208. FYMask := '';
  209. FZMask := '';
  210. UpdateExtents;
  211. end;
  212. destructor TgxEParticleMask.Destroy;
  213. begin
  214. FScale.Free;
  215. FPosition.Free;
  216. FMaterialLibrary := nil;
  217. FBackgroundColor := TColorRec.Black;
  218. FMaskColor := TColorRec.White;
  219. FXMask := '';
  220. FYMask := '';
  221. FZMask := '';
  222. inherited Destroy;
  223. end;
  224. procedure TgxEParticleMask.GenerateMaskFromProjection(FromMask,
  225. ToMask: TgxEProjectedParticleMask; Depth: Integer);
  226. var
  227. FromBitMap: TBitmap;
  228. ToBitMap: TBitmap;
  229. X, Y: Integer;
  230. Rect: TRect;
  231. begin
  232. FromBitMap := nil;
  233. ToBitMap := nil;
  234. if not assigned(FMaterialLibrary) then
  235. Exit;
  236. if FromMask = ToMask then
  237. Exit; // we can't project to the same mask
  238. if Depth < 0 then
  239. Exit;
  240. case FromMask of
  241. pptXMask: FromBitMap := XCan;
  242. pptYMask: FromBitMap := YCan;
  243. pptZMask: FromBitMap := ZCan;
  244. end;
  245. if (FromBitMap.Width = 0) and (FromBitMap.Height = 0) then
  246. Exit; // we can't use something that has no image
  247. case ToMask of
  248. pptXMask: ToBitMap := XCan;
  249. pptYMask: ToBitMap := YCan;
  250. pptZMask: ToBitMap := ZCan;
  251. end;
  252. ToBitMap.Width := FromBitMap.Width;
  253. ToBitMap.Height := FromBitMap.Height;
  254. // TODO : E2003 Undeclared identifier: 'Pen'
  255. (*
  256. ToBitMap.Canvas.Pen.Color := FBackgroundColor;
  257. ToBitMap.Canvas.Pen.Style := psSolid;
  258. ToBitMap.Canvas.Brush.Color := FBackgroundColor;
  259. ToBitMap.Canvas.Brush.Style := bsSolid;
  260. *)
  261. Rect.Left := 0;
  262. Rect.Top := 0;
  263. Rect.Right := ToBitMap.Width;
  264. Rect.Bottom := ToBitMap.Height;
  265. { TODO : E2250 There is no overloaded version of 'FillRect' that can be called with these arguments }
  266. (*ToBitMap.Canvas.FillRect(Rect);*)
  267. { TODO : E2003 Undeclared identifier: 'Pen' }
  268. (*
  269. ToBitMap.Canvas.Pen.Color := FMaskColor;
  270. ToBitMap.Canvas.Brush.Color := FMaskColor;
  271. *)
  272. for X := 0 to ToBitMap.Width do
  273. for Y := 0 to ToBitMap.Height do
  274. begin
  275. // from x mask
  276. if (FromMask = pptXMask) and (ToMask = pptYMask) then
  277. // TODO : E2003 Undeclared identifier: 'Pixels'
  278. (*
  279. if FromBitMap.Canvas.Pixels[X, Y] = FMaskColor then
  280. begin
  281. ToBitMap.Canvas.MoveTo(((FromBitmap.Width - Depth) div 2), X);
  282. ToBitMap.Canvas.LineTo(((FromBitmap.Width + Depth) div 2), X);
  283. end;
  284. if (FromMask = pptXMask) and (ToMask = pptZMask) then
  285. if FromBitMap.Canvas.Pixels[X, Y] = FMaskColor then
  286. begin
  287. ToBitMap.Canvas.MoveTo(((FromBitmap.Width - Depth) div 2), Y);
  288. ToBitMap.Canvas.LineTo(((FromBitmap.Width + Depth) div 2), Y);
  289. end;
  290. // from y mask
  291. if (FromMask = pptYMask) and (ToMask = pptXMask) then
  292. if FromBitMap.Canvas.Pixels[X, Y] = FMaskColor then
  293. begin
  294. ToBitMap.Canvas.MoveTo(Y, ((FromBitmap.Height - Depth) div 2));
  295. ToBitMap.Canvas.LineTo(Y, ((FromBitmap.Height + Depth) div 2));
  296. end;
  297. if (FromMask = pptYMask) and (ToMask = pptZMask) then
  298. if FromBitMap.Canvas.Pixels[X, Y] = FMaskColor then
  299. begin
  300. ToBitMap.Canvas.MoveTo(X, ((FromBitmap.Height - Depth) div 2));
  301. ToBitMap.Canvas.LineTo(X, ((FromBitmap.Height + Depth) div 2));
  302. end;
  303. // from z mask
  304. if (FromMask = pptZMask) and (ToMask = pptXMask) then
  305. if FromBitMap.Canvas.Pixels[X, Y] = FMaskColor then
  306. begin
  307. ToBitMap.Canvas.MoveTo(((FromBitmap.Width - Depth) div 2), Y);
  308. ToBitMap.Canvas.LineTo(((FromBitmap.Width + Depth) div 2), Y);
  309. end;
  310. if (FromMask = pptZMask) and (ToMask = pptYMask) then
  311. if FromBitMap.Canvas.Pixels[X, Y] = FMaskColor then
  312. begin
  313. ToBitMap.Canvas.MoveTo(X, ((FromBitmap.Height - Depth) div 2));
  314. ToBitMap.Canvas.LineTo(X, ((FromBitmap.Height + Depth) div 2));
  315. end;
  316. *)
  317. end;
  318. UpdateExtents;
  319. end;
  320. function TgxEParticleMask.GetDisplayName: string;
  321. begin
  322. Result := '';
  323. if FName <> '' then
  324. Result := FName
  325. else
  326. Result := 'TgxEParticleMask';
  327. end;
  328. function TgxEParticleMask.GetMaterialLibrary: TgxAbstractMaterialLibrary;
  329. begin
  330. Result := FMaterialLibrary;
  331. end;
  332. procedure TgxEParticleMask.Pitch(Angle: Single);
  333. begin
  334. FPitchAngle := FPitchAngle + Angle;
  335. end;
  336. procedure TgxEParticleMask.Roll(Angle: Single);
  337. begin
  338. FRollAngle := FRollAngle + Angle;
  339. end;
  340. procedure TgxEParticleMask.SetMaterialLibrary(const Value: TgxMaterialLibrary);
  341. begin
  342. FMaterialLibrary := Value;
  343. UpdateExtents;
  344. end;
  345. procedure TgxEParticleMask.SetName(const Value: string);
  346. var
  347. I: Integer;
  348. begin
  349. for I := 1 to Length(Value) do
  350. if Value[I] = ' ' then
  351. begin
  352. raise Exception.Create('Cannot contain spaces or special characters.');
  353. Exit;
  354. end;
  355. FName := Value;
  356. end;
  357. procedure TgxEParticleMask.SetXMask(const Value: TgxLibMaterialName);
  358. begin
  359. FXMask := Value;
  360. if assigned(FMaterialLibrary) then
  361. if not assigned(FMaterialLibrary.LibMaterialByName(FXMask)) then
  362. begin
  363. XCan.Width := 0;
  364. XCan.Height := 0;
  365. end;
  366. UpdateExtents;
  367. end;
  368. procedure TgxEParticleMask.SetYMask(const Value: TgxLibMaterialName);
  369. begin
  370. FYMask := Value;
  371. if assigned(FMaterialLibrary) then
  372. if not assigned(FMaterialLibrary.LibMaterialByName(FYMask)) then
  373. begin
  374. YCan.Width := 0;
  375. YCan.Height := 0;
  376. end;
  377. UpdateExtents;
  378. end;
  379. procedure TgxEParticleMask.SetZMask(const Value: TgxLibMaterialName);
  380. begin
  381. FZMask := Value;
  382. if assigned(FMaterialLibrary) then
  383. if not assigned(FMaterialLibrary.LibMaterialByName(FZMask)) then
  384. begin
  385. ZCan.Width := 0;
  386. ZCan.Height := 0;
  387. end;
  388. UpdateExtents;
  389. end;
  390. procedure TgxEParticleMask.Turn(Angle: Single);
  391. begin
  392. FTurnAngle := FTurnAngle + Angle;
  393. end;
  394. procedure TgxEParticleMask.UpdateExtents;
  395. var
  396. MinXX, MinXY, MinYX, MinYY, MinZX, MinZY: Integer;
  397. MaxXX, MaxXY, MaxYX, MaxYY, MaxZX, MaxZY: Integer;
  398. X, Y: Integer;
  399. begin
  400. FMinX := 0; // min extents
  401. FMinY := 0;
  402. FMinZ := 0;
  403. FMaxX := 0; // max extents
  404. FMaxY := 0;
  405. FMaxZ := 0;
  406. IXW := 0; // widths
  407. IYW := 0;
  408. IZW := 0;
  409. IXH := 0; // heights
  410. IYH := 0;
  411. IZH := 0;
  412. MinXX := 0; // min plane mask extents
  413. MinXY := 0;
  414. MinYX := 0;
  415. MinYY := 0;
  416. MinZX := 0;
  417. MinZY := 0;
  418. MaxXX := 0; // max plane mask extents
  419. MaxXY := 0;
  420. MaxYX := 0;
  421. MaxYY := 0;
  422. MaxZX := 0;
  423. MaxZY := 0;
  424. BogusMask := True; // prevents system locks
  425. BogusMaskX := True;
  426. BogusMaskY := True;
  427. BogusMaskZ := True;
  428. // we don't find it? no point in continuing
  429. if not assigned(FMaterialLibrary) then
  430. Exit;
  431. // it is recommended to have 3 different masks
  432. // if there is only 2, the 3rd image will just take the largest extents and use them...
  433. // creating not a very good effect
  434. if XCan <> nil then
  435. begin
  436. IXW := XCan.Width;
  437. IXH := XCan.Height;
  438. end;
  439. if YCan <> nil then
  440. begin
  441. IYW := YCan.Width;
  442. IYH := YCan.Height;
  443. end;
  444. if ZCan <> nil then
  445. begin
  446. IZW := ZCan.Width;
  447. IZH := ZCan.Height;
  448. end;
  449. // we find the largest dimensions of each image and give them to min mask extents so we work backwards
  450. MX := MaxInteger(MaxInteger(IXW, IYW), IZW);
  451. MY := MaxInteger(MaxInteger(IXH, IYH), IZH);
  452. if XCan <> nil then
  453. begin
  454. MinXX := MX;
  455. MinXY := MY;
  456. end;
  457. if YCan <> nil then
  458. begin
  459. MinYX := MX;
  460. MinYY := MY;
  461. end;
  462. if ZCan <> nil then
  463. begin
  464. MinZX := MX;
  465. MinZY := MY;
  466. end;
  467. // this is where we work backwards from to find the max size of the dimensions...
  468. // in a sense, this provides information for the randomizing, and speeds up the code
  469. for X := 0 to MX do
  470. for Y := 0 to MY do
  471. begin
  472. if XCan <> nil then
  473. if (X <= XCan.Width) and (Y <= XCan.Height) then
  474. // TODO : E2003 Undeclared identifier: 'Pixels'
  475. (*if (XCan.Canvas.Pixels[X, Y] = FMaskColor) then*)
  476. begin
  477. if X > MaxXX then
  478. MaxXX := X;
  479. if Y > MaxXY then
  480. MaxXY := Y;
  481. if X < MinXX then
  482. MinXX := X;
  483. if X < MinXY then
  484. MinXY := Y;
  485. BogusMaskX := False;
  486. end;
  487. if YCan <> nil then
  488. if (X <= YCan.Width) and (Y <= YCan.Height) then
  489. // TODO : E2003 Undeclared identifier: 'Pixels'
  490. (* if (YCan.Canvas.Pixels[X, Y] = FMaskColor) then*)
  491. begin
  492. if X > MaxYX then
  493. MaxYX := X;
  494. if Y > MaxYY then
  495. MaxYY := Y;
  496. if X < MinYX then
  497. MinYX := X;
  498. if X < MinYY then
  499. MinYY := Y;
  500. BogusMaskY := False;
  501. end;
  502. if ZCan <> nil then
  503. if (X <= ZCan.Width) and (Y <= ZCan.Height) then
  504. // TODO : E2003 Undeclared identifier: 'Pixels'
  505. (*if (ZCan.Canvas.Pixels[X, Y] = FMaskColor) then*)
  506. begin
  507. if X > MaxZX then
  508. MaxZX := X;
  509. if Y > MaxZY then
  510. MaxZY := Y;
  511. if X < MinZX then
  512. MinZX := X;
  513. if X < MinZY then
  514. MinZY := Y;
  515. BogusMaskZ := False;
  516. end;
  517. end;
  518. BogusMask := (BogusMaskX or BogusMaskY or BogusMaskZ);
  519. // here we find our 3d extents from a 1st angle orthographic shape
  520. FMinX := MinInteger(MinZX, MinYX);
  521. FMinY := MinInteger(MinXY, MinZY);
  522. FMinZ := MinInteger(MinXX, MinYY);
  523. FMaxX := MaxInteger(MaxZX, MaxYX);
  524. FMaxY := MaxInteger(MaxXY, MaxZY);
  525. FMaxZ := MaxInteger(MaxXX, MaxYY);
  526. // this is the largest mask image sizes converted to orthographic and extents... used later on
  527. LX := MaxInteger(IZW, IYW);
  528. LY := MaxInteger(IXH, IZH);
  529. LZ := MaxInteger(IXW, IYH);
  530. end;
  531. function TgxEParticleMask.XCan: TBitmap;
  532. begin
  533. Result := nil;
  534. if not assigned(FMaterialLibrary) then
  535. Exit;
  536. if not assigned(FMaterialLibrary.LibMaterialByName(FXMask)) then
  537. Exit;
  538. if FMaterialLibrary.LibMaterialByName(FXMask).Material.Texture.ImageClassName
  539. <> TgxPersistentImage.ClassName then
  540. Exit;
  541. Result :=
  542. TBitmap((FMaterialLibrary.LibMaterialByName(FXMask).Material.Texture.Image as
  543. TgxPersistentImage).Picture.Bitmap);
  544. end;
  545. function TgxEParticleMask.YCan: TBitmap;
  546. begin
  547. Result := nil;
  548. if not assigned(FMaterialLibrary) then
  549. Exit;
  550. if not assigned(FMaterialLibrary.LibMaterialByName(FYMask)) then
  551. Exit;
  552. if FMaterialLibrary.LibMaterialByName(FYMask).Material.Texture.ImageClassName
  553. <> TgxPersistentImage.ClassName then
  554. Exit;
  555. Result :=
  556. TBitmap((FMaterialLibrary.LibMaterialByName(FYMask).Material.Texture.Image as
  557. TgxPersistentImage).Picture.Bitmap);
  558. end;
  559. function TgxEParticleMask.ZCan: TBitmap;
  560. begin
  561. Result := nil;
  562. if not assigned(FMaterialLibrary) then
  563. Exit;
  564. if not assigned(FMaterialLibrary.LibMaterialByName(FZMask)) then
  565. Exit;
  566. if FMaterialLibrary.LibMaterialByName(FZMask).Material.Texture.ImageClassName
  567. <> TgxPersistentImage.ClassName then
  568. Exit;
  569. Result :=
  570. TBitmap((FMaterialLibrary.LibMaterialByName(FZMask).Material.Texture.Image as
  571. TgxPersistentImage).Picture.Bitmap);
  572. end;
  573. function TgxEParticleMask.QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  574. begin
  575. if GetInterface(IID, Obj) then
  576. Result := S_OK
  577. else
  578. Result := E_NOINTERFACE;
  579. end;
  580. function TgxEParticleMask._AddRef: Integer; stdcall;
  581. begin
  582. Result := -1; //ignore
  583. end;
  584. function TgxEParticleMask._Release: Integer; stdcall;
  585. begin
  586. Result := -1; //ignore
  587. end;
  588. //----------------------------------------
  589. // TgxEParticleMasksManager
  590. //----------------------------------------
  591. procedure TgxEParticleMasksManager.ApplyOrthoGraphic(var Vec: TVector3f; Mask:
  592. TgxEParticleMask);
  593. begin
  594. Vec.X := (Mask.LX / 2 - Vec.X) / Mask.LX;
  595. Vec.Y := (Mask.LY / 2 - Vec.Y) / Mask.LY;
  596. Vec.Z := (Mask.LZ / 2 - Vec.Z) / Mask.LZ;
  597. end;
  598. procedure TgxEParticleMasksManager.ApplyRotation(var Vec: TVector3f; Mask:
  599. TgxEParticleMask);
  600. begin
  601. Vec := VectorRotateAroundX(Vec, DegToRadian(Mask.FPitchAngle));
  602. Vec := VectorRotateAroundY(Vec, DegToRadian(Mask.FTurnAngle));
  603. Vec := VectorRotateAroundZ(Vec, DegToRadian(Mask.FRollAngle));
  604. end;
  605. procedure TgxEParticleMasksManager.ApplyRotationTarget(var Vec: TVector3f; Mask:
  606. TgxEParticleMask; TargetObject: TgxBaseSceneObject);
  607. begin
  608. Vec := VectorRotateAroundX(Vec, DegToRadian(Mask.FPitchAngle +
  609. TargetObject.Rotation.X));
  610. Vec := VectorRotateAroundY(Vec, DegToRadian(Mask.FTurnAngle +
  611. TargetObject.Rotation.Y));
  612. Vec := VectorRotateAroundZ(Vec, DegToRadian(Mask.FRollAngle +
  613. TargetObject.Rotation.Z));
  614. end;
  615. procedure TgxEParticleMasksManager.ApplyScaleAndPosition(var Vec: TVector3f;
  616. Mask: TgxEParticleMask);
  617. begin
  618. Vec.X := Vec.X * Mask.FScale.DirectX + Mask.FPosition.DirectX;
  619. Vec.Y := Vec.Y * Mask.FScale.DirectY + Mask.FPosition.DirectY;
  620. Vec.Z := Vec.Z * Mask.FScale.DirectZ + Mask.FPosition.DirectZ;
  621. end;
  622. procedure TgxEParticleMasksManager.ApplyScaleAndPositionTarget(var Vec:
  623. TVector3f; Mask: TgxEParticleMask; TargetObject: TgxBaseSceneObject);
  624. begin
  625. Vec.X := Vec.X * Mask.FScale.DirectX * TargetObject.Scale.DirectX +
  626. Mask.FPosition.DirectX + TargetObject.AbsolutePosition.X;
  627. Vec.Y := Vec.Y * Mask.FScale.DirectY * TargetObject.Scale.DirectY +
  628. Mask.FPosition.DirectY + TargetObject.AbsolutePosition.Y;
  629. Vec.Z := Vec.Z * Mask.FScale.DirectZ * TargetObject.Scale.DirectZ +
  630. Mask.FPosition.DirectZ + TargetObject.AbsolutePosition.Z;
  631. end;
  632. constructor TgxEParticleMasksManager.Create(AOwner: TComponent);
  633. begin
  634. inherited Create(AOwner);
  635. FParticleMasks := TgxEParticleMasks.Create(Self);
  636. end;
  637. function TgxEParticleMasksManager.CreateParticlePositionFromMask(MaskName:
  638. string): TVector3f;
  639. var
  640. Mask: TgxEParticleMask;
  641. begin
  642. Result := NullVector;
  643. Mask := ParticleMaskByName(MaskName);
  644. if not assigned(Mask) then
  645. Exit;
  646. if Mask.BogusMask then
  647. Exit;
  648. // finds the particle position on the masks
  649. FindParticlePosition(Result, Mask);
  650. // this converts 1st angle orthographic to 3rd angle orthograhic
  651. ApplyOrthoGraphic(Result, Mask);
  652. // this just turns it accordingly
  653. ApplyRotation(Result, Mask);
  654. // this applies the scales and positioning
  655. ApplyScaleAndPosition(Result, Mask);
  656. end;
  657. destructor TgxEParticleMasksManager.Destroy;
  658. begin
  659. FParticleMasks.Destroy;
  660. inherited Destroy;
  661. end;
  662. procedure TgxEParticleMasksManager.FindParticlePosition(var Vec: TVector3f;
  663. Mask: TgxEParticleMask);
  664. var
  665. X, Y, Z: Integer;
  666. begin
  667. // TODO : E2003 Undeclared identifier: 'Pixels'
  668. (*
  669. repeat
  670. X := Random(Mask.FMaxX - Mask.FMinX) + Mask.FMinX;
  671. Y := Random(Mask.FMaxY - Mask.FMinY) + Mask.FMinY;
  672. Z := Random(Mask.FMaxZ - Mask.FMinZ) + Mask.FMinZ;
  673. until (Mask.XCan.Canvas.Pixels[Z, Y] = Mask.FMaskColor) and
  674. (Mask.YCan.Canvas.Pixels[X, Z] = Mask.FMaskColor) and
  675. (Mask.ZCan.Canvas.Pixels[X, Y] = Mask.FMaskColor);
  676. *)
  677. MakeVector(Vec, X, Y, Z);
  678. end;
  679. function TgxEParticleMasksManager.ParticleMaskByName(MaskName: string):
  680. TgxEParticleMask;
  681. var
  682. I: Integer;
  683. begin
  684. Result := nil;
  685. if FParticleMasks.Count > 0 then
  686. for I := 0 to FParticleMasks.Count - 1 do
  687. if FParticleMasks.Items[I].FName = MaskName then
  688. Result := FParticleMasks.Items[I];
  689. end;
  690. procedure TgxEParticleMasksManager.SetParticlePositionFromMask(
  691. Particle: TgxParticle; MaskName: string);
  692. begin
  693. if not assigned(Particle) then
  694. Exit;
  695. Particle.Position := CreateParticlePositionFromMask(MaskName);
  696. end;
  697. procedure TgxEParticleMasksManager.SetParticlePositionFromMaskTarget(
  698. Particle: TgxParticle; MaskName: string; TargetObject: TgxBaseSceneObject);
  699. begin
  700. if not assigned(Particle) then
  701. Exit;
  702. Particle.Position := TargetParticlePositionFromMask(TargetObject, MaskName);
  703. end;
  704. function TgxEParticleMasksManager.TargetParticlePositionFromMask(
  705. TargetObject: TgxBaseSceneObject; MaskName: string): TVector3f;
  706. var
  707. Mask: TgxEParticleMask;
  708. begin
  709. Result := NullVector;
  710. if not assigned(TargetObject) then
  711. Exit;
  712. Mask := ParticleMaskByName(MaskName);
  713. if not assigned(Mask) then
  714. Exit;
  715. if Mask.BogusMask then
  716. Exit;
  717. // finds the particle position on the masks
  718. FindParticlePosition(Result, Mask);
  719. // this converts 1st angle orthographic to 3rd angle orthograhic
  720. ApplyOrthoGraphic(Result, Mask);
  721. // this just turns it accordingly
  722. ApplyRotationTarget(Result, Mask, TargetObject);
  723. // this applies the scales and positioning
  724. ApplyScaleAndPositionTarget(Result, Mask, TargetObject);
  725. end;
  726. end.