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

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @Abstract(CAST II Engine particles 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.  Unit contains basic particle system classes
  6. *)
  7. {$Include GDefines.inc}
  8. {$Include C2Defines.inc}
  9. unit C2Particle;
  10. interface
  11. uses
  12.   SysUtils,
  13.   BaseTypes, BaseMsg, ItemMsg, Basics, BaseCont, Props, Base3D, BaseClasses,
  14.   C2Types, CAST2, C2Visual;
  15. const
  16.   ParticlesCapacityStep = 32;
  17. type
  18.   TPSRenderRecord = record
  19.     Position: TVector3s;
  20.     Size: Single;
  21.     Color: BaseTypes.TColor;
  22.     Angle: Single;
  23.     Sprite: Integer;
  24.     Temp: Single;
  25.   end;
  26.   TPSSimulationRecord = record
  27.     Velocity: TVector3s;
  28.     Age: Single;
  29.   end;
  30.   TPSRenderData     = array of TPSRenderRecord;
  31.   TPSSimulationData = array of TPSSimulationRecord;
  32.   TParticleSystem = class(TVisible)
  33.   private
  34.     FMaxCapacity,
  35.     FTotalParticles: Integer;
  36.     FRenderData: TPSRenderData;
  37.     FSimulationData: TPSSimulationData;
  38. //    FRotationSupport: Boolean;
  39.     FDirectionSupport: Boolean;
  40.     function Emit(Count: Integer): Integer;
  41.     procedure SetMaxCapacity(const Value: Integer);
  42.   public
  43.     // Size of biggest particle in the system. Calculated automatically.
  44.     MaxSize: Single;
  45.     { When FastKill is off particles are stored in order of emitting.
  46.       FSimulationData[i].Age >= FSimulationData[i+n].Age is true if starting age of particles is constant for the system.
  47.       With Fastkill mode on particle order is not defined but it's faster. }
  48.     FastKill,
  49.     // New particles are not emitted when DisableEmit is True
  50.     DisableEmit: Boolean;
  51.     constructor Create(AManager: TItemsManager); override;
  52.     destructor Destroy; override;
  53.     function GetTesselatorClass: CTesselator; override;
  54.     procedure Init; virtual;
  55.     function CalcSortValue(const Camera: TCamera): Single; override;
  56.     procedure SetMesh; override;
  57.     procedure AddProperties(const Result: Props.TProperties); override;
  58.     procedure SetProperties(Properties: Props.TProperties); override;
  59.     procedure Process(const DeltaT: BaseClasses.Float); override;
  60.     procedure Kill(Index: Integer);
  61.     procedure KillAll;
  62.     property TotalParticles: Integer read FTotalParticles;
  63.     // Maximum number of particles
  64.     property MaxCapacity: Integer read FMaxCapacity write SetMaxCapacity;
  65.     // Particles visualization data
  66.     property RenderData: TPSRenderData read FRenderData;
  67.     // Particles simulation data
  68.     property SimulationData: TPSSimulationData read FSimulationData;
  69.   end;
  70.   TPSAffector = class(CAST2.TProcessing)
  71.   private
  72.     FTotalParticleSystems: Integer;
  73.     procedure SetTotalParticleSystems(Value: Integer); virtual;
  74.   protected
  75.     ParticleSystem: array of TParticleSystem;
  76.     AgeStart, AgeEnd: Single;
  77.     procedure ResolveLinks; override;
  78.     // Called when a new particle system is resolved
  79.     procedure NewParticleSystem(Index: Integer); virtual;                                         
  80.     // Calculates affector position in particle system coordinates
  81.     procedure CalcPositionInSystem(Index: Integer; var Result: TVector3s);
  82.     // Transform the given vector into the particle system's frame
  83.     procedure TransformToSystem(Index: Integer; const Vector: TVector3s; out Result: TVector3s);  
  84.     property TotalParticleSystems: Integer read FTotalParticleSystems;
  85.   public
  86.     constructor Create(AManager: TItemsManager); override;
  87.     destructor Destroy; override;
  88.     class function IsAbstract: Boolean; override;
  89.     procedure AddProperties(const Result: Props.TProperties); override;
  90.     procedure SetProperties(Properties: Props.TProperties); override;
  91.     procedure SetupExternalVariables; virtual;
  92.   end;
  93.   TEmitter = class(TPSAffector)
  94.   private
  95.     ParticlesToEmit: Single;
  96.     procedure SetTotalParticleSystems(Value: Integer); override;
  97.   protected
  98.     FCurrentTime, CycleK: Single;
  99.     LastEmit: array of record
  100.       Count:    Integer;
  101.       Location: TVector3s;                      // Not guaranteed to be a real last emission location
  102.     end;
  103.     procedure NewParticleSystem(Index: Integer); override;
  104.     procedure ParticleSystemEmit(Index, EmitCount: Integer);
  105.   public
  106.     DefaultSize, UniformInterval, EmitRate, LifeTime, InitialAge: TSampledFloats;
  107.     EmitInLocal: Boolean;
  108.     CycleDuration: Single;
  109.     DefaultColor: TSampledGradient;
  110.     constructor Create(AManager: TItemsManager); override;
  111.     destructor Destroy; override;
  112.     procedure AddProperties(const Result: Props.TProperties); override;
  113.     procedure SetProperties(Properties: Props.TProperties); override;
  114.     procedure HandleMessage(const Msg: TMessage); override;
  115.     // Called immediately after emission of new particles. EmittedStart and EmittedEnd define range of the emitted particles.
  116.     procedure InitParticles(Index, EmittedStart, EmittedEnd: Integer); virtual;
  117.     procedure Emit(Count: Single);
  118.     procedure Process(const DeltaT: BaseClasses.Float); override;
  119.   end;
  120.   TParticleSystemMesh = class(TTesselator)
  121.     ParticleSystem: TParticleSystem;
  122.     constructor Create; override;
  123.   end;
  124.   T2DParticlesMesh = class(TParticleSystemMesh)
  125.   private
  126.     ParticlesVisible: Integer;
  127.   public
  128.     ReverseOrder: Boolean;
  129.     constructor Create; override;
  130. //    procedure Init;             // ?
  131.     function GetMaxVertices: Integer; override;
  132.     function GetMaxIndices: Integer; override;
  133.     function Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer; override;
  134.     function SetIndices(IBPTR: Pointer): Integer; override;
  135.   end;
  136.   T3DParticlesMesh = class(T2DParticlesMesh)
  137.   public
  138.     function Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer; override;
  139.   end;
  140.   T3DDirParticlesMesh = class(T2DParticlesMesh)
  141.   public
  142.     FMaxLength: Single;
  143.     procedure AddProperties(const Result: Props.TProperties; const PropNamePrefix: TNameString); override;
  144.     procedure SetProperties(Properties: Props.TProperties; const PropNamePrefix: TNameString); override;
  145.     function Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer; override;
  146.   end;
  147. {  T3DAngleParticlesMesh = class(T3DParticlesMesh)
  148.     function Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer; override;
  149.   end; }
  150.   T2DParticleSystem = class(TParticleSystem)
  151.   public
  152.   end;
  153.   T3DParticleSystem = class(TParticleSystem)
  154.   public
  155.     function GetTesselatorClass: CTesselator; override;
  156.   end;
  157.   
  158.   TPSSmoke = class(T3DParticleSystem)
  159.   end;
  160. implementation
  161. { TParticleSystem }
  162. function TParticleSystem.Emit(Count: Integer): Integer;
  163. // Returns the number of actually added particles
  164.   procedure UpdateMesh;
  165.   var PMesh: TParticleSystemMesh;
  166.   begin
  167.     PMesh := CurrentTesselator as TParticleSystemMesh;
  168.     with PMesh do begin
  169.       TotalVertices := 4;
  170.       TotalPrimitives := 2;
  171.       TotalIndices := TotalParticles*0;
  172.     end;
  173.     CurrentTesselator.Invalidate([tbVertex, tbIndex], True);
  174.   end;
  175. begin
  176.   Result := FTotalParticles;
  177.   FTotalParticles := MinI(FTotalParticles + Count, FMaxCapacity);
  178.   if Length(FRenderData) < FTotalParticles then begin
  179.     SetLength(FRenderData,     GetSteppedSize(FTotalParticles, ParticlesCapacityStep));
  180.     SetLength(FSimulationData, Length(FRenderData));
  181.   end;
  182.   Result := FTotalParticles - Result;
  183. //  UpdateMesh;
  184.   Assert(Result >= 0);
  185. end;
  186. procedure TParticleSystem.SetMaxCapacity(const Value: Integer);
  187. begin
  188.   FMaxCapacity := Value;
  189.   FTotalParticles := MinI(FTotalParticles, FMaxCapacity);
  190.   if Length(FRenderData) > FMaxCapacity then begin
  191.     SetLength(FRenderData,     FMaxCapacity);
  192.     SetLength(FSimulationData, FMaxCapacity);
  193.   end;
  194. end;
  195. constructor TParticleSystem.Create(AManager: TItemsManager);
  196. begin
  197.   inherited;
  198.   FastKill         := True;
  199.   DisableEmit      := False;
  200.   FMaxCapacity     := 2048;
  201.   FTotalParticles  := 0;
  202.   SetLength(FRenderData,     ParticlesCapacityStep);
  203.   SetLength(FSimulationData, ParticlesCapacityStep);
  204. end;
  205. destructor TParticleSystem.Destroy;
  206. begin
  207.   FRenderData     := nil;
  208.   FSimulationData := nil;
  209.   inherited;
  210. end;
  211. function TParticleSystem.GetTesselatorClass: CTesselator; begin Result := T2DParticlesMesh end;
  212. procedure TParticleSystem.Init;
  213. var i: Integer;
  214. begin
  215.   inherited;
  216.   for i := 0 to TotalChilds-1 do if Childs[i] is TParticleSystem then (Childs[i] as TParticleSystem).Init;
  217.   DisableEmit := False;
  218. end;
  219. function TParticleSystem.CalcSortValue(const Camera: TCamera): Single;
  220. var P: TVector3s;
  221. begin
  222.   P.X := (BoundingBox.P1.X + BoundingBox.P2.X) * 0.5;
  223.   P.Y := (BoundingBox.P1.Y + BoundingBox.P2.Y) * 0.5;
  224.   P.Z := (BoundingBox.P1.Z + BoundingBox.P2.Z) * 0.5;
  225.   SortValue := SqrMagnitude(SubVector3s(Camera.GetAbsLocation, ModelToWorld(P)));
  226.   Result    := SortValue;
  227. end;
  228. procedure TParticleSystem.SetMesh;
  229. begin
  230.   inherited;
  231. //  if CurrentTesselator is TParticleSystemMesh then begin
  232.   (CurrentTesselator as TParticleSystemMesh).ParticleSystem := Self;
  233. //  end;
  234. end;
  235. procedure TParticleSystem.AddProperties(const Result: Props.TProperties);
  236. begin
  237.   inherited;
  238.   if not Assigned(Result) then Exit;
  239.   Result.Add('Current',           vtNat,     [poReadonly], IntToStr(TotalParticles),   '');
  240.   Result.Add('Max',               vtNat,     [],           IntToStr(MaxCapacity),      '');
  241. //  Result.Add('Rotation support',  vtBoolean, [],           OnOffStr[FRotationSupport], '');
  242.   Result.Add('Direction support', vtBoolean, [],           OnOffStr[FDirectionSupport], '');
  243.   Result.Add('Fast killing',      vtBoolean, [],           OnOffStr[FastKill],         '');
  244. //  Result.Add('Reverse order',     vtBoolean, [],           OnOffStr[T2DParticlesMesh(CurrentTesselator).ReverseOrder], '');   //ToDo: eliminate mesh request
  245. end;
  246. procedure TParticleSystem.SetProperties(Properties: Props.TProperties);
  247. begin
  248.   if Properties.Valid('Direction support') then begin
  249.     FDirectionSupport := Properties.GetAsInteger('Direction support') > 0;
  250.     SetMesh();
  251.   end;  
  252.   inherited;
  253.   if Properties.Valid('Max')               then MaxCapacity := StrToIntDef(Properties['Max'], 0);
  254. //  if Properties.Valid('Rotation support')  then FRotationSupport  := Properties.GetAsInteger('Rotation support')  > 0;
  255.   
  256.   if Properties.Valid('Fast killing')      then FastKill          := Properties.GetAsInteger('Fast killing')      > 0;
  257. //  if Properties.Valid('Reverse order')     then T2DParticlesMesh(CurrentTesselator).ReverseOrder := Properties.GetAsInteger('Reverse order') > 0;
  258.   ResetProcessedTime;
  259. end;
  260. procedure TParticleSystem.Kill(Index: Integer);
  261. var i: Integer;
  262. begin
  263.   Assert((Index >= 0) and (Index < FTotalParticles));
  264.   if Assigned(CurrentTesselator) then CurrentTesselator.Invalidate([tbVertex, tbIndex], False);
  265.   Dec(FTotalParticles);
  266.   if Index = FTotalParticles then Exit;
  267.   if FastKill then begin
  268.     FRenderData[Index]     := FRenderData[FTotalParticles];
  269.     FSimulationData[Index] := FSimulationData[FTotalParticles];
  270.   end else for i := Index+1 to FTotalParticles do begin
  271.     FRenderData[i-1]     := FRenderData[i];
  272.     FSimulationData[i-1] := FSimulationData[i];
  273.   end;
  274. end;
  275. procedure TParticleSystem.KillAll;
  276. begin
  277.   if FTotalParticles = 0 then Exit;
  278.   if Assigned(CurrentTesselator) then CurrentTesselator.Invalidate([tbVertex, tbIndex], True);
  279.   FTotalParticles := 0;
  280. end;
  281. procedure TParticleSystem.Process(const DeltaT: BaseClasses.Float);
  282. begin
  283.   inherited;
  284.   MaxSize := 0;
  285. end;
  286. { TParticleSystemMesh }
  287. constructor TParticleSystemMesh.Create;
  288. begin
  289.   inherited;
  290.   TesselationStatus[tbVertex].TesselatorType := ttDynamic;
  291.   TesselationStatus[tbIndex].TesselatorType  := ttDynamic;
  292. end;
  293. { T2DParticlesMesh }
  294. constructor T2DParticlesMesh.Create;
  295. begin
  296.   inherited;
  297.   PrimitiveType := ptTRIANGLELIST;
  298. //  PrimitiveType := ptTRIANGLESTRIP;
  299. //  InitVertexFormat(GetVertexFormat(True, False, True, False, False, 0, [2]));
  300.   InitVertexFormat(GetVertexFormat(False, False, True, False, False, 0, [2]));
  301.   ReverseOrder := True;
  302. end;
  303. {procedure T2DParticlesMesh.Init;
  304. begin
  305.   if not Assigned(ParticleSystem) then Exit;
  306.   TotalVertices   := ParticleSystem.TotalParticles*4;
  307.   TotalPrimitives := ParticleSystem.TotalParticles*2;
  308.   TotalIndices    := ParticleSystem.TotalParticles*6;
  309.   Invalidate(True);
  310. end;}
  311. function T2DParticlesMesh.Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer;
  312. var i: Integer; Transformed: TVector4s; TRHW: Single;
  313. begin
  314.   Result := 0;
  315.   LastTotalVertices := 0;
  316.   if not Assigned(ParticleSystem) then Exit;
  317.   Transformed := GetVector4s(0, 0, ParticleSystem.Transform._43, 1); //Transform4Vector3s(RenderPars.TotalMatrix, Location);
  318.   if Transformed.W < 0 then Exit;
  319.   TRHW := 0.001;//1/Transformed.W;
  320.   Transformed.X := {RenderPars.ActualWidth shr 1 + RenderPars.ActualWidth shr 1*}Transformed.X;
  321.   Transformed.Y := {RenderPars.ActualHeight shr 1 - RenderPars.ActualHeight shr 1*}Transformed.Y;
  322. //  with RenderPars do Transformed.Z := 0*(ZFar/(ZFar-ZNear))*(1-ZNear/(Transformed.Z));
  323.   for i := 0 to ParticleSystem.TotalParticles-1 do with ParticleSystem.FRenderData[i] do begin
  324.     SetVertexDataCRHW(Transformed.X + (Position.X - Size*0.5), Transformed.Y - Position.Y - Size*0.5, Transformed.Z, TRHW, i*4, VBPTR);
  325.     SetVertexDataUV(0, 0,  i*4, VBPTR);
  326.     SetVertexDataD (Color, i*4, VBPTR);
  327.     SetVertexDataCRHW(Transformed.X + (Position.X + Size*0.5), Transformed.Y - Position.Y - Size*0.5, Transformed.Z, TRHW, i*4+1, VBPTR);
  328.     SetVertexDataUV(1, 0,  i*4+1, VBPTR);
  329.     SetVertexDataD (Color, i*4+1, VBPTR);
  330.     SetVertexDataCRHW(Transformed.X + (Position.X + Size*0.5), Transformed.Y - Position.Y + Size*0.5, Transformed.Z, TRHW, i*4+2, VBPTR);
  331.     SetVertexDataUV(1, 1,  i*4+2, VBPTR);
  332.     SetVertexDataD (Color, i*4+2, VBPTR);
  333.     SetVertexDataCRHW(Transformed.X + (Position.X - Size*0.5), Transformed.Y - Position.Y + Size*0.5, Transformed.Z, TRHW, i*4+3, VBPTR);
  334.     SetVertexDataUV(0, 1,  i*4+3, VBPTR);
  335.     SetVertexDataD (Color, i*4+3, VBPTR);
  336.   end;
  337.   TotalVertices     := ParticleSystem.TotalParticles*4; TotalPrimitives := ParticleSystem.TotalParticles*2;
  338.   IndexingVertices  := TotalVertices;
  339.   LastTotalVertices := TotalVertices;
  340.   ParticlesVisible  := ParticleSystem.TotalParticles;
  341.   Result            := TotalVertices;
  342.   
  343.   TesselationStatus[tbVertex].Status := tsMaxSizeChanged;
  344. end;
  345. function T2DParticlesMesh.SetIndices(IBPTR: Pointer): Integer;
  346. var i, Ind: Integer; IBuf: ^TWordBuffer;
  347. begin
  348.   IBuf := IBPTR;
  349.   for i := 0 to ParticlesVisible-1 do begin
  350.     if ReverseOrder then Ind := ParticlesVisible-i-1 else Ind := i;   // SetIndices must be called after Tesselate!
  351.     IBuf^[Ind*6+0] := i*4; IBuf^[Ind*6+1] := i*4+1; IBuf^[Ind*6+2] := i*4+2;
  352.     IBuf^[Ind*6+3] := i*4; IBuf^[Ind*6+4] := i*4+2; IBuf^[Ind*6+5] := i*4+3;
  353.   end;
  354.   TotalIndices := ParticlesVisible*6;
  355.   LastTotalIndices := TotalIndices;
  356.   TesselationStatus[tbIndex].Status := tsTesselated;
  357.   TesselationStatus[tbIndex].Status := tsMaxSizeChanged;
  358.   Result := TotalIndices;
  359. end;
  360. function T2DParticlesMesh.GetMaxVertices: Integer;
  361. begin
  362. //  Result := MaxI(1, TotalVertices);
  363.   Result := ParticleSystem.TotalParticles*4;
  364. end;
  365. function T2DParticlesMesh.GetMaxIndices: Integer;
  366. begin
  367. //  Result := TotalIndices;
  368.   Result := ParticleSystem.TotalParticles*6;
  369. end;
  370. { T3DParticlesMesh }
  371. function T3DParticlesMesh.Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer;
  372. var i: Integer; TCamRight, TCamUp, OTCamRight, OTCamUp: TVector3s; Rotation: TMatrix3s;
  373. begin
  374.   Result := 0;
  375.   LastTotalVertices := 0;
  376.   if not Assigned(ParticleSystem) then Exit;
  377. //  Matrix := MulMatrix4s(RenderPars.WorldMatrix, RenderPars.TotalMatrix);
  378.   ParticlesVisible := 0;
  379.   Rotation := CutMatrix3s(ParticleSystem.Transform);
  380.   OTCamRight := Transform3Vector3sTransp(Rotation, Params.Camera.RightVector);
  381.   OTCamUp    := Transform3Vector3sTransp(Rotation, Params.Camera.UpVector);
  382.   for i := 0 to ParticleSystem.TotalParticles-1 do with ParticleSystem.FRenderData[i] do begin
  383.         // Temporary implementation
  384.         OTCamRight := Transform3Vector3s(ZRotationMatrix3s(Angle), Vec3s(1, 0, 0));
  385.         OTCamUp    := Transform3Vector3s(ZRotationMatrix3s(Angle), Vec3s(0, 1, 0));
  386.         TCamRight := Transform3Vector3s(GetTransposedMatrix3s(CutMatrix3s(Params.Camera.ViewMatrix)), OTCamRight);
  387.         TCamUp    := Transform3Vector3s(GetTransposedMatrix3s(CutMatrix3s(Params.Camera.ViewMatrix)), OTCamUp);
  388.         TCamRight := Transform3Vector3sTransp(Rotation, TCamRight);
  389.         TCamUp    := Transform3Vector3sTransp(Rotation, TCamUp);
  390.     SetVertexDataC(Position.X + (-TCamRight.X - TCamUp.X) * Size,
  391.                    Position.Y + (-TCamRight.Y - TCamUp.Y) * Size,
  392.                    Position.Z + (-TCamRight.Z - TCamUp.Z) * Size,
  393.                    ParticlesVisible*4+3, VBPTR);
  394.     SetVertexDataUV(0, 0, ParticlesVisible*4+3, VBPTR);
  395.     SetVertexDataD(Color, ParticlesVisible*4+3, VBPTR);
  396.     SetVertexDataC(Position.X + (TCamRight.X - TCamUp.X) * Size,
  397.                    Position.Y + (TCamRight.Y - TCamUp.Y) * Size,
  398.                    Position.Z + (TCamRight.Z - TCamUp.Z) * Size,
  399.                    ParticlesVisible*4+2, VBPTR);
  400.     SetVertexDataUV(1, 0, ParticlesVisible*4+2, VBPTR);
  401.     SetVertexDataD(Color, ParticlesVisible*4+2, VBPTR);
  402.     SetVertexDataC(Position.X + (TCamRight.X + TCamUp.X) * Size,
  403.                    Position.Y + (TCamRight.Y + TCamUp.Y) * Size,
  404.                    Position.Z + (TCamRight.Z + TCamUp.Z) * Size,
  405.                    ParticlesVisible*4+1, VBPTR);
  406.     SetVertexDataUV(1, 1, ParticlesVisible*4+1, VBPTR);
  407.     SetVertexDataD(Color, ParticlesVisible*4+1, VBPTR);
  408.     SetVertexDataC(Position.X + (-TCamRight.X + TCamUp.X) * Size,
  409.                    Position.Y + (-TCamRight.Y + TCamUp.Y) * Size,
  410.                    Position.Z + (-TCamRight.Z + TCamUp.Z) * Size,
  411.                    ParticlesVisible*4, VBPTR);
  412.     SetVertexDataUV(0, 1, ParticlesVisible*4, VBPTR);
  413.     SetVertexDataD(Color, ParticlesVisible*4, VBPTR);
  414.     Inc(ParticlesVisible);
  415.   end;
  416.   TotalVertices     := ParticlesVisible*4;
  417.   TotalPrimitives   := ParticlesVisible*2;
  418.   Result            := TotalVertices;
  419.   IndexingVertices  := TotalVertices;
  420.   LastTotalVertices := TotalVertices;
  421.   TesselationStatus[tbVertex].Status := tsMaxSizeChanged;
  422. end;
  423. { T3DDirParticlesMesh }
  424. procedure T3DDirParticlesMesh.AddProperties(const Result: TProperties; const PropNamePrefix: TNameString);
  425. begin
  426.   inherited;
  427.   Result.Add(PropNamePrefix + 'Max length', vtSingle, [], FloatToStr(FMaxLength), '1-20');
  428. end;
  429. procedure T3DDirParticlesMesh.SetProperties(Properties: TProperties; const PropNamePrefix: TNameString);
  430. begin
  431.   inherited;
  432.   if Properties.Valid(PropNamePrefix + 'Max length') then FMaxLength := StrToFloatDef(Properties[PropNamePrefix + 'Max length'], 1);
  433. end;
  434. function T3DDirParticlesMesh.Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer;
  435. var
  436.   i: Integer;
  437.   Trans1, Trans2: TVector4s;
  438.   V, N, Cam: TVector3s;
  439.   l: Single;
  440.   Point1, Point2: TVector4s;
  441. begin
  442.   Result := 0;
  443.   LastTotalVertices := 0;
  444.   if not Assigned(ParticleSystem) then Exit;
  445.   ParticlesVisible := 0;
  446.   for i := 0 to ParticleSystem.TotalParticles-1 do with ParticleSystem.FRenderData[i] do begin
  447.     Cam := Params.Camera.GetAbsLocation;
  448.     l := SqrMagnitude(ParticleSystem.FSimulationData[i].Velocity);
  449.     if l > Sqr(FMaxLength) then l := FMaxLength*InvSqrt(l) else l := 1;
  450. //    Point1 := ExpandVector3s(Position);
  451.     Point1 := ExpandVector3s(AddVector3s(Position, ScaleVector3s(ParticleSystem.FSimulationData[i].Velocity, -l*0.5)));
  452.     Point2 := ExpandVector3s(AddVector3s(Position, ScaleVector3s(ParticleSystem.FSimulationData[i].Velocity,  l*0.5)));
  453.     Trans1 := Transform4Vector4s(Params.ModelMatrix, Point1);
  454.     Trans2 := Transform4Vector4s(Params.ModelMatrix, Point2);
  455.     N := SubVector4s(Trans2, Trans1).XYZ;                                   // Line vector in world
  456.     V := GetVector3s(- Trans1.X + Cam.X, - Trans1.Y + Cam.Y, - Trans1.Z + Cam.Z);    // From Point1 to camera
  457.     N := CrossProductVector3s(V, N);
  458.     l := SqrMagnitude(N);
  459. //    N :=
  460.     N := Transform3Vector3s(InvertMatrix3s(CutMatrix3s(Params.ModelMatrix)), N);
  461.     l := InvSqrt(l);
  462.     SetVertexDataC(Point1.X - N.X * l * Size, Point1.Y - N.Y * l * Size, Point1.Z - N.Z * l * Size, ParticlesVisible*4+0, VBPtr);
  463.     SetVertexDataD(Color, ParticlesVisible*4+0, VBPtr);
  464.     SetVertexDataUV(0, 0, ParticlesVisible*4+0, VBPtr);
  465.     SetVertexDataC(Point2.X - N.X * l * Size, Point2.Y - N.Y * l * Size, Point2.Z - N.Z * l * Size, ParticlesVisible*4+1, VBPtr);
  466.     SetVertexDataD(Color, ParticlesVisible*4+1, VBPtr);
  467.     SetVertexDataUV(1, 0, ParticlesVisible*4+1, VBPtr);
  468.     SetVertexDataC(Point2.X + N.X * l * Size, Point2.Y + N.Y * l * Size, Point2.Z + N.Z * l * Size, ParticlesVisible*4+2, VBPtr);
  469.     SetVertexDataD(Color, ParticlesVisible*4+2, VBPtr);
  470.     SetVertexDataUV(1, 1, ParticlesVisible*4+2, VBPtr);
  471.     SetVertexDataC(Point1.X + N.X * l * Size, Point1.Y + N.Y * l * Size, Point1.Z + N.Z * l * Size, ParticlesVisible*4+3, VBPtr);
  472.     SetVertexDataD(Color, ParticlesVisible*4+3, VBPtr);
  473.     SetVertexDataUV(0, 1, ParticlesVisible*4+3, VBPtr);
  474.     Inc(ParticlesVisible);
  475.   end;
  476.   TotalVertices     := ParticlesVisible*4;
  477.   TotalPrimitives   := ParticlesVisible*2;
  478.   Result            := TotalVertices;
  479.   IndexingVertices  := TotalVertices;
  480.   LastTotalVertices := TotalVertices;
  481.   TesselationStatus[tbVertex].Status := tsMaxSizeChanged;
  482. end;
  483. { T2DParticleSystem }
  484. { T3DParticleSystem }
  485. function T3DParticleSystem.GetTesselatorClass: CTesselator;
  486. begin
  487.   if FDirectionSupport then
  488.     Result := T3DDirParticlesMesh
  489.   else
  490.     Result := T3DParticlesMesh
  491. end;
  492. { TPSAffector }
  493. procedure TPSAffector.NewParticleSystem(Index: Integer);
  494. begin
  495. end;
  496. procedure TPSAffector.SetTotalParticleSystems(Value: Integer);
  497. begin
  498.   FTotalParticleSystems := Value;
  499.   if Length(ParticleSystem) < FTotalParticleSystems then
  500.     SetLength(ParticleSystem, FTotalParticleSystems);
  501.   BuildItemLinks;
  502. end;
  503. destructor TPSAffector.Destroy;
  504. begin
  505.   SetLength(ParticleSystem, 0);
  506.   inherited;
  507. end;
  508. class function TPSAffector.IsAbstract: Boolean;
  509. begin
  510.   Result := Self = TPSAffector;
  511. end;
  512. procedure TPSAffector.ResolveLinks;
  513. var i: Integer; Item: TItem;
  514. begin
  515.   inherited;
  516.   for i := 0 to FTotalParticleSystems-1 do begin
  517.     ResolveLink(Format('System #%D', [i]), Item);
  518.     if Assigned(Item) then begin
  519.       ParticleSystem[i] := Item as TParticleSystem;
  520.       NewParticleSystem(i);
  521.     end;
  522.   end;
  523. end;
  524. procedure TPSAffector.CalcPositionInSystem(Index: Integer; var Result: TVector3s);
  525. begin   
  526.   Assert((Index >= 0) and (Index < FTotalParticleSystems) and Assigned(ParticleSystem[Index]), ClassName + '.CalcPositionInSystem: Invalid particle system');
  527.   SubVector3s(Result, GetAbsLocation, ParticleSystem[Index].GetAbsLocation);
  528.   Result := Transform3Vector3sTransp(CutMatrix3s(ParticleSystem[Index].Transform), Result);
  529. end;
  530. procedure TPSAffector.TransformToSystem(Index: Integer; const Vector: TVector3s; out Result: TVector3s);
  531. begin
  532.   Assert((Index >= 0) and (Index < FTotalParticleSystems) and Assigned(ParticleSystem[Index]), ClassName + '.CalcPositionInSystem: Invalid particle system');
  533.   Transform4Vector33s(Result, MulMatrix4s(Transform, InvertRotTransMatrix(ParticleSystem[Index].Transform)), Vector);
  534. end;
  535. constructor TPSAffector.Create(AManager: TItemsManager);
  536. begin
  537.   inherited;
  538.   AgeEnd := MaxFloatValue;
  539. end;
  540. procedure TPSAffector.AddProperties(const Result: Props.TProperties);
  541. var i: Integer;
  542. begin
  543.   inherited;
  544.   if Assigned(Result) then begin
  545.     Result.Add('Systems affected', vtInt,    [], IntToStr(FTotalParticleSystems), '');
  546.     Result.Add('Starting age',     vtSingle, [], FloatToStr(AgeStart),            '');
  547.     Result.Add('Ending age',       vtSingle, [], FloatToStr(AgeEnd),              '');
  548.   end;
  549.   for i := 0 to FTotalParticleSystems-1 do
  550.     AddItemLink(Result, Format('System #%D', [i]), [], 'TParticleSystem');
  551. end;
  552. procedure TPSAffector.SetProperties(Properties: Props.TProperties);
  553. var i: Integer;
  554. begin
  555.   inherited;
  556.   if Properties.Valid('Systems affected') then SetTotalParticleSystems(StrToIntDef(Properties['Systems affected'], 0));
  557.   for i := 0 to FTotalParticleSystems-1 do if Properties.Valid(Format('System #%D', [i])) then
  558.     SetLinkProperty(Format('System #%D', [i]), Properties[Format('System #%D', [i])]);
  559.   ResolveLinks;
  560.   if Properties.Valid('Starting age') then AgeStart := StrToFloatDef(Properties['Starting age'], 0);
  561.   if Properties.Valid('Ending age')   then AgeEnd   := StrToFloatDef(Properties['Ending age'],   0);
  562. end;
  563. procedure TPSAffector.SetupExternalVariables;
  564. begin
  565.   inherited;
  566. {$IFDEF SCRIPTING}
  567.   World.Compiler.ImportExternalVar('DefaultColor',    'LONGINT',    @DefaultColor);
  568.   World.Compiler.ImportExternalVar('DefaultRadius',   'SINGLE',     @DefaultRadius);
  569.   World.Compiler.ImportExternalVar('TotalParticles',  'LONGINT',    @T3DParticlesMesh(CurrentTesselator).TotalParticles);
  570.   World.Compiler.ImportExternalVar('Particles',       'TParticles', @T3DParticlesMesh(CurrentTesselator).Particles[0]);
  571.   World.Compiler.ImportExternalVar('ParticlesToEmit', 'LONGINT',    @ParticlesToEmit);
  572. {$ENDIF}
  573. end;
  574. { TEmitter }
  575. procedure TEmitter.SetTotalParticleSystems(Value: Integer);
  576. begin
  577.   inherited;
  578.   if Length(LastEmit) < FTotalParticleSystems then SetLength(LastEmit, FTotalParticleSystems);
  579. end;
  580. procedure TEmitter.NewParticleSystem(Index: Integer);
  581. begin
  582.   inherited;
  583.   LastEmit[Index].Count := 0;
  584.   CalcPositionInSystem(Index, LastEmit[Index].Location);
  585. end;
  586. procedure TEmitter.ParticleSystemEmit(Index, EmitCount: Integer);
  587. begin
  588.   if not Assigned(ParticleSystem[Index]) or ParticleSystem[Index].DisableEmit or
  589.      not (isProcessing in ParticleSystem[Index].State) then Exit;
  590. //  {$IFDEF DEBUGMODE} Assert(LastEmit[Index].Count = 0, ClassName + '.ParticleSystemEmit: Duplicate ParticleSystemEmit() call'); {$ENDIF}
  591.   LastEmit[Index].Count := 0;
  592.   if EmitCount > 0 then LastEmit[Index].Count := ParticleSystem[Index].Emit(EmitCount);
  593. end;
  594. constructor TEmitter.Create(AManager: TItemsManager);
  595. begin
  596.   inherited;
  597.   DefaultColor := TSampledGradient.Create;
  598.   DefaultSize     := TSampledFloats.Create;
  599.   UniformInterval := TSampledFloats.Create;
  600.   EmitRate        := TSampledFloats.Create;
  601.   LifeTime        := TSampledFloats.Create;
  602.   InitialAge      := TSampledFloats.Create;
  603.   DefaultSize.MaxY := 1000;
  604.   EmitRate.MaxY    := 1000;
  605.   LifeTime.MaxY    := 100;
  606.   InitialAge.MaxY  := 60;
  607.   DefaultSize.DefaultValue := 1;
  608.   DefaultSize.Reset();
  609.   UniformInterval.DefaultValue := 0.1;
  610.   UniformInterval.Reset();
  611.   EmitRate.DefaultValue := 10;
  612.   EmitRate.Reset();
  613.   LifeTime.DefaultValue := 10;
  614.   LifeTime.Reset();
  615.   InitialAge.DefaultValue := 0;
  616.   InitialAge.Reset();
  617.   CycleDuration := 2;
  618. end;
  619. destructor TEmitter.Destroy;
  620. begin
  621.   SetLength(LastEmit, 0);
  622.   FreeAndNil(DefaultColor);
  623.   FreeAndNil(DefaultSize);
  624.   FreeAndNil(UniformInterval);
  625.   FreeAndNil(EmitRate);
  626.   FreeAndNil(LifeTime);
  627.   FreeAndNil(InitialAge);
  628.   inherited;
  629. end;
  630. procedure TEmitter.AddProperties(const Result: Props.TProperties);
  631. begin
  632.   inherited;
  633.   if not Assigned(Result) then Exit;
  634. //  AddColorProperty(Result, 'DefaultColor', DefaultColor);
  635.   Result.Add('Cycle duration',    vtSingle, [],       FloatToStr(CycleDuration),   '');
  636. //  Result.Add('DefaultSize',      vtSingle, [],       FloatToStr(DefaultRadius),   '');
  637. //  Result.Add('DefaultLifetime',  vtNat,    [],       IntToStr(DefaultLifetime),   '');
  638.   Result.Add('Local coordinates', vtBoolean, [], OnOffStr[EmitInLocal], '');
  639.   Result.Add('Instant emit',      vtNat,     [], '1',                       '');
  640. //  Result.Add('Rate',              vtSingle,  [], FloatToStr(Rate),          '');
  641. //  Result.Add('Uniform',           vtBoolean, [], OnOffStr[UniformEmit],     '');
  642.   DefaultColor.AddAsProperty(Result, 'DefaultColor');
  643.   EmitRate.       AddAsProperty(Result, 'Rate');
  644.   DefaultSize.    AddAsProperty(Result, 'DefaultSize');
  645. //  LifeTime.       AddAsProperty(Result, 'DefaultLifetime');
  646.   InitialAge.     AddAsProperty(Result, 'Initial age');
  647.   UniformInterval.AddAsProperty(Result, 'UniformInterval');
  648. end;
  649. procedure TEmitter.SetProperties(Properties: Props.TProperties);
  650. begin
  651.   inherited;
  652.   if Properties.Valid('Cycle duration') then CycleDuration := StrToFloatDef(Properties['Cycle duration'], 0);
  653. //  SetColorProperty(Properties, 'DefaultColor', DefaultColor);
  654. //  if Properties.Valid('')      then DefaultRadius    := StrToFloatDef(Properties['DefaultSize'],   0);
  655. //  if Properties.Valid('DefaultLifetime')  then DefaultLifetime  := StrToIntDef(Properties['DefaultLifetime'], 0);
  656.   if Properties.Valid('Local coordinates') then EmitInLocal := Properties.GetAsInteger('Local coordinates') > 0;
  657. //  if Properties.Valid('Rate')              then Rate          := StrToFloatDef(Properties['Rate'], 0);
  658. //  if Properties.Valid('Uniform')           then UniformEmit   := Properties.GetAsInteger('Uniform') > 0;
  659.   if Properties.Valid('Instant emit')      then Emit(StrToIntDef(Properties['Instant emit'], 0));
  660.   DefaultColor.SetFromProperty(Properties, 'DefaultColor');
  661.   EmitRate.SetFromProperty(Properties, 'Rate');
  662.   DefaultSize.SetFromProperty(Properties, 'DefaultSize');
  663. //  LifeTime.SetFromProperty(Properties, 'DefaultLifetime');
  664.   InitialAge.SetFromProperty(Properties, 'Initial age');
  665.   UniformInterval.SetFromProperty(Properties, 'UniformInterval');
  666. end;
  667. procedure TEmitter.HandleMessage(const Msg: TMessage);
  668. begin
  669.   inherited;
  670.   if Msg.ClassType = TSyncTimeMsg then
  671.     FCurrentTime := 0;
  672. end;
  673. procedure TEmitter.InitParticles(Index, EmittedStart, EmittedEnd: Integer);
  674. var
  675.   i: Integer;
  676.   DefSize: Single;
  677.   DefColor: TColor;
  678. begin
  679.   if DefaultSize.Enabled then
  680.     DefSize := DefaultSize.Value[CycleK]
  681.   else
  682.     DefSize := DefaultSize.DefaultValue;
  683.   if DefaultColor.Enabled then
  684.     DefColor := DefaultColor.Value[CycleK]
  685.   else
  686.     DefColor.C := $80808080;
  687.   for i := EmittedEnd downto EmittedStart do begin       // ToDo: Make independent of data structures used
  688.     with ParticleSystem[Index].FRenderData[i] do begin
  689. //      Position := EmitterInSystem;
  690.       Size   := DefSize;
  691.       Color    := DefColor;
  692.       Angle    := 0;
  693.       Sprite   := 0;
  694.     end;
  695.     if InitialAge.Enabled then ParticleSystem[Index].FSimulationData[i].Age := InitialAge.Value[CycleK];
  696.   end;
  697. end;
  698. procedure TEmitter.Emit(Count: Single);
  699. var
  700.   i, Index, EmitCount: Integer;
  701.   EmitterInSystem, UniformPath: TVector3s;
  702.   UniformEmitCount, K, KIncr, InvUniformRadius: Single;
  703.   UniformEmit: Boolean;
  704. begin
  705.   ParticlesToEmit := ParticlesToEmit + Count;
  706.   InvUniformRadius := UniformInterval.Value[CycleK];
  707.   if Abs(InvUniformRadius) > epsilon then InvUniformRadius := 1/InvUniformRadius else InvUniformRadius := MaxFloatValue;
  708.   UniformEmit := UniformInterval.Enabled;
  709.   for Index := 0 to TotalParticleSystems-1 do
  710.     if Assigned(ParticleSystem[Index]) and //(ParticleSystem[Index].FTotalParticles > 0) and
  711.        not ParticleSystem[Index].DisableEmit and (isProcessing in ParticleSystem[Index].State) then begin
  712.       if EmitInLocal then EmitterInSystem := GetVector3s(0, 0, 0) else CalcPositionInSystem(Index, EmitterInSystem);
  713.       if UniformEmit then begin
  714.         UniformEmitCount := Sqrt(SqrMagnitude(SubVector3s(EmitterInSystem, LastEmit[Index].Location))) * InvUniformRadius;
  715.         EmitCount := Trunc(MinS(ParticleSystem[Index].MaxCapacity, MaxS(ParticlesToEmit, UniformEmitCount)));
  716.         SubVector3s(UniformPath, EmitterInSystem, LastEmit[Index].Location);
  717.         if UniformEmitCount < 1 then
  718.           LastEmit[Index].Location := SubVector3s(LastEmit[Index].Location, SubVector3s(EmitterInSystem, LastEmit[Index].Location))
  719.         else
  720.           LastEmit[Index].Location := EmitterInSystem;
  721.       end else EmitCount := Trunc(ParticlesToEmit);
  722.       ParticleSystemEmit(Index, EmitCount);
  723.       if LastEmit[Index].Count > 0 then begin
  724.         K := 0;
  725.         KIncr := 1 / LastEmit[Index].Count;
  726.         for i := ParticleSystem[Index].TotalParticles-1 downto ParticleSystem[Index].TotalParticles-LastEmit[Index].Count do begin       // ToDo: Make independent of data structures used
  727.           with ParticleSystem[Index].FRenderData[i] do begin
  728.             Position := EmitterInSystem;
  729.             Size   := 0;
  730.             Color.C  := 0;
  731.             Angle    := 0;
  732.             Sprite   := 0;
  733.             if UniformEmit then SubVector3s(Position, Position, ScaleVector3s(UniformPath, K));
  734.             K := K + KIncr;
  735.           end;
  736.           ParticleSystem[Index].FSimulationData[i].Age := 0;
  737.         end;
  738.         InitParticles(Index, ParticleSystem[Index].TotalParticles-LastEmit[Index].Count, ParticleSystem[Index].TotalParticles-1);
  739.       end;
  740. //      if LastEmit[Index].Count > 0 then
  741. //        FillChar(ParticleSystem[Index].FSimulationData[ParticleSystem[Index].TotalParticles-LastEmit[Index].Count], LastEmit[Index].Count * SizeOf(TPSSimulationRecord), 0);
  742.   end;
  743.   ParticlesToEmit := ParticlesToEmit - Trunc(ParticlesToEmit);
  744. end;
  745. procedure TEmitter.Process(const DeltaT: BaseClasses.Float);
  746. {$IFDEF DEBUGMODE} var Index: Integer; {$ENDIF}
  747. begin
  748.   inherited;
  749.   FCurrentTime := FCurrentTime + DeltaT;
  750.   if FCurrentTime > CycleDuration then
  751.     FCurrentTime := FCurrentTime - CycleDuration;
  752.   if CycleDuration > epsilon then
  753.     CycleK := FCurrentTime / CycleDuration
  754.   else
  755.     CycleK := 0;
  756.   if EmitRate.Enabled then Emit(EmitRate.Value[CycleK] * DeltaT);   // Emit ParticlesToEmit number of particles
  757.   {$IFDEF DEBUGMODE}                                                // Zero out last emit counter to avoid emit duplication errors
  758.   for Index := 0 to TotalParticleSystems-1 do LastEmit[Index].Count := 0;
  759.   {$ENDIF}
  760. end;
  761. end.