C2Affectors.pas
上传用户:yj_qiu
上传日期:2022-08-08
资源大小:23636k
文件大小:29k
源码类别:

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @Abstract(CAST II Engine affectors unit)
  3.  (C) 2006-2007 George "Mirage" Bakhtadze. <a href="http://www.casteng.com">www.casteng.com</a> <br>
  4.  The source code may be used under either MPL 1.1 or LGPL 2.1 license. See included license.txt file <br>
  5.  Created: 08.01.2007 <br>
  6.  Unit contains basic affectors and emitters for particle systems
  7. *)
  8. {$Include GDefines.inc}
  9. {$Include C2Defines.inc}
  10. unit C2Affectors;
  11. interface
  12. uses
  13.   SysUtils,
  14.   BaseTypes, Basics, BaseCont, Props, Base3D, BaseClasses,
  15.   CAST2, C2Particle;
  16. type
  17.   TPSMover = class(C2Particle.TPSAffector)
  18.     procedure Process(const DeltaT: BaseClasses.Float); override;
  19.   end;
  20.   TRangedAffector = class(C2Particle.TPSAffector)
  21.     Range: Single;
  22.     constructor Create(AManager: TItemsManager); override;
  23.     procedure AddProperties(const Result: Props.TProperties); override;
  24.     procedure SetProperties(Properties: Props.TProperties); override;
  25.   end;
  26.   TPSAttractor = class(TRangedAffector)
  27.     MinRange, Intensity: Single;
  28.     procedure AddProperties(const Result: Props.TProperties); override;
  29.     procedure SetProperties(Properties: Props.TProperties); override;
  30.     procedure Process(const DeltaT: BaseClasses.Float); override;
  31.   end;
  32.   TPSAbsorber = class(TRangedAffector)
  33.     Intensity: Single;
  34.     procedure AddProperties(const Result: Props.TProperties); override;
  35.     procedure SetProperties(Properties: Props.TProperties); override;
  36.     procedure Process(const DeltaT: BaseClasses.Float); override;
  37.   end;
  38.   TPSColorInterpolator = class(C2Particle.TPSAffector)
  39.   public
  40.     Colors: TSampledGradient;
  41.     constructor Create(AManager: TItemsManager); override;
  42.     destructor Destroy; override;
  43.     procedure AddProperties(const Result: Props.TProperties); override;
  44.     procedure SetProperties(Properties: Props.TProperties); override;
  45.     procedure Process(const DeltaT: BaseClasses.Float); override;
  46.   end;
  47.   TPSForce = class(TRangedAffector)
  48.     Force: TVector3s;
  49.     procedure AddProperties(const Result: Props.TProperties); override;
  50.     procedure SetProperties(Properties: Props.TProperties); override;
  51.     procedure Process(const DeltaT: BaseClasses.Float); override;
  52.   end;
  53.   TSphericalEmitter = class(C2Particle.TEmitter)
  54.   public
  55.     Tangent: Boolean;
  56.     PhiRange ,ThetaRange,
  57.     EmitMinRadius, EmitMaxRadius, MinSpeed, MaxSpeed: TSampledFloats;
  58.     constructor Create(AManager: TItemsManager); override;
  59.     destructor Destroy; override;
  60.     procedure AddProperties(const Result: Props.TProperties); override;
  61.     procedure SetProperties(Properties: Props.TProperties); override;
  62.     procedure InitParticles(Index, EmittedStart, EmittedEnd: Integer); override;
  63.   end;
  64.   TPSUniAffector = class(C2Particle.TPSAffector)
  65.   protected
  66.     FColor: TSampledGradient;
  67.     FSizeModulator, FForceModulator, FSpeedModulator, FAngle: TSampledFloats;
  68.   public
  69.     Force: TVector3s;
  70.     LifeTime: Single;
  71.     constructor Create(AManager: TItemsManager); override;
  72.     destructor Destroy; override;
  73.     procedure AddProperties(const Result: Props.TProperties); override;
  74.     procedure SetProperties(Properties: Props.TProperties); override;
  75.     procedure Process(const DeltaT: BaseClasses.Float); override;
  76.     property Color: TSampledGradient read FColor;
  77.     property SizeModulator: TSampledFloats read FSizeModulator;
  78.     property ForceModulator: TSampledFloats read FForceModulator;
  79.     property Angle: TSampledFloats read FAngle;
  80.   end;
  81.   // Affector which moves partciles of affected system into places of particles of source system. This can be used to emulate sub-emitters.
  82.   TSubEmitter = class(TSphericalEmitter)
  83.   protected
  84.     FSourceSystem: TParticleSystem;
  85.     procedure ResolveLinks; override;
  86.   public
  87.     // Age range of source particle which should cause emit
  88.     SrcAgeStart, SrcAgeEnd: Single;
  89.     // Determines if need to kill source particle when emitting from it
  90.     KillSource: Boolean;
  91.     procedure AddProperties(const Result: Props.TProperties); override;
  92.     procedure SetProperties(Properties: Props.TProperties); override;
  93.     procedure InitParticles(Index, EmittedStart, EmittedEnd: Integer); override;
  94.   end;
  95.   TPSRandomAffector = class(C2Particle.TPSAffector)
  96.   public
  97.     Color, Size, Coords, Speed, PAge, Angle: TSampledFloats;
  98.     constructor Create(AManager: TItemsManager); override;
  99.     destructor Destroy; override;
  100.     procedure AddProperties(const Result: Props.TProperties); override;
  101.     procedure SetProperties(Properties: Props.TProperties); override;
  102.     procedure Process(const DeltaT: BaseClasses.Float); override;
  103.   end;
  104.   // Returns list of classes introduced by the unit
  105.   function GetUnitClassList: TClassArray;
  106. implementation
  107. function GetUnitClassList: TClassArray;
  108. begin
  109.   Result := GetClassList([TParticleSystem, T2DParticleSystem, T3DParticleSystem,
  110.                           TEmitter, TSphericalEmitter, TSubEmitter,
  111.                           TPSAffector, TPSMover, TPSAttractor, TPSAbsorber, TPSColorInterpolator, TPSForce, TPSUniAffector, TPSRandomAffector
  112.                           ]);
  113. end;
  114. { TPSMover }
  115. procedure TPSMover.Process(const DeltaT: BaseClasses.Float);
  116. var Index, i: Integer;
  117.   procedure CheckBBox(const Coord: TVector3s);
  118.   begin
  119.     with ParticleSystem[Index] do begin
  120.       BoundingBox.P1.X := MinS(BoundingBox.P1.X, Coord.X - MaxSize);
  121.       BoundingBox.P1.Y := MinS(BoundingBox.P1.Y, Coord.Y - MaxSize);
  122.       BoundingBox.P1.Z := MinS(BoundingBox.P1.Z, Coord.Z - MaxSize);
  123.       BoundingBox.P2.X := MaxS(BoundingBox.P2.X, Coord.X + MaxSize);
  124.       BoundingBox.P2.Y := MaxS(BoundingBox.P2.Y, Coord.Y + MaxSize);
  125.       BoundingBox.P2.Z := MaxS(BoundingBox.P2.Z, Coord.Z + MaxSize);
  126.     end;
  127.   end;
  128. begin
  129.   inherited;
  130.   for Index := 0 to TotalParticleSystems-1 do
  131.     if Assigned(ParticleSystem[Index]) and (isProcessing in ParticleSystem[Index].State) then begin
  132.     ParticleSystem[Index].BoundingBox.P1 := GetVector3s(MaxFloatValue, MaxFloatValue, MaxFloatValue);
  133.     ParticleSystem[Index].BoundingBox.P2 := GetVector3s(-MaxFloatValue, -MaxFloatValue, -MaxFloatValue);
  134.     for i := ParticleSystem[Index].TotalParticles-1 downto 0 do with ParticleSystem[Index].SimulationData[i] do
  135.       if (Age >= AgeStart) and (Age < AgeEnd) then with ParticleSystem[Index].RenderData[i] do begin
  136.         AddVector3s(Position, Position, ScaleVector3s(Velocity, DeltaT));
  137.         Age := Age + DeltaT;
  138.         if ParticleSystem[Index].MaxSize < Size*0.5 then ParticleSystem[Index].MaxSize := Size*0.5;
  139.         CheckBBox(Position);
  140.       end;
  141.   end;
  142. end;
  143. { TPSAttractor }
  144. procedure TPSAttractor.AddProperties(const Result: Props.TProperties);
  145. begin
  146.   inherited;
  147.   if not Assigned(Result) then Exit;
  148.   Result.Add('Min. range',  vtSingle,  [], FloatToStr(MinRange),  '');
  149.   Result.Add('Intensity',   vtSingle,  [], FloatToStr(Intensity), '');
  150. end;
  151. procedure TPSAttractor.SetProperties(Properties: Props.TProperties);
  152. begin
  153.   inherited;
  154.   if Properties.Valid('Min. range')  then MinRange    := StrToFloatDef(Properties['Min. range'],  0);
  155.   if Properties.Valid('Intensity')   then Intensity   := StrToFloatDef(Properties['Intensity'],   0);
  156. end;
  157. procedure TPSAttractor.Process(const DeltaT: BaseClasses.Float);
  158. var i, Index: Integer; SystemAffector, ParticleAffector: TVector3s; Dist: Single;
  159. begin
  160.   inherited;
  161.   for Index := 0 to TotalParticleSystems-1 do
  162.     if Assigned(ParticleSystem[Index]) and (isProcessing in ParticleSystem[Index].State) then begin
  163.     CalcPositionInSystem(Index, SystemAffector);
  164.     for i := ParticleSystem[Index].TotalParticles-1 downto 0 do
  165.       with ParticleSystem[Index].SimulationData[i] do if (Age >= AgeStart) and (Age < AgeEnd) then begin
  166.         SubVector3s(ParticleAffector, SystemAffector, ParticleSystem[Index].RenderData[i].Position);
  167.         Dist := MaxS(Sqr(MinRange), SqrMagnitude(ParticleAffector));
  168.         if Dist < Sqr(Range) then begin
  169.     //      Dist := InvSqrt(Dist);
  170.     //      if Attenuation then AttractionPower := Intensity * Dist else AttractionPower := Intensity;
  171.           AddVector3s(Velocity, Velocity, ScaleVector3s(ParticleAffector, Intensity * DeltaT / Dist));
  172.         end;
  173.       end;
  174.   end;
  175. end;
  176. { TRangedAffector }
  177. constructor TRangedAffector.Create(AManager: TItemsManager);
  178. begin
  179.   inherited;
  180.   Range := MaxFloatValue;
  181. end;
  182. procedure TRangedAffector.AddProperties(const Result: Props.TProperties);
  183. begin
  184.   inherited;
  185.   if not Assigned(Result) then Exit;
  186.   Result.Add('Range', vtSingle, [], FloatToStr(Range), '');
  187. end;
  188. procedure TRangedAffector.SetProperties(Properties: Props.TProperties);
  189. begin
  190.   inherited;
  191.   if Properties.Valid('Range') then Range := StrToFloatDef(Properties['Range'], 0);
  192. end;
  193. { TPSAbsorber }
  194. procedure TPSAbsorber.AddProperties(const Result: Props.TProperties);
  195. begin
  196.   inherited;
  197.   if not Assigned(Result) then Exit;
  198.   Result.Add('Intensity', vtSingle, [], FloatToStr(Intensity), '');
  199. end;
  200. procedure TPSAbsorber.SetProperties(Properties: Props.TProperties);
  201. begin
  202.   inherited;   
  203.   if Properties.Valid('Intensity') then Intensity := StrToFloatDef(Properties['Intensity'], 0);
  204. end;
  205. procedure TPSAbsorber.Process(const DeltaT: BaseClasses.Float);
  206. var i, Index: Integer; SystemAffector: TVector3s;
  207. begin
  208.   inherited;
  209.   for Index := 0 to TotalParticleSystems-1 do
  210.     if Assigned(ParticleSystem[Index]) and (isProcessing in ParticleSystem[Index].State) then begin
  211.     CalcPositionInSystem(Index, SystemAffector);
  212.     for i := ParticleSystem[Index].TotalParticles-1 downto 0 do with ParticleSystem[Index].SimulationData[i] do begin
  213.       if ( (Age >= AgeStart) and (Age < AgeEnd) ) and
  214.          ( (Range = 0) or (SqrMagnitude(SubVector3s(SystemAffector, ParticleSystem[Index].RenderData[i].Position)) < Sqr(Range)) ) then
  215.         ParticleSystem[Index].Kill(i);
  216.     end;
  217.   end;
  218. end;
  219. { TPSColorInterpolator }
  220. constructor TPSColorInterpolator.Create(AManager: TItemsManager);
  221. begin
  222.   inherited;
  223.   Colors := TSampledGradient.Create;
  224. end;
  225. destructor TPSColorInterpolator.Destroy;
  226. begin
  227.   FreeAndNil(Colors);
  228.   inherited;
  229. end;
  230. procedure TPSColorInterpolator.AddProperties(const Result: Props.TProperties);
  231. begin
  232.   inherited;
  233.   if not Assigned(Result) then Exit;
  234.   Colors.AddAsProperty(Result, 'Colors');
  235. end;
  236. procedure TPSColorInterpolator.SetProperties(Properties: Props.TProperties);
  237. begin
  238.   inherited;
  239.   Colors.SetFromProperty(Properties, 'Colors');
  240. end;
  241. procedure TPSColorInterpolator.Process(const DeltaT: BaseClasses.Float);
  242. var
  243.   i, Index: Integer;
  244.   AgeNormK, Modulator: Single;
  245. begin
  246.   inherited;
  247.   AgeNormK := 1/(AgeEnd-AgeStart);
  248.   if Colors.Enabled then for Index := 0 to TotalParticleSystems-1 do
  249.     if Assigned(ParticleSystem[Index]) and (isProcessing in ParticleSystem[Index].State) then begin
  250.     
  251.     for i := ParticleSystem[Index].TotalParticles-1 downto 0 do with ParticleSystem[Index].SimulationData[i] do
  252.       if (Age >= AgeStart) and (Age < AgeEnd) then begin
  253.         Modulator := (Age - AgeStart) * AgeNormK;
  254.         ParticleSystem[Index].RenderData[i].Color := Colors.Value[Modulator];
  255.       end;
  256.   end;
  257. end;
  258. { TPSForce }
  259. procedure TPSForce.AddProperties(const Result: Props.TProperties);
  260. begin
  261.   inherited;
  262.   if not Assigned(Result) then Exit;
  263.   AddVector3sProperty(Result, 'Force', Force);
  264. end;
  265. procedure TPSForce.SetProperties(Properties: Props.TProperties);
  266. begin
  267.   inherited;
  268.   SetVector3sProperty(Properties, 'Force', Force);
  269. end;
  270. procedure TPSForce.Process(const DeltaT: BaseClasses.Float);
  271. var i, Index: Integer; SystemAffector: TVector3s;
  272. begin
  273.   inherited;
  274.   for Index := 0 to TotalParticleSystems-1 do
  275.     if Assigned(ParticleSystem[Index]) and (isProcessing in ParticleSystem[Index].State) then begin
  276.     CalcPositionInSystem(Index, SystemAffector);
  277.     for i := ParticleSystem[Index].TotalParticles-1 downto 0 do with ParticleSystem[Index].SimulationData[i] do
  278.       if (Age >= AgeStart) and (Age < AgeEnd) and
  279.          (SqrMagnitude(SubVector3s(SystemAffector, ParticleSystem[Index].RenderData[i].Position)) < Sqr(Range)) then
  280.         AddVector3s(Velocity, Velocity, ScaleVector3s(Force, DeltaT));
  281.   end;
  282. end;
  283. { TSphericalEmitter }
  284. constructor TSphericalEmitter.Create(AManager: TItemsManager);
  285. begin
  286.   inherited;
  287.   PhiRange      := CreateSampledFloats(0, 2*pi, 2*pi);
  288.   ThetaRange    := CreateSampledFloats(0, pi, pi);
  289.   EmitMinRadius := CreateSampledFloats(0, 1, 0);
  290.   EmitMaxRadius := CreateSampledFloats(0, 1, 0);
  291.   MinSpeed   := CreateSampledFloats(0, 1, 0);
  292.   MaxSpeed   := CreateSampledFloats(0, 1, 0);
  293.   PhiRange.MaxY   := 2*Pi;
  294.   ThetaRange.MaxY := Pi;
  295.   EmitMinRadius.MaxY := 10;
  296.   EmitMaxRadius.MaxY := 10;
  297.   MinSpeed.MaxY   := 5;
  298.   MaxSpeed.MaxY   := 5;
  299. end;
  300. destructor TSphericalEmitter.Destroy;
  301. begin
  302.   FreeAndNil(PhiRange);
  303.   FreeAndNil(ThetaRange);
  304.   FreeAndNil(EmitMinRadius);
  305.   FreeAndNil(EmitMaxRadius);
  306.   FreeAndNil(MinSpeed);
  307.   FreeAndNil(MaxSpeed);
  308.   inherited;
  309. end;
  310. procedure TSphericalEmitter.AddProperties(const Result: Props.TProperties);
  311. begin
  312.   inherited;
  313.   if not Assigned(Result) then Exit;
  314.   PhiRange.AddAsProperty(Result, 'RangePhi');
  315.   ThetaRange.AddAsProperty(Result, 'RangeTheta');
  316.   EmitMinRadius.AddAsProperty(Result, 'RangeMin radius');
  317.   EmitMaxRadius.AddAsProperty(Result, 'RangeMax radius');
  318.   MinSpeed.AddAsProperty(Result, 'RangeMin speed');
  319.   MaxSpeed.AddAsProperty(Result, 'RangeMax speed');
  320. {  Result.Add('Emit min. radius', vtSingle, [], FloatToStr(EmitMinRadius), '');
  321.   Result.Add('Emit max. radius', vtSingle, [], FloatToStr(EmitMaxRadius), '');
  322.   Result.Add('Min. speed',       vtSingle, [], FloatToStr(MinSpeed),      '');
  323.   Result.Add('Max. speed',       vtSingle, [], FloatToStr(MaxSpeed),      '');
  324.   Result.Add('Phi range',        vtNat,    [],   IntToStr(PhiRange),      '');
  325.   Result.Add('Theta range',      vtNat,    [],   IntToStr(ThetaRange),    '');}
  326.   Result.Add('Tangent velocity', vtBoolean, [], OnOffStr[Tangent],        '');
  327. end;
  328. procedure TSphericalEmitter.SetProperties(Properties: Props.TProperties);
  329. begin
  330.   inherited;
  331.   PhiRange.SetFromProperty(Properties, 'RangePhi');
  332.   ThetaRange.SetFromProperty(Properties, 'RangeTheta');
  333.   EmitMinRadius.SetFromProperty(Properties, 'RangeMin radius');
  334.   EmitMaxRadius.SetFromProperty(Properties, 'RangeMax radius');
  335.   MinSpeed.SetFromProperty(Properties, 'RangeMin speed');
  336.   MaxSpeed.SetFromProperty(Properties, 'RangeMax speed');
  337. {  if Properties.Valid('Emit min. radius') then EmitMinRadius := StrToFloatDef(Properties['Emit min. radius'], 0);
  338.   if Properties.Valid('Emit max. radius') then EmitMaxRadius := StrToFloatDef(Properties['Emit max. radius'], 0);
  339.   if Properties.Valid('Min. speed')       then MinSpeed      := StrToFloatDef(Properties['Min. speed'],       0);
  340.   if Properties.Valid('Max. speed')       then MaxSpeed      := StrToFloatDef(Properties['Max. speed'],       0);
  341.   if Properties.Valid('Phi range')        then PhiRange      :=   StrToIntDef(Properties['Phi range'],        0);
  342.   if Properties.Valid('Theta range')      then ThetaRange    :=   StrToIntDef(Properties['Theta range'],      0);}
  343.   if Properties.Valid('Tangent velocity') then Tangent       := Properties.GetAsInteger('Tangent velocity') > 0;
  344. end;
  345. procedure TSphericalEmitter.InitParticles(Index, EmittedStart, EmittedEnd: Integer);
  346. var
  347.   i: Integer;
  348.   Vec: TVector3s;
  349.   CosPhi, SinTheta, CosTheta, SinPhi, Radius: Single; //IPhi, ITheta: Integer;
  350.   PhiRangeValue, ThetaRangeValue, MinRadiusValue, MaxRadiusValue, MinSpeedValue, MaxSpeedValue: Single;
  351. begin
  352.   inherited;
  353.   if PhiRange.Enabled      then PhiRangeValue   := PhiRange.Value[CycleK]      else PhiRangeValue   := 0;
  354.   if ThetaRange.Enabled    then ThetaRangeValue := ThetaRange.Value[CycleK]    else ThetaRangeValue := 0;
  355.   if EmitMinRadius.Enabled then MinRadiusValue  := EmitMinRadius.Value[CycleK] else MinRadiusValue  := 0;
  356.   if EmitMaxRadius.Enabled then MaxRadiusValue  := EmitMaxRadius.Value[CycleK] else MaxRadiusValue  := 0;
  357.   if MinSpeed.Enabled      then MinSpeedValue   := MinSpeed.Value[CycleK]      else MinSpeedValue   := 0;
  358.   if MaxSpeed.Enabled      then MaxSpeedValue   := MaxSpeed.Value[CycleK]      else MaxSpeedValue   := 0;
  359.   for i := EmittedEnd downto EmittedStart do begin       // ToDo: Make independent of data structures used
  360.     SinCos((1-2*Random)*PhiRangeValue,   SinPhi,   CosPhi);
  361.     SinCos((1-2*Random)*ThetaRangeValue, SinTheta, CosTheta);
  362.     Radius   := ( MinRadiusValue + Random*(MaxRadiusValue - MinRadiusValue) );
  363.     Vec := Transform3Vector3s(CutMatrix3s(Transform), Vec3s(CosPhi*SinTheta*Radius, SinPhi*SinTheta*Radius, CosTheta*Radius));
  364.     AddVector3s(ParticleSystem[Index].RenderData[i].Position, ParticleSystem[Index].RenderData[i].Position, Vec);
  365.     Radius   := MinSpeedValue + Random*(MaxSpeedValue - MinSpeedValue);
  366.     ParticleSystem[Index].SimulationData[i].Velocity := Transform3Vector3s(CutMatrix3s(Transform), Vec3s(CosPhi*SinTheta*Radius, SinPhi*SinTheta*Radius, CosTheta*Radius));
  367.   end;
  368. end;
  369. { TPSUniAffector }
  370. constructor TPSUniAffector.Create(AManager: TItemsManager);
  371. begin
  372.   inherited;
  373.   FColor          := TSampledGradient.Create;
  374.   FSizeModulator  := CreateSampledFloats(0, 10, 1);
  375.   FForceModulator := CreateSampledFloats(0, 1, 0);
  376.   FSpeedModulator := CreateSampledFloats(0, 1, 0);
  377.   FAngle          := CreateSampledFloats(-pi, pi, 0);
  378.   LifeTime        := 10;
  379. end;
  380. destructor TPSUniAffector.Destroy;
  381. begin
  382.   FreeAndNil(FColor);
  383.   FreeAndNil(FSizeModulator);
  384.   FreeAndNil(FForceModulator);
  385.   FreeAndNil(FSpeedModulator);
  386.   FreeAndNil(FAngle);
  387.   inherited;
  388. end;
  389. procedure TPSUniAffector.AddProperties(const Result: Props.TProperties);
  390. begin
  391.   inherited;
  392.   if not Assigned(Result) then Exit;
  393.   FColor.AddAsProperty(Result, 'Color');
  394.   FSizeModulator.AddAsProperty(Result, 'Size');
  395.   FForceModulator.AddAsProperty(Result, 'Weight');
  396.   FSpeedModulator.AddAsProperty(Result, 'Speed');
  397.   FAngle.AddAsProperty(Result, 'Angle');
  398.   Result.Add('LifeTime', vtSingle, [], FloatToStr(LifeTime), '');
  399.   AddVector3sProperty(Result, 'Force', Force);
  400. end;
  401. procedure TPSUniAffector.SetProperties(Properties: Props.TProperties);
  402. begin
  403.   inherited;
  404.   FColor.SetFromProperty(Properties, 'Color');
  405.   FSizeModulator.SetFromProperty(Properties, 'Size');
  406.   FForceModulator.SetFromProperty(Properties, 'Weight');
  407.   FSpeedModulator.SetFromProperty(Properties, 'Speed');
  408.   FAngle.SetFromProperty(Properties, 'Angle');
  409.   if Properties.Valid('LifeTime') then LifeTime := StrToFloatDef(Properties['LifeTime'], 0);
  410.   SetVector3sProperty(Properties, 'Force', Force);
  411. end;
  412. procedure TPSUniAffector.Process(const DeltaT: BaseClasses.Float);
  413. var
  414.   Index, i: Integer;
  415.   SystemAffector: TVector3s;
  416.   Modulator, AgeNormK: Single;
  417.   procedure CheckBBox(const Coord: TVector3s);
  418.   begin
  419.     with ParticleSystem[Index] do begin
  420.       BoundingBox.P1.X := MinS(BoundingBox.P1.X, Coord.X - MaxSize);
  421.       BoundingBox.P1.Y := MinS(BoundingBox.P1.Y, Coord.Y - MaxSize);
  422.       BoundingBox.P1.Z := MinS(BoundingBox.P1.Z, Coord.Z - MaxSize);
  423.       BoundingBox.P2.X := MaxS(BoundingBox.P2.X, Coord.X + MaxSize);
  424.       BoundingBox.P2.Y := MaxS(BoundingBox.P2.Y, Coord.Y + MaxSize);
  425.       BoundingBox.P2.Z := MaxS(BoundingBox.P2.Z, Coord.Z + MaxSize);
  426.     end;
  427.   end;
  428. begin
  429.   inherited;
  430.   AgeNormK := 1/(AgeEnd-AgeStart);
  431.   for Index := 0 to TotalParticleSystems-1 do
  432.     if Assigned(ParticleSystem[Index]) and (isProcessing in ParticleSystem[Index].State) then begin
  433.     ParticleSystem[Index].BoundingBox.P1 := GetVector3s( MaxFloatValue,  MaxFloatValue,  MaxFloatValue);
  434.     ParticleSystem[Index].BoundingBox.P2 := GetVector3s(-MaxFloatValue, -MaxFloatValue, -MaxFloatValue);
  435.     CalcPositionInSystem(Index, SystemAffector);
  436.     for i := ParticleSystem[Index].TotalParticles-1 downto 0 do with ParticleSystem[Index].SimulationData[i] do begin
  437.       Age := Age + DeltaT;
  438.       if Age > LifeTime then
  439.         ParticleSystem[Index].Kill(i)
  440.       else begin
  441.         if (Age >= AgeStart) and (Age < AgeEnd) then begin
  442.           Modulator := (Age - AgeStart) * AgeNormK;
  443.           with ParticleSystem[Index].RenderData[i] do begin
  444.             if FSizeModulator.Enabled then Size := FSizeModulator.Value[Modulator];
  445.             if FSpeedModulator.Enabled then
  446.               AddVector3s(Position, Position, ScaleVector3s(Velocity, DeltaT * FSpeedModulator.Value[Modulator]))
  447.             else
  448.               AddVector3s(Position, Position, ScaleVector3s(Velocity, DeltaT));
  449.             if ParticleSystem[Index].MaxSize < Size*0.5 then ParticleSystem[Index].MaxSize := Size*0.5;
  450.             CheckBBox(Position);
  451.             if FColor.Enabled then Color := FColor.Value[Modulator];
  452.             if FForceModulator.Enabled then
  453.               AddVector3s(Velocity, Velocity, ScaleVector3s(Force, DeltaT * FForceModulator.Value[Modulator]))
  454.             else
  455.               AddVector3s(Velocity, Velocity, ScaleVector3s(Force, DeltaT));
  456.             if FAngle.Enabled then
  457.               Angle := Abs(FAngle.Value[Modulator]) * Sign(Angle);
  458.           end;
  459.         end;
  460.       end;
  461.       
  462.     end;
  463.   end;
  464. end;
  465. { TSubEmitter }
  466. procedure TSubEmitter.ResolveLinks;
  467. var Item: TItem;
  468. begin
  469.   inherited;
  470.   ResolveLink('Source system', Item);
  471.   if Assigned(Item) then FSourceSystem := Item as TParticleSystem;
  472. end;
  473. procedure TSubEmitter.AddProperties(const Result: Props.TProperties);
  474. begin
  475.   inherited;
  476.   
  477.   if Assigned(Result) then begin
  478.     Result.Add('Source systemStarting age',    vtSingle,  [], FloatToStr(SrcAgeStart), '');
  479.     Result.Add('Source systemEnding age',      vtSingle,  [], FloatToStr(SrcAgeEnd),   '');
  480.     Result.Add('Source systemKill after emit', vtBoolean, [], OnOffStr[KillSource],   '');
  481.   end;
  482.   AddItemLink(Result, 'Source system', [], 'TParticleSystem');
  483. end;
  484. procedure TSubEmitter.SetProperties(Properties: Props.TProperties);
  485. begin
  486.   inherited;
  487.   if Properties.Valid('Source system') then SetLinkProperty('Source system', Properties['Source system']);
  488.   ResolveLinks;
  489.   if Properties.Valid('Source systemStarting age')    then SrcAgeStart := StrToFloatDef(Properties['Source systemStarting age'], 0);
  490.   if Properties.Valid('Source systemEnding age')      then SrcAgeEnd   := StrToFloatDef(Properties['Source systemEnding age'],   0);
  491.   if Properties.Valid('Source systemKill after emit') then KillSource  := Properties.GetAsInteger('Source systemKill after emit') > 0;
  492. end;
  493. {procedure TSubEmitter.Emit(Count: Single);
  494. var Index, i: Integer;
  495. begin
  496.   inherited;
  497.   for Index := 0 to TotalParticleSystems-1 do
  498.     if Assigned(ParticleSystem[Index]) and
  499.        not ParticleSystem[Index].DisableEmit and (isProcessing in ParticleSystem[Index].State) then begin
  500.     for i := ParticleSystem[Index].TotalParticles-LastEmit[Index].Count to ParticleSystem[Index].TotalParticles-1 do begin       // ToDo: Make independent of data structures used
  501.       SinCos((1-2*Random)*PhiRangeValue,   SinPhi,   CosPhi);
  502.       SinCos((1-2*Random)*ThetaRangeValue, SinTheta, CosTheta);
  503.       Size   := ( MinRadiusValue + Random*(MaxRadiusValue - MinRadiusValue) );
  504.       Vec.X := CosPhi*SinTheta*Radius;
  505.       Vec.Y := SinPhi*SinTheta*Radius;
  506.       Vec.Z := CosTheta*Radius;
  507.       AddVector3s(ParticleSystem[Index].RenderData[i].Position, ParticleSystem[Index].RenderData[i].Position, Vec);
  508.       Radius   := MinSpeedValue + Random*(MaxSpeedValue - MinSpeedValue);
  509.       ParticleSystem[Index].SimulationData[i].Velocity := GetVector3s(CosPhi*SinTheta*Radius, SinPhi*SinTheta*Radius, CosTheta*Radius);
  510.     end;
  511.   end;
  512. end;  }
  513. procedure TSubEmitter.InitParticles(Index, EmittedStart, EmittedEnd: Integer);
  514. const MaxSourceParticles = 1024;
  515. var
  516.   i: Integer;
  517.   SrcCoords: array[0..MaxSourceParticles-1] of TVector3s;
  518.   MaxCoordIndex, CoordIndex: Integer;
  519. begin
  520.   MaxCoordIndex := 0;
  521.   if Assigned(FSourceSystem) then
  522.     for i := MinI(MaxSourceParticles, MinI(ParticleSystem[Index].TotalParticles, FSourceSystem.TotalParticles))-1 downto 0 do
  523.       with FSourceSystem.SimulationData[i] do
  524.         if (Age >= SrcAgeStart) and (Age < SrcAgeEnd) then begin
  525.           SrcCoords[MaxCoordIndex] := FSourceSystem.RenderData[i].Position;
  526.           if KillSource then FSourceSystem.Kill(i);
  527.           Inc(MaxCoordIndex);
  528.         end;
  529.   Dec(MaxCoordIndex);
  530.   CoordIndex := 0;
  531.   if MaxCoordIndex >= 0 then begin
  532.     for i := EmittedEnd downto EmittedStart do with ParticleSystem[Index].SimulationData[i] do
  533.       if (Age >= AgeStart) and (Age < AgeEnd) then with ParticleSystem[Index].RenderData[i] do begin
  534.         Position := SrcCoords[CoordIndex];
  535.         CoordIndex := (CoordIndex + 1) * Ord(CoordIndex < MaxCoordIndex);
  536.       end;
  537.   end else begin
  538.     for i := EmittedEnd downto EmittedStart do ParticleSystem[Index].Kill(i);
  539.   end;
  540.   inherited;
  541. end;
  542. { TPSRandomAffector }
  543. constructor TPSRandomAffector.Create(AManager: TItemsManager);
  544. begin
  545.   inherited;
  546.   Color  := CreateSampledFloats(-5, 5, -5);
  547.   Size   := CreateSampledFloats(-2, 2, -2);
  548.   Coords := CreateSampledFloats(-2, 2, -2);
  549.   Speed  := CreateSampledFloats(-2, 2, -2);
  550.   PAge   := CreateSampledFloats(-3, 3, -3);
  551.   Angle  := CreateSampledFloats(-pi, pi, -pi);
  552. end;
  553. destructor TPSRandomAffector.Destroy;
  554. begin
  555.   FreeAndNil(Color);
  556.   FreeAndNil(Size);
  557.   FreeAndNil(Coords);
  558.   FreeAndNil(Speed);
  559.   FreeAndNil(PAge);
  560.   FreeAndNil(Angle);
  561.   inherited;
  562. end;
  563. procedure TPSRandomAffector.AddProperties(const Result: Props.TProperties);
  564. begin
  565.   inherited;
  566.   if not Assigned(Result) then Exit;
  567.   Color.AddAsProperty(Result,  'Colors');
  568.   Size.AddAsProperty(Result,   'Size');
  569.   Coords.AddAsProperty(Result, 'Position');
  570.   Speed.AddAsProperty(Result,  'Speed');
  571.   PAge.AddAsProperty(Result,   'Age');
  572.   Angle.AddAsProperty(Result,  'Angle');
  573. end;
  574. procedure TPSRandomAffector.SetProperties(Properties: Props.TProperties);
  575. begin
  576.   inherited;
  577.   Color.SetFromProperty(Properties,  'Colors');
  578.   Size.SetFromProperty(Properties,   'Size');
  579.   Coords.SetFromProperty(Properties, 'Position');
  580.   Speed.SetFromProperty(Properties,  'Speed');
  581.   PAge.SetFromProperty(Properties,   'Age');
  582.   Angle.SetFromProperty(Properties,  'Angle');
  583. end;
  584. procedure TPSRandomAffector.Process(const DeltaT: BaseClasses.Float);
  585. var
  586.   i, Index: Integer;
  587.   AgeNormK, Modulator, Temp: Single;
  588. begin
  589.   inherited;
  590.   AgeNormK := 1/(AgeEnd-AgeStart);
  591.   for Index := 0 to TotalParticleSystems-1 do
  592.     if Assigned(ParticleSystem[Index]) and (isProcessing in ParticleSystem[Index].State) then begin
  593.       for i := ParticleSystem[Index].TotalParticles-1 downto 0 do with ParticleSystem[Index].SimulationData[i] do
  594.         if (Age >= AgeStart) and (Age < AgeEnd) then begin
  595.           Modulator := (Age - AgeStart) * AgeNormK;
  596.           if Color.Enabled then with Color do begin
  597.             ParticleSystem[Index].RenderData[i].Color.A := ClampI(ParticleSystem[Index].RenderData[i].Color.A + Round((MinY + Random * Range) * (Value[Modulator] - MinY)), 0, 255);
  598.             ParticleSystem[Index].RenderData[i].Color.R := ClampI(ParticleSystem[Index].RenderData[i].Color.R + Round((MinY + Random * Range) * (Value[Modulator] - MinY)), 0, 255);
  599.             ParticleSystem[Index].RenderData[i].Color.G := ClampI(ParticleSystem[Index].RenderData[i].Color.G + Round((MinY + Random * Range) * (Value[Modulator] - MinY)), 0, 255);
  600.             ParticleSystem[Index].RenderData[i].Color.B := ClampI(ParticleSystem[Index].RenderData[i].Color.B + Round((MinY + Random * Range) * (Value[Modulator] - MinY)), 0, 255);
  601.           end;
  602.           if Size.Enabled then with Size do begin
  603.             Temp := (MinY + Random * Range) * (Value[Modulator] - MinY) * RangeInv;
  604.             ParticleSystem[Index].RenderData[i].Size := ParticleSystem[Index].RenderData[i].Size + Temp;
  605.           end;
  606.           if Coords.Enabled then with Coords do begin
  607.             AddVector3s(ParticleSystem[Index].RenderData[i].Position,
  608.                         ParticleSystem[Index].RenderData[i].Position,
  609.                         Vec3s((MinY + Random * Range) * (Value[Modulator] - MinY) * RangeInv,
  610.                               (MinY + Random * Range) * (Value[Modulator] - MinY) * RangeInv,
  611.                               (MinY + Random * Range) * (Value[Modulator] - MinY) * RangeInv));
  612.           end;
  613.           if Speed.Enabled then with Speed do begin
  614.             AddVector3s(ParticleSystem[Index].SimulationData[i].Velocity,
  615.                         ParticleSystem[Index].SimulationData[i].Velocity,
  616.                         Vec3s((MinY + Random * Range) * (Value[Modulator] - MinY) * RangeInv, (MinY + Random * Range) * (Value[Modulator] - MinY) * RangeInv, (MinY + Random * Range) * (Value[Modulator] - MinY) * RangeInv));
  617.           end;
  618.           if PAge.Enabled then with PAge do begin
  619.             Temp := (MinY + Random * Range) * (Value[Modulator] - MinY) * RangeInv;
  620.             ParticleSystem[Index].SimulationData[i].Age := ParticleSystem[Index].SimulationData[i].Age + Temp;
  621.           end;
  622.           if Angle.Enabled then with Angle do begin
  623.             Temp := (MinY + Random * Range) * (Value[Modulator] - MinY) * RangeInv;
  624.             ParticleSystem[Index].RenderData[i].Angle := ParticleSystem[Index].RenderData[i].Angle + Temp;
  625.           end;
  626.         end;
  627.     end;
  628. end;
  629. begin
  630.   GlobalClassList.Add('C2Affectors', GetUnitClassList);                     
  631. end.