GLS.EParticleMasksManager.pas 23 KB

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