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

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @Abstract(CAST II Engine advanced particle 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: 21.01.2007 <br>
  6.  Unit contains advanced particle system classes
  7. *)
  8. {$Include GDefines.inc}
  9. {$Include C2Defines.inc}
  10. unit C2ParticleAdv;
  11. interface
  12. uses
  13.   SysUtils,
  14.   BaseTypes, Basics, Base3D, Props,
  15.   BaseClasses, C2Types, CAST2, C2Visual, C2Particle;
  16. type
  17.   TCordTesselator = class(TParticleSystemMesh)
  18.   private
  19.     ParticlesVisible: Integer;
  20.   public
  21.     UVScale: Single;
  22.     TryToCorrect: Boolean;
  23.     constructor Create; override;
  24.     function GetMaxVertices: Integer; override;
  25.     function Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer; override;
  26.   end;
  27.   TParticleCord = class(TParticleSystem)
  28.     function GetTesselatorClass: CTesselator; override;
  29.     procedure AddProperties(const Result: Props.TProperties); override;
  30.     procedure SetProperties(Properties: Props.TProperties); override;
  31.   end;
  32.   TRibbonTesselator = class(TParticleSystemMesh)
  33.   private
  34.     ParticlesVisible: Integer;
  35.     Crosses: array of TVector3s;
  36.   public
  37.     UVScale: Single;
  38.     constructor Create; override;
  39.     destructor Destroy; override;
  40.     function GetMaxVertices: Integer; override;
  41.     function Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer; override;
  42.   end;
  43.   TParticleRibbon = class(TParticleSystem)
  44.     function GetTesselatorClass: CTesselator; override;
  45.     procedure AddProperties(const Result: Props.TProperties); override;
  46.     procedure SetProperties(Properties: Props.TProperties); override;
  47.   end;
  48.   // Returns list of classes introduced by the unit
  49.   function GetUnitClassList: TClassArray;
  50. implementation
  51. function GetUnitClassList: TClassArray;
  52. begin
  53.   Result := GetClassList([TParticleCord, TParticleRibbon]);
  54. end;
  55. { TCordTesselator }
  56. constructor TCordTesselator.Create;
  57. begin
  58.   inherited;
  59.   PrimitiveType := ptTRIANGLESTRIP;
  60.   InitVertexFormat(GetVertexFormat(False, False, True, False, False, 0, [2]));
  61.   UVScale := 0.001;
  62. end;
  63. function TCordTesselator.GetMaxVertices: Integer;
  64. begin
  65.   Result := ParticleSystem.TotalParticles*2;
  66. end;
  67. function TCordTesselator.Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer;
  68. var
  69.   i, LastI: Integer;
  70.   SqDist, InvDist, CurU: Single;
  71.   CamZInModel, Cross, OldCross, P1, P2, OldP1, OldP2: TVector3s;
  72. function GetCross(Index: Integer): TVector3s;
  73. begin
  74.   if Index < ParticleSystem.TotalParticles-1 then Inc(Index);
  75.   Result := CrossProductVector3s(SubVector3s(ParticleSystem.RenderData[Index].Position, ParticleSystem.RenderData[LastI].Position), CamZInModel);
  76. end;
  77. begin
  78.   TotalPrimitives   := 0;
  79.   Result := 0;
  80.   LastTotalVertices := Result;
  81.   if not Assigned(ParticleSystem) or (ParticleSystem.TotalParticles < 2) then Exit;
  82.   CamZInModel := Transform3Vector3sTransp(CutMatrix3s(ParticleSystem.Transform), Params.Camera.ForwardVector);
  83.   ParticlesVisible := 0;
  84.   CurU := 0;
  85.   LastI := 0;
  86.   OldCross := GetCross(1);
  87.   for i := 0 to ParticleSystem.TotalParticles-1 do begin
  88.     if i > 0 then
  89.       Cross := GetCross(i) else
  90.         Cross := GetCross(i+1);
  91. //    if i < ParticleSystem.TotalParticles-1 then Cross := GetCross(i);
  92. {    if (i > 0) and (i < ParticleSystem.TotalParticles-2) then begin
  93.       Cross := GetCross(i-1);
  94.       Cross2 := GetCross(i+1);
  95.       Cross := ScaleVector3s(AddVector3s(Cross, Cross2), 0.5);
  96.     end;}
  97.     with ParticleSystem.RenderData[i] do begin
  98.       SqDist := SqrMagnitude(Cross);
  99.       InvDist := 1/Sqrt(SqDist);
  100.       CurU := CurU + UVScale/InvDist;
  101.       if SqDist < {epsilon}Sqr(Size*0.5) then Continue;
  102.       ScaleVector3s(Cross, Cross, Size*InvDist);
  103.       P1 := AddVector3s(Position, Cross);
  104.       P2 := SubVector3s(Position, Cross);
  105.       if TryToCorrect and (i > 0) then begin
  106. //        if SqrMagnitude(SubVector3s(OldP1, P1)) < Sqr(Size*0.9) then P1 := OldP1;
  107. //        if SqrMagnitude(SubVector3s(OldP2, P2)) < Sqr(Size*0.9) then P2 := OldP2;
  108.         if not IsPointsSameSide(ParticleSystem.RenderData[LastI].Position, OldCross, P1, Position) then
  109.           P1 := OldP1 else
  110.             if not IsPointsSameSide(ParticleSystem.RenderData[LastI].Position, OldCross, P2, Position) then
  111.               P2 := OldP2;
  112. //        P1 := OldP1
  113.       end;
  114.       SetVertexDataC(P1,       ParticlesVisible*2, VBPTR);
  115.       SetVertexDataUV(0, CurU, ParticlesVisible*2, VBPTR);
  116.       SetVertexDataD(Color,    ParticlesVisible*2, VBPTR);
  117.       SetVertexDataC(P2,       ParticlesVisible*2+1, VBPTR);
  118.       SetVertexDataUV(1, CurU, ParticlesVisible*2+1, VBPTR);
  119.       SetVertexDataD(Color,    ParticlesVisible*2+1, VBPTR);
  120.     end;
  121.     Inc(ParticlesVisible);
  122.     OldP1 := P1;
  123.     OldP2 := P2;
  124.     OldCross := Cross;
  125.     LastI := i;
  126.   end;
  127. {  for i := 0 to ParticleSystem.TotalParticles-1 do begin
  128.     if i < ParticleSystem.TotalParticles-1 then
  129.       Cross := CrossProductVector3s(SubVector3s(ParticleSystem.RenderData[i+1].Position, ParticleSystem.RenderData[i].Position), CamZInModel);
  130.     SqDist := SqrMagnitude(Cross);
  131.     if SqDist < Sqr(ParticleSystem.RenderData[i].Size*0.1) then Continue;
  132.     InvDist := 1/Sqrt(SqDist);
  133.     ScaleVector3s(Cross, Cross, InvDist);
  134.     CurU := CurU + UScale/InvDist;
  135.     with ParticleSystem.RenderData[i] do begin
  136.       ScaleVector3s(Cross, Cross, Size * InvSqrt(SqrMagnitude(Cross)));
  137.       SetVertexDataC(AddVector3s(Position, Cross), ParticlesVisible*2, VBPTR);
  138.       SetVertexDataUV(1, CurU, ParticlesVisible*2, VBPTR);
  139.       SetVertexDataD(Color, ParticlesVisible*2, VBPTR);
  140.       SetVertexDataC(SubVector3s(Position, Cross), ParticlesVisible*2+1, VBPTR);
  141.       SetVertexDataUV(0, CurU, ParticlesVisible*2+1, VBPTR);
  142.       SetVertexDataD(Color, ParticlesVisible*2+1, VBPTR);
  143.     end;
  144.     Inc(ParticlesVisible);
  145.   end;}
  146.   TotalPrimitives   := ParticlesVisible*2 - 2;
  147.   Result            := ParticlesVisible*2;
  148.   TotalVertices     := Result;
  149.   LastTotalVertices := Result;
  150. end;
  151. { TParticleCord }
  152. function TParticleCord.GetTesselatorClass: CTesselator; begin Result := TCordTesselator end;
  153. procedure TParticleCord.AddProperties(const Result: Props.TProperties);
  154. var Mesh: TCordTesselator;
  155. begin
  156.   inherited;
  157.   if not Assigned(Result) then Exit;
  158.   if not (CurrentTesselator is TCordTesselator) then begin
  159.     Result.Add('Error', vtString, [poReadOnly], 'Tesselator is undefined', '');
  160.     Exit;
  161.   end;
  162.   Mesh := CurrentTesselator as TCordTesselator;
  163.   Result.Add('Texture scale', vtSingle,  [], FloatToStr(Mesh.UVScale), '');
  164.   Result.Add('Correct folds', vtBoolean, [], OnOffStr[Mesh.TryToCorrect], '');
  165. end;
  166. procedure TParticleCord.SetProperties(Properties: Props.TProperties);
  167. var Mesh: TCordTesselator;
  168. begin
  169.   inherited;
  170.   if not (CurrentTesselator is TCordTesselator) then Exit;
  171.   Mesh := CurrentTesselator as TCordTesselator;
  172.   if Properties.Valid('Texture scale') then Mesh.UVScale      := StrToFloatDef(Properties['Texture scale'], 0);
  173.   if Properties.Valid('Correct folds') then Mesh.TryToCorrect := Properties.GetAsInteger('Correct folds') > 0;
  174. end;
  175. { TParticleRibbon }
  176. function TParticleRibbon.GetTesselatorClass: CTesselator; begin Result := TRibbonTesselator end;
  177. procedure TParticleRibbon.AddProperties(const Result: Props.TProperties);
  178. var Mesh: TRibbonTesselator;
  179. begin
  180.   inherited;
  181.   if not Assigned(Result) then Exit;
  182.   if not (CurrentTesselator is TRibbonTesselator) then begin
  183.     Result.Add('Error', vtString, [poReadOnly], 'Tesselator is undefined', '');
  184.     Exit;
  185.   end;
  186.   Mesh := CurrentTesselator as TRibbonTesselator;
  187.   Result.Add('Texture scale', vtSingle,  [], FloatToStr(Mesh.UVScale), '');
  188. end;
  189. procedure TParticleRibbon.SetProperties(Properties: Props.TProperties);
  190. var Mesh: TRibbonTesselator;
  191. begin
  192.   inherited;
  193.   if not (CurrentTesselator is TRibbonTesselator) then Exit;
  194.   Mesh := CurrentTesselator as TRibbonTesselator;
  195.   if Properties.Valid('Texture scale') then Mesh.UVScale      := StrToFloatDef(Properties['Texture scale'], 0);
  196. end;
  197. { TRibbonTesselator }
  198. constructor TRibbonTesselator.Create;
  199. begin
  200.   inherited;
  201.   PrimitiveType := ptTRIANGLESTRIP;
  202.   InitVertexFormat(GetVertexFormat(False, True, True, False, False, 0, [2]));
  203.   UVScale := 0.001;
  204. end;
  205. destructor TRibbonTesselator.Destroy;
  206. begin
  207.   Crosses := nil;
  208.   inherited;
  209. end;
  210. function TRibbonTesselator.GetMaxVertices: Integer;
  211. begin
  212.   Result := ParticleSystem.TotalParticles*2;
  213. end;
  214. function TRibbonTesselator.Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer;
  215. function GetNormal(Index: Integer): TVector3s;
  216. var I2, I1: Integer;
  217. begin
  218.   if Index > 0 then I1 := Index-1 else I1 := 0;
  219.   if Index < ParticleSystem.TotalParticles-1 then I2 := Index+1 else I2 := ParticleSystem.TotalParticles-1;
  220.   CrossProductVector3s(Result, SubVector3s(ParticleSystem.RenderData[I2].Position, ParticleSystem.RenderData[I1].Position), Crosses[Index]);
  221. end;
  222. var
  223.   i, j, LastIndex: Integer;
  224.   CurNorm, OldNorm: TVector3s;
  225.   CurU, InvDist: Single;
  226. begin
  227.   TotalPrimitives := 0;
  228.   Result := 0;
  229.   LastTotalVertices := Result;
  230.   if not Assigned(ParticleSystem) or (ParticleSystem.TotalParticles < 2) then Exit;
  231.   if Length(Crosses) < ParticleSystem.TotalParticles then SetLength(Crosses, ParticleSystem.TotalParticles);
  232. // Crosses calculation
  233.   LastIndex := -1;
  234.   CrossProductVector3s(CurNorm, GetVector3s(0, 1, 0), SubVector3s(ParticleSystem.RenderData[1].Position, ParticleSystem.RenderData[0].Position));
  235.   if SqrMagnitude(CurNorm) < epsilon then CurNorm := GetVector3s(1, 0, 0);
  236.   Crosses[0] := CurNorm;
  237.   for i := 1 to ParticleSystem.TotalParticles-2 do begin
  238.     CrossProductVector3s(OldNorm, SubVector3s(ParticleSystem.RenderData[i].Position, ParticleSystem.RenderData[i-1].Position),
  239.                                   SubVector3s(ParticleSystem.RenderData[i+1].Position, ParticleSystem.RenderData[i].Position));
  240.     if SqrMagnitude(OldNorm) > epsilon then begin
  241.       if LastIndex <> -1 then begin
  242.         if DotProductVector3s(OldNorm, CurNorm) < 0 then
  243.           ScaleVector3s(OldNorm, -1);
  244.       end else for j := i-1 downto 0 do Crosses[j] := OldNorm;
  245.       CurNorm := OldNorm;
  246.       LastIndex := i;
  247.     end;
  248.     Crosses[i] := CurNorm;
  249.   end;
  250.   Crosses[ParticleSystem.TotalParticles-1] := Crosses[ParticleSystem.TotalParticles-2];
  251.   ParticlesVisible := 0;
  252.   CurU             := 0;
  253.   for i := 0 to ParticleSystem.TotalParticles-1 do begin
  254.     with ParticleSystem.RenderData[i] do begin
  255.       CurNorm := GetNormal(i);
  256.       InvDist := 1/Sqrt(SqrMagnitude(Crosses[i]));
  257.       ScaleVector3s(Crosses[i], Crosses[i], Size*InvDist);
  258.       CurU := CurU + UVScale/InvDist;
  259.       SetVertexDataC(AddVector3s(Position, Crosses[i]), ParticlesVisible*2, VBPTR);
  260.       SetVertexDataN(CurNorm,  ParticlesVisible*2, VBPTR);
  261.       SetVertexDataUV(0, CurU, ParticlesVisible*2, VBPTR);
  262.       SetVertexDataD(Color,    ParticlesVisible*2, VBPTR);
  263.       SetVertexDataC(SubVector3s(Position, Crosses[i]), ParticlesVisible*2+1, VBPTR);
  264.       SetVertexDataN(CurNorm,  ParticlesVisible*2+1, VBPTR);
  265.       SetVertexDataUV(1, CurU, ParticlesVisible*2+1, VBPTR);
  266.       SetVertexDataD(Color,    ParticlesVisible*2+1, VBPTR);
  267.     end;
  268.     Inc(ParticlesVisible);
  269.   end;
  270.   TotalPrimitives   := ParticlesVisible*2 - 2;
  271.   Result            := ParticlesVisible*2;
  272.   TotalVertices     := Result;
  273.   LastTotalVertices := Result;
  274. end;
  275. begin
  276.   GlobalClassList.Add('C2ParticleAdv', GetUnitClassList);
  277. end.