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

游戏引擎

开发平台:

Delphi

  1. (*
  2.  CAST II Engine grass vegetation unit
  3.  (C) 2006-2008 George "Mirage" Bakhtadze. avagames@gmail.com
  4.  Created: Jul 20, 2008
  5.  Unit contains grass visualisation class
  6. *)
  7. {$Include GDefines.inc}
  8. {$Include C2Defines.inc}
  9. unit C2Grass;
  10. interface
  11. uses
  12.   SysUtils, TextFile, Basics, BaseTypes, Base3D, Props, BaseMsg, ItemMsg, BaseClasses,
  13.   {$IFDEF EDITORMODE} BaseGraph, C2MapEditMsg, {$ENDIF}
  14.   C2Types, C2Visual, C2VisItems, CAST2, C2Land, C2Maps;
  15. type
  16.   TGrassTesselator = class(TMappedTesselator)
  17.   private
  18.     FDensity, FThreshold, FOscillationIrregularity: Single;
  19.     FRandoms: TRandomGenerator;
  20.     FHeightMap: C2Maps.TMap;
  21.     BoundingBox: TBoundingBox;
  22.   public
  23.     constructor Create; override;
  24.     destructor Destroy; override;
  25.     procedure AddProperties(const Result: Props.TProperties; const PropNamePrefix: TNameString); override;
  26.     procedure SetProperties(Properties: Props.TProperties; const PropNamePrefix: TNameString); override;
  27.     procedure Init; override;
  28.     function GetBoundingBox: TBoundingBox; override;
  29.     
  30.     function Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer; override;
  31.   end;
  32.   TGrass = class(C2Visual.TMappedItem)
  33.   private
  34.     FHeightMap: C2Maps.TMap;
  35.     ShaderConsts: TShaderConstants;
  36.     FOscillationFreq, FOscillationAmplitude: Single;
  37.   protected
  38.     procedure ResolveLinks; override;
  39.     {$IFDEF EDITORMODE}
  40.     function PickCell(Camera: TCamera; MouseX, MouseY: Integer; out CellX, CellZ: Integer): Boolean; override;
  41.     function DrawCursor(Cursor: C2MapEditMsg.TMapCursor; Camera: TCamera; Screen: TScreen): Boolean; override;
  42.     {$ENDIF}
  43.     procedure InitShaderConstants;
  44.   public
  45.     function GetTesselatorClass: CTesselator; override;
  46.     procedure RetrieveShaderConstants(var ConstList: TShaderConstants); override;
  47.     procedure OnSceneLoaded; override;
  48.     procedure HandleMessage(const Msg: TMessage); override;
  49.     procedure AddProperties(const Result: Props.TProperties); override;
  50.     procedure SetProperties(Properties: Props.TProperties); override;
  51.   end;
  52.   TRadGridGrassTesselator = class(TRadGridTesselator)
  53.   private
  54.     FGrassHeight, FSampleSize: Single;
  55.   public
  56.     procedure Init; override;
  57.     function GetUpdatedElements(Buffer: TTesselationBuffer; const Params: TTesselationParameters): Integer; override;
  58.     procedure AddProperties(const Result: Props.TProperties; const PropNamePrefix: TNameString); override;
  59.     procedure SetProperties(Properties: Props.TProperties; const PropNamePrefix: TNameString); override;
  60.     function Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer; override;
  61.   end;
  62.   TRadGridGrass = class(TProjectedLandscape)
  63.   public
  64.     function GetTesselatorClass: CTesselator; override;
  65.   end;
  66.   // Returns list of classes introduced by the unit
  67.   function GetUnitClassList: TClassArray;
  68. implementation
  69. function GetUnitClassList: TClassArray;
  70. begin
  71.   Result := GetClassList([TGrass, TRadGridGrass]);
  72. end;
  73. { TRadGridGrassTesselator }
  74. const VerticesPerPoint = 6;
  75. procedure TRadGridGrassTesselator.Init;
  76. begin
  77.   inherited;
  78.   if Assigned(FMap) then begin
  79.     TotalVertices   := (FGridWidth+1)*(FGridHeight+1) * VerticesPerPoint;
  80.     TotalIndices    := 0;//(FGridWidth+1)*2;    //  - - 89, 1 - 309-315, 2 - 85
  81.     TotalStrips     := 1;//FGridHeight;
  82.     TotalPrimitives := (FGridWidth+1)*(FGridHeight+1);
  83.     StripOffset     := 0;//FGridWidth+1;
  84. //    StripOffset     := FGridWidth+1;
  85.     SetLength(FMipZ, FGridHeight+1);
  86. //  0  2  4          0 1 2 3 4 5  5 1           P: ??? (w*2)*(h-1)-2 = (3*2)*3-2 = 16
  87. //  1  3  5          1 6 3 7 5 8  8 6           V: w*h = 3*4 = 12
  88. //  6  7  8          6 9 7 A 8 B                I: (2+(w-1)*2+2)*(h-1)-2 = 2*(w+1)*(h-1) = (2+(3-1)*2+2)*3-2 = 8*3-2 = 22
  89. //  9  A  B
  90. {    TotalIndices    := 2*(FGridWidth+2)*(FGridHeight);//-2
  91.     TotalStrips     := 1;
  92.     TotalPrimitives := 2*(FGridWidth+1)*(FGridHeight)-2;//(TotalIndices-2-2);
  93.     StripOffset     := 0;}
  94.   end else begin
  95.     TotalVertices   := 0;
  96.     TotalStrips     := 0;
  97.     TotalIndices    := 0;
  98.     TotalPrimitives := 0;
  99.     StripOffset     := 0;
  100.   end;
  101.   ManualRender := False;
  102.   PrimitiveType := ptTRIANGLELIST;
  103.   TesselationStatus[tbVertex].TesselatorType := ttStatic;
  104.   TesselationStatus[tbIndex].TesselatorType  := ttStatic;
  105.    IndexingVertices := TotalVertices;
  106. //  InitVertexFormat(GetVertexFormat(False, False, True, False, False, 0, [2]));
  107.   InitVertexFormat(GetVertexFormat(False, False, False, False, False, 0, [2]));
  108.   LastTexUpdX := 0;
  109.   LastTexUpdZ := 0;
  110. end;
  111. function TRadGridGrassTesselator.GetUpdatedElements(Buffer: TTesselationBuffer; const Params: TTesselationParameters): Integer;
  112. begin
  113.   Result := inherited GetUpdatedElements(Buffer, Params) * VerticesPerPoint;
  114. end;
  115. function TRadGridGrassTesselator.Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer;
  116. var
  117.   HalfLengthX, HalfLengthZ: Single;
  118.   VBuf: PVector3s;
  119.   TVBuf: PVector2s;
  120.   P, P1, P2, P1Incr, P2Incr, PIncr: TVector3s;
  121.   OneOverCellWidthScale, OneOverCellHeightScale: Single;
  122.   i, k, l, X1, Z1, Addr: Integer;
  123.   Data, Data2: Pointer;
  124.   LastY, CurY, xo, zo: Single;
  125. //  LastLine: array[0..1023] of Single;
  126.   OutP: TVector3s;
  127.   DistIncr, FarDist, NearDist, TempK, Error: Single;
  128.   FirstPartK, LastPartK, LightMapScaleX, LightMapScaleZ, MipK, MipDivider, TempX, TempZ: Single;
  129.   MipW, MipH, MipW2, MipH2, Index: Integer;
  130.   IndI, IndJ: Cardinal;
  131.   type
  132.     TData = record
  133.       case Boolean of
  134.         True: (a, b, c, d: Byte);
  135.         False: (d32: Longword);
  136.     end;
  137.   var
  138.     d0, d1, d2, d3: TData;
  139.     ModelInv: TMatrix4s;
  140.     CameraInModel: TVector3s;
  141.     j: Integer;
  142.     Rad, TriSize: Single;
  143.   procedure PutStamp(P: TVector3s);
  144.   begin
  145.     P.X := Round(P.X) div 4 * 4;
  146.     P.Z := Round(P.Z) div 4 * 4;
  147.     P.Y := P.Y + Random * FGrassHeight;
  148.     VBuf^.X := P.X-TriSize;
  149.     VBuf^.Z := P.Z;
  150.     VBuf^.Y := P.Y;
  151.     Single(Pointer(Integer(VBuf) + 12)^) := 0;
  152.     Single(Pointer(Integer(VBuf) + 16)^) := 1;
  153.     VBuf := Pointer(Integer(VBuf) + FVertexSize);
  154.     VBuf^.X := P.X+TriSize;
  155.     VBuf^.Z := P.Z;
  156.     VBuf^.Y := P.Y;
  157.     Single(Pointer(Integer(VBuf) + 12)^) := 1;
  158.     Single(Pointer(Integer(VBuf) + 16)^) := 1;
  159.     VBuf := Pointer(Integer(VBuf) + FVertexSize);
  160.     VBuf^.X := P.X;
  161.     VBuf^.Z := P.Z;
  162.     VBuf^.Y := P.Y+FGrassHeight;
  163.     Single(Pointer(Integer(VBuf) + 12)^) := 0.5;
  164.     Single(Pointer(Integer(VBuf) + 16)^) := 0;
  165.     VBuf := Pointer(Integer(VBuf) + FVertexSize);
  166.     VBuf^.X := P.X;
  167.     VBuf^.Z := P.Z-TriSize;
  168.     VBuf^.Y := P.Y;
  169.     Single(Pointer(Integer(VBuf) + 12)^) := 0;
  170.     Single(Pointer(Integer(VBuf) + 16)^) := 1;
  171.     VBuf := Pointer(Integer(VBuf) + FVertexSize);
  172.     VBuf^.X := P.X;
  173.     VBuf^.Z := P.Z+TriSize;
  174.     VBuf^.Y := P.Y;
  175.     Single(Pointer(Integer(VBuf) + 12)^) := 1;
  176.     Single(Pointer(Integer(VBuf) + 16)^) := 1;
  177.     VBuf := Pointer(Integer(VBuf) + FVertexSize);
  178.     VBuf^.X := P.X;
  179.     VBuf^.Z := P.Z;
  180.     VBuf^.Y := P.Y+FGrassHeight;
  181.     Single(Pointer(Integer(VBuf) + 12)^) := 0.5;
  182.     Single(Pointer(Integer(VBuf) + 16)^) := 0;
  183.     VBuf := Pointer(Integer(VBuf) + FVertexSize);
  184.   //          TColor(Pointer(Integer(VBuf) + 12)^).C := MipColors[k+NearMip];
  185.   end;
  186. begin
  187.   Result := 0;
  188.   if not Assigned(FMap) or not FMap.IsReady then Exit;
  189.   OldCameraMatrix := Params.Camera.Transform;
  190.   ModelInv := InvertAffineMatrix4s(Params.ModelMatrix);
  191.   Transform4Vector33s(CameraInModel, ModelInv, Params.Camera.GetAbsLocation);
  192.   CamOfsX := CameraInModel.X;
  193.   CamOfsZ := CameraInModel.Z;
  194.   HalfLengthX := (FMap.Width-1)  * FMap.CellWidthScale  * 0.5;
  195.   HalfLengthZ := (FMap.Height-1) * FMap.CellHeightScale * 0.5;
  196.   LightMapScaleX := 0.5/HalfLengthX;
  197.   LightMapScaleZ := 0.5/HalfLengthZ;
  198.   OneOverCellWidthScale  := 1/FMap.CellWidthScale;
  199.   OneOverCellHeightScale := 1/FMap.CellHeightScale;
  200.   Rad := 0;
  201.   NearDist := 2*pi * Rad;
  202.   FarDist  := 2*pi * (ViewDepth + 1*ExcessDist);
  203.   DistIncr := FarDist - NearDist;
  204.   if DistIncr < 0 then Exit;
  205.   NearMip := 0;
  206.   while (NearMip < THeightMap(FMap).Image.SuggestedLevels-1) and
  207.         (2*pi*FMap.CellWidthScale * (FGridWidth+1) * (1 shl NearMip) * MipScale <= NearDist) do
  208.     Inc(NearMip);
  209.   FarMip := 0;
  210.   while (FarMip < THeightMap(FMap).Image.SuggestedLevels-1) and
  211.         (2*pi*FMap.CellWidthScale * (FGridWidth+1) * (1 shl FarMip) * MipScale <= FarDist) do
  212.     Inc(FarMip);
  213.   for i := NearMip to FarMip do MipStart[i-NearMip+1] := (FMap.CellWidthScale * (FGridWidth+1) * (1 shl i) * MipScale-NearDist) / DistIncr;
  214.   if MipStart[FarMip-NearMip+1] < 1 then begin
  215. //    Assert(MipStart[FarMip-NearMip+1] >= 1);
  216.   end;
  217.   if FarMip-NearMip >= 1 then begin
  218.     MipStart[0] := -(MipStart[2] - 3*MipStart[1])/2;
  219.     FirstPartK  := MipStart[1]/(MipStart[1] - MipStart[0]);
  220.     LastPartK   := (1-MipStart[FarMip-NearMip])/(MipStart[FarMip-NearMip+1] - MipStart[FarMip-NearMip]);
  221.     TempK := 1/(FirstPartK + FarMip - NearMip - 1 + LastPartK);
  222.     MipDetail[0] := Round(FirstPartK * TempK * (FGridHeight+1));
  223.     Error := FirstPartK * TempK * (FGridHeight+1) - MipDetail[0];
  224.     for i := NearMip+1 to FarMip-1 do begin
  225.       MipDetail[i-NearMip] := Round(TempK * (FGridHeight+1) + Error);
  226.       Error := (TempK * (FGridHeight+1) + Error) - MipDetail[i-NearMip];
  227.     end;
  228.     MipDetail[FarMip-NearMip] := Round(LastPartK * TempK * (FGridHeight+1) + Error);
  229.     Error := (LastPartK * TempK * (FGridHeight+1) + Error) - MipDetail[FarMip-NearMip];
  230.     if Error >= 0.5 then Inc(MipDetail[0]);
  231.     if MipDetail[FarMip-NearMip] <= 1 then begin
  232.       Inc(MipDetail[FarMip-NearMip-1], MipDetail[FarMip-NearMip]);
  233.       Dec(FarMip);
  234.     end;
  235.     Error := 0;
  236.     for i := 0 to FarMip-NearMip do Error := Error + MipDetail[i];
  237.     Assert(Error = (FGridHeight+1));
  238.   end else begin
  239.     MipDetail[0] := (FGridHeight+1);
  240.   end;
  241.   MipStart[0] := 0;
  242.   MipStart[FarMip-NearMip+1] := 1;
  243.   VBuf := VBPTR;
  244.   TVBuf := @FGrid[0];
  245.   j := 0;
  246.   for k := 0 to FarMip-NearMip do begin
  247.     Data  := PtrOffs(FMap.Data, THeightMap(FMap).Image.LevelInfo[k + NearMip].Offset);
  248.     Data2 := PtrOffs(FMap.Data, THeightMap(FMap).Image.LevelInfo[k + NearMip+1].Offset);
  249.     MipDivider := 1/(1 shl (k + NearMip));
  250.     MipW  := FMap.Width  shr (k + NearMip);
  251.     MipH  := FMap.Height shr (k + NearMip);
  252.     MipW2 := FMap.Width  shr (k + NearMip+1);
  253.     MipH2 := FMap.Height shr (k + NearMip+1);
  254.     for l := 0 to MipDetail[k]-1 do begin
  255. //      Rad := (ViewDepth + ExcessDist) * (MipStart[k] + l*(MipStart[k+1] - MipStart[k])/(MipDetail[k]-Ord(k = FarMip-NearMip)));
  256. //      FMipZ[j] := Rad;
  257. //      Sqrt(SqrMagnitude(GetVector3s(P1.X - CamOfsX, 0, P1.Z - CamOfsZ)));
  258.       TriSize := (1+FMipZ[j])*FSampleSize;
  259.       Inc(j);
  260. //      ScaleVector3s(PIncr, SubVector3s(P2, P1), 1 / FGridWidth);
  261. //      P := P1;
  262.       MipK := MaxS(0, l/MipDetail[k] - (1-TrilinearRange))/TrilinearRange;
  263.       if MipK < epsilon then begin
  264.         for i := 0 to FGridWidth do begin
  265.           P.X := CamOfsX - TVBuf^.X;
  266.           P.Z := CamOfsZ + TVBuf^.Y;
  267.           TempX := (ClampS(P.X, -HalfLengthX, HalfLengthX) + HalfLengthX) * OneOverCellWidthScale  * MipDivider;
  268.           TempZ := (ClampS(P.Z, -HalfLengthZ, HalfLengthZ) + HalfLengthZ) * OneOverCellHeightScale * MipDivider;
  269.           X1 := FastTrunc(TempX);
  270.           Z1 := FastTrunc(TempZ);
  271.           xo := (TempX - X1);// * Ord(X1 >= 0) * Ord(X1 < MipW);
  272.           zo := (TempZ - Z1);// * Ord(Z1 >= 0) * Ord(Z1 < MipH);
  273.           X1 := X1 * Ord(X1 >= 0) * Ord(X1 < MipW);
  274.           Z1 := Z1 * Ord(Z1 >= 0) * Ord(Z1 < MipH);
  275.           Addr := Z1 * MipW + X1;
  276.           // May read 2 bytes outside texture data. It's safe because these 2 bytes will go from next mipmap.
  277.           d0.d32 := PLongword(Integer(Data) + Addr - MipW * Ord(Z1 > 0) - Ord(X1 > 0))^;
  278.           d1.d32 := PLongword(Integer(Data) + Addr - Ord(X1 > 0))^;
  279.           d2.d32 := PLongword(Integer(Data) + Addr - Ord(X1 > 0) + MipW * Ord(Z1 < MipH-1))^;
  280.           d3.d32 := PLongword(Integer(Data) + Addr - Ord(X1 > 0) + MipW * Ord(Z1 < MipH-1) + MipW * Ord(Z1 < MipH-2))^;
  281.           P.Y := ((1-xo) * (( d0.b + d1.a + d1.c + d2.b ) * (1-zo) +
  282.                             ( d1.b + d2.a + d2.c + d3.b ) * zo ) +
  283.                      xo  * (( d0.c + d1.b + d1.d + d2.c ) * (1-zo) +
  284.                             ( d1.c + d2.b + d2.d + d3.c ) * zo)) * FMap.DepthScale * 0.25;
  285.           PutStamp(P);
  286.           TVBuf := Pointer(Integer(TVBuf) + SizeOf(TVector2s));
  287.         end;
  288.       end else begin
  289.         for i := 0 to FGridWidth do begin
  290.           P.X := CamOfsX - TVBuf^.X;
  291.           P.Z := CamOfsZ + TVBuf^.Y;
  292.           TempX := (ClampS(P.X, -HalfLengthX, HalfLengthX) + HalfLengthX) * OneOverCellWidthScale  * MipDivider;
  293.           TempZ := (ClampS(P.Z, -HalfLengthZ, HalfLengthZ) + HalfLengthZ) * OneOverCellHeightScale * MipDivider;
  294.           X1 := FastTrunc(TempX);
  295.           Z1 := FastTrunc(TempZ);
  296.           xo := (TempX - X1){ * Ord(X1 >= 0) * Ord(X1 < MipW)};
  297.           zo := (TempZ - Z1){ * Ord(Z1 >= 0) * Ord(Z1 < MipH)};
  298.           X1 := X1 * Ord(X1 >= 0) * Ord(X1 < MipW);
  299.           Z1 := Z1 * Ord(Z1 >= 0) * Ord(Z1 < MipH);
  300.           Addr := Z1 * MipW + X1;
  301.           d0.d32 := PLongword(Integer(Data) + Addr - MipW * Ord(Z1 > 0) - Ord(X1 > 0))^;
  302.           d1.d32 := PLongword(Integer(Data) + Addr - Ord(X1 > 0))^;
  303.           d2.d32 := PLongword(Integer(Data) + Addr - Ord(X1 > 0) + MipW * Ord(Z1 < MipH-1))^;
  304.           d3.d32 := PLongword(Integer(Data) + Addr - Ord(X1 > 0) + MipW * Ord(Z1 < MipH-1) + MipW * Ord(Z1 < MipH-2))^;
  305.           P.Y := ((1-xo) * (( d0.b + d1.a + d1.c + d2.b ) * (1-zo) +
  306.                             ( d1.b + d2.a + d2.c + d3.b ) * zo ) +
  307.                      xo  * (( d0.c + d1.b + d1.d + d2.c ) * (1-zo) +
  308.                             ( d1.c + d2.b + d2.d + d3.c ) * zo));
  309.           // Second mip
  310.           xo := (xo + X1 and 1)*0.5;
  311.           zo := (zo + Z1 and 1)*0.5;
  312.           X1 := X1 shr 1;
  313.           Z1 := Z1 shr 1;
  314.           Addr := Z1 * MipW2 + X1;
  315.           d0.d32 := PLongword(Integer(Data2) + Addr - MipW2 * Ord(Z1 > 0) - Ord(X1 > 0))^;
  316.           d1.d32 := PLongword(Integer(Data2) + Addr - Ord(X1 > 0))^;
  317.           d2.d32 := PLongword(Integer(Data2) + Addr - Ord(X1 > 0) + MipW2 * Ord(Z1 < MipH2-1))^;
  318.           d3.d32 := PLongword(Integer(Data2) + Addr - Ord(X1 > 0) + MipW2 * Ord(Z1 < MipH2-1) + MipW2 * Ord(Z1 < MipH2-2))^;
  319.           P.Y := 0.25*(P.Y * (1 - MipK) + MipK * (
  320.                   (1-xo) * (( d0.b + d1.a + d1.c + d2.b ) * (1-zo) +
  321.                             ( d1.b + d2.a + d2.c + d3.b ) * zo ) +
  322.                      xo  * (( d0.c + d1.b + d1.d + d2.c ) * (1-zo) +
  323.                             ( d1.c + d2.b + d2.d + d3.c ) * zo)) ) * FMap.DepthScale;
  324.           PutStamp(P);
  325.           TVBuf := Pointer(Integer(TVBuf) + SizeOf(TVector2s));
  326.         end;
  327.       end;
  328.     end;
  329.   end;
  330.   TesselationStatus[tbVertex].Status := tsTesselated;
  331. //  TesselationStatus[tbVertex].Status := tsChanged;
  332.   Result  := TotalVertices;
  333. //  Assert((FGridWidth+1)*jj = Result);
  334.   LastTotalVertices := TotalVertices;
  335. end;
  336. procedure TRadGridGrassTesselator.AddProperties(const Result: TProperties; const PropNamePrefix: TNameString);
  337. begin
  338.   inherited;
  339.   if Assigned(Result) then begin
  340.     Result.Add(PropNamePrefix + 'Height',      vtSingle, [], FloatToStr(FGrassHeight), '0.1-4');
  341.     Result.Add(PropNamePrefix + 'Sample size', vtSingle, [], FloatToStr(FSampleSize),  '0.03-3');
  342.   end;
  343. end;
  344. procedure TRadGridGrassTesselator.SetProperties(Properties: TProperties; const PropNamePrefix: TNameString);
  345. begin
  346.   inherited;
  347.   if Properties.Valid(PropNamePrefix + 'Height')      then FGrassHeight := StrToFloatDef(Properties[PropNamePrefix + 'Height'], 1);
  348.   if Properties.Valid(PropNamePrefix + 'Sample size') then FSampleSize  := StrToFloatDef(Properties[PropNamePrefix + 'Sample size'], 0.1);
  349. end;
  350. { TRadGridGrass }
  351. function TRadGridGrass.GetTesselatorClass: CTesselator; begin Result := TRadGridGrassTesselator; end;
  352. { TGrass }
  353. procedure TGrass.ResolveLinks;
  354. var Item: TItem;
  355. begin
  356.   inherited;
  357.   if CurrentTesselator is TGrassTesselator then begin
  358.     ResolveLink('Height map', Item);
  359.     if Assigned(Item) then begin
  360.       FHeightMap := Item as C2Maps.TMap;
  361.       (CurrentTesselator as TGrassTesselator).FHeightMap := FHeightMap;
  362.       CurrentTesselator.Init;
  363.     end;
  364.   end;
  365. end;
  366. {$IFDEF EDITORMODE}
  367. function TGrass.PickCell(Camera: TCamera; MouseX, MouseY: Integer; out CellX, CellZ: Integer): Boolean;
  368. var CameraPos, PickRay, PickPos: TVector3s; M: TMatrix4s;
  369. begin
  370.   Result := False;
  371.   if not Assigned(FHeightMap) then Exit;
  372.   // Transform camera position and pick ray to model space
  373.   M := InvertMatrix4s(Transform);
  374.   CameraPos := Transform4Vector33s(M, Camera.Position);
  375.   PickRay := Camera.GetPickRay(MouseX, MouseY);
  376.   PickRay := Transform3Vector3s(CutMatrix3s(InvertAffineMatrix4s(Camera.ViewMatrix)), PickRay);
  377.   PickRay.Y := PickRay.Y;
  378.   PickRay := NormalizeVector3s(Transform3Vector3s(CutMatrix3s(M), PickRay));
  379.   Result := FHeightMap.TraceRay(CameraPos, PickRay, PickPos);
  380.   if Result then Map.ObtainCell(PickPos.X, PickPos.Z, CellX, CellZ);
  381. end;
  382. function TGrass.DrawCursor(Cursor: TMapCursor; Camera: TCamera; Screen: TScreen): Boolean;
  383.   procedure DrawCell(CellX, CellZ: Integer);
  384.   var v: TVector3s;
  385.   begin
  386.     if (CellX < 1) or (CellZ < 1) or (CellX > FMap.Width-2) or (CellZ > FMap.Height-2) then Exit;
  387.     v.x := (CellX - (FMap.Width -1) * 0.5) * FMap.CellWidthScale;
  388.     v.z := (CellZ - (FMap.Height-1) * 0.5) * FMap.CellHeightScale;
  389.     v.y := FHeightMap.GetHeight(v.x, v.z);
  390.     Screen.MoveToVec(Camera.Project(Transform4Vector33s(Transform, v)).xyz);
  391.     v.y := v.y + (FMap[CellX, CellZ]+1) * FMap.DepthScale * 0.5;
  392.     Screen.LineToVec(Camera.Project(Transform4Vector33s(Transform, v)).xyz);
  393.   end;
  394.   procedure DrawCursorAt(CellX, CellZ, Size: Integer);
  395.   var i, j: Integer;
  396.   begin
  397. //    Screen.MoveTo(0, 0);
  398. //    Screen.LineTo(0, 0);
  399.     for i := CellX - Size div 2 to CellX + Size div 2 do
  400.       for j := CellZ - Size div 2 to CellZ + Size div 2 do DrawCell(i, j);
  401.   end;
  402. begin
  403.   Result := False;
  404.   if not EditMode and not PickCell(Camera, Cursor.MouseX, Cursor.MouseY, EditCellX, EditCellZ) then Exit;
  405.   DrawCursorAt(EditCellX, EditCellZ, Cursor.Params.GetAsInteger('Size'));
  406.   Result := True;
  407. end;
  408. {$ENDIF}
  409. procedure TGrass.InitShaderConstants;
  410. begin
  411.   SetLength(ShaderConsts, 2);
  412.   ShaderConsts[0].ShaderKind     := skVertex;
  413.   ShaderConsts[0].ShaderRegister := 8;
  414.   ShaderConsts[0].Value          := Vec4s(FOscillationAmplitude * Sin(TimeProcessed*FOscillationFreq*2*pi),      FOscillationAmplitude * Sin(TimeProcessed*FOscillationFreq*2*pi+pi/4),
  415.                                           FOscillationAmplitude * Sin(TimeProcessed*FOscillationFreq*2*pi+pi/2), FOscillationAmplitude * Sin(TimeProcessed*FOscillationFreq*2*pi+3*pi/4));
  416.   ShaderConsts[1].ShaderKind     := skVertex;
  417.   ShaderConsts[1].ShaderRegister := 9;
  418.   ShaderConsts[1].Value          := Vec4s(1/(FHeightMap.Width*FHeightMap.CellWidthScale), 1/(FHeightMap.Height*FHeightMap.CellHeightScale), 0.5*FHeightMap.Width*FHeightMap.CellWidthScale, 0.5*FHeightMap.Height*FHeightMap.CellHeightScale);
  419. end;
  420. function TGrass.GetTesselatorClass: CTesselator; begin Result := TGrassTesselator; end;
  421. procedure TGrass.RetrieveShaderConstants(var ConstList: TShaderConstants);
  422. begin
  423.   ShaderConsts[0].Value := Vec4s(FOscillationAmplitude * Sin(TimeProcessed*FOscillationFreq*2*pi),      FOscillationAmplitude * Sin(TimeProcessed*FOscillationFreq*2*pi+pi/4),
  424.                                  FOscillationAmplitude * Sin(TimeProcessed*FOscillationFreq*2*pi+pi/2), FOscillationAmplitude * Sin(TimeProcessed*FOscillationFreq*2*pi+3*pi/4));
  425.   ShaderConsts[1].Value := Vec4s(1/(FHeightMap.Width*FHeightMap.CellWidthScale), 1/(FHeightMap.Height*FHeightMap.CellHeightScale), 0.5*FHeightMap.Width*FHeightMap.CellWidthScale, 0.5*FHeightMap.Height*FHeightMap.CellHeightScale);
  426.   ConstList := ShaderConsts;
  427. end;
  428. procedure TGrass.OnSceneLoaded;
  429. begin
  430.   InitShaderConstants;
  431. end;
  432. procedure TGrass.AddProperties(const Result: TProperties);
  433. begin
  434.   inherited;
  435.   AddItemLink(Result, 'Height map', [], 'TMap');
  436.   if Result <> nil then begin
  437.     Result.Add('Oscillation frequency',    vtSingle, [], FloatToStr(FOscillationFreq),         '0.1-2');
  438.     Result.Add('Oscillation amplitude',    vtSingle, [], FloatToStr(FOscillationAmplitude),    '0.1-2');
  439.   end;
  440. end;
  441. procedure TGrass.SetProperties(Properties: TProperties);
  442. begin
  443.   inherited;
  444.   if Properties.Valid('Height map') then SetLinkProperty('Height map', Properties['Height map']);
  445.   if Properties.Valid('Oscillation frequency')    then FOscillationFreq         := StrToFloatDef(Properties['Oscillation frequency'], 0.1);
  446.   if Properties.Valid('Oscillation amplitude')    then FOscillationAmplitude    := StrToFloatDef(Properties['Oscillation amplitude'], 0.1);
  447.   ResolveLinks;
  448. end;
  449. procedure TGrass.HandleMessage(const Msg: TMessage);
  450. begin
  451.   inherited;
  452.   if (Msg.ClassType = TItemModifiedMsg) and (TItemModifiedMsg(Msg).Item = FHeightMap) and Assigned(FCurrentTesselator) then
  453.     FCurrentTesselator.Invalidate([tbVertex, tbIndex], False);
  454. end;
  455. { TGrassTesselator }
  456. constructor TGrassTesselator.Create;
  457. begin
  458.   inherited;
  459.   FRandoms := TRandomGenerator.Create;
  460.   FRandoms.InitSequence(0, 195);
  461. end;
  462. destructor TGrassTesselator.Destroy;
  463. begin
  464.   FreeAndNil(FRandoms);
  465.   inherited;
  466. end;
  467. procedure TGrassTesselator.AddProperties(const Result: TProperties; const PropNamePrefix: TNameString);
  468. begin
  469.   inherited;
  470.   if Assigned(Result) then begin
  471.     Result.Add(PropNamePrefix + 'Density',   vtSingle, [], FloatToStr(FDensity),     '0.05-10');
  472.     Result.Add(PropNamePrefix + 'Threshold', vtSingle, [], FloatToStr(FThreshold),   '0.01-1');
  473.     Result.Add(PropNamePrefix + 'Oscillation irregularity', vtSingle, [], FloatToStr(FOscillationIrregularity), '0-1');
  474.   end;
  475. end;
  476. procedure TGrassTesselator.SetProperties(Properties: TProperties; const PropNamePrefix: TNameString);
  477. begin
  478.   inherited;
  479.   if Properties.Valid(PropNamePrefix + 'Density')   then FDensity     := StrToFloatDef(Properties[PropNamePrefix + 'Density'], 1);
  480.   if Properties.Valid(PropNamePrefix + 'Threshold') then FThreshold   := StrToFloatDef(Properties[PropNamePrefix + 'Threshold'], 0.1);
  481.   if Properties.Valid(PropNamePrefix + 'Oscillation irregularity') then FOscillationIrregularity := StrToFloatDef(Properties[PropNamePrefix + 'Oscillation irregularity'], 0.5);
  482.   Init;
  483. end;
  484. procedure TGrassTesselator.Init;
  485. begin
  486.   inherited;
  487.   if Assigned(FMap) then begin
  488.     TotalVertices   := FMap.Width*FMap.Height*2*3*2;
  489. //    TotalIndices    := MaxI(0, (FMap.Width-1)) * MaxI(0, (FMap.Height-1)) * 6;
  490.     TotalPrimitives := FMap.Width * FMap.Height * 2*2;
  491.   end else begin
  492.     TotalVertices   := 0;
  493.     TotalIndices    := 0;
  494.     TotalPrimitives := 0;
  495.   end;
  496.   IndexingVertices := TotalVertices;
  497.   PrimitiveType    := ptTRIANGLELIST;
  498.   InitVertexFormat(GetVertexFormat(False, False, False, False, False, 0, [3]));
  499.   BoundingBox := EmptyBoundingBox;
  500. end;
  501. function TGrassTesselator.GetBoundingBox: TBoundingBox;
  502. begin
  503.   Result := BoundingBox;
  504. {  Result.P2 := ZeroVector3s;
  505.   if not Assigned(FMap) or (FMap.Width = 0) or (FMap.Height = 0) then Exit;
  506.   Result.P1 := GetVector3s(-(FMap.Width-1)  * FMap.CellWidthScale * 0.5,
  507.                             0,
  508.                            -(FMap.Height-1) * FMap.CellHeightScale * 0.5);
  509.   Result.P2 := GetVector3s( (FMap.Width-1)  * FMap.CellWidthScale * 0.5,
  510.                             FMap.MaxHeight * FMap.DepthScale,
  511.                             (FMap.Height-1) * FMap.CellHeightScale * 0.5);
  512.   if Assigned(FHeightMap) then Result.P2.Y := Result.P2.Y + FHeightMap.MaxHeight * FHeightMap.DepthScale;}
  513. end;
  514. function TGrassTesselator.Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer;
  515. const RndOffs: array[0..15] of Single =
  516.   (0.00, 0.05, 0.01, 0.15,
  517.    0.02, 0.25, 0.03, 0.35,
  518.    0.65, 0.70, 0.75, 0.80,
  519.    0.85, 0.90, 0.95, 1.0);
  520. var
  521.   VBuf: PVector3s;
  522.   Scattering: Single;
  523.   procedure PutStamp(PX, PZ, H: Single);
  524.   var d, u1, u2, y: Single; Osc: Cardinal;
  525.     procedure AddVertex(X, Y, Z, U, V: Single);
  526.     begin
  527.       VBuf^.X := X;
  528.       VBuf^.Z := Z;
  529.       VBuf^.Y := Y;
  530.       Single(Pointer(Integer(VBuf) + 12)^) := U*0.25;
  531.       Single(Pointer(Integer(VBuf) + 16)^) := V;
  532.       Single(Pointer(Integer(VBuf) + 20)^) := RndOffs[Osc];
  533.       VBuf := Pointer(Integer(VBuf) + FVertexSize);
  534.       Inc(Result);
  535.     end;
  536.   begin
  537. //    P.X := Round(P.X) div 4 * 4;
  538. //    P.Z := Round(P.Z) div 4 * 4;            //  (0,0) l /l (1,0)
  539. //    P.Y := P.Y + Random * FGrassHeight;     //  (0,1) l/_l (1,1)
  540.     u1 := FRandoms.RndI(4);
  541.     u2 := FRandoms.RndI(4);
  542.     Osc := FRandoms.RndI(1+Round(High(RndOffs)*FOscillationIrregularity));
  543. //    if u1 = 1 then u1 := 2;
  544. //    if u2 = 1 then u2 := 0;
  545. //    if FRandoms.RndI(30)=0 then u1 := 1;
  546.     d := Scattering * (0.5 + FRandoms.Rnd(1));
  547.     if h < FThreshold*255 then Exit;
  548.     h := h * FMap.DepthScale;
  549.     y := FHeightMap.GetHeight(PX, PZ);
  550.     ExpandBBox(BoundingBox, PX, y+h, PZ);
  551.     AddVertex(PX-d, y,   PZ, u1,   1);
  552.     AddVertex(PX+d, y,   PZ, u1+1, 1);
  553.     AddVertex(PX+d, y+h, PZ, u1+1, 0);
  554.     AddVertex(PX-d, y,   PZ, u1,   1);
  555.     AddVertex(PX+d, y+h, PZ, u1+1, 0);
  556.     AddVertex(PX-d, y+h, PZ, u1,   0);
  557.     AddVertex(PX, y,   PZ-d, u2,   1);
  558.     AddVertex(PX, y,   PZ+d, u2+1, 1);
  559.     AddVertex(PX, y+h, PZ+d, u2+1, 0);
  560.     AddVertex(PX, y,   PZ-d, u2,   1);
  561.     AddVertex(PX, y+h, PZ+d, u2+1, 0);
  562.     AddVertex(PX, y+h, PZ-d, u2,   0);
  563.   end;
  564. var i, j: Integer;
  565. begin
  566.   Result := 0;
  567.   if not Assigned(FMap) or not Assigned(FHeightMap) or not FMap.IsReady then Exit;
  568.   BoundingBox := EmptyBoundingBox;
  569.   BoundingBox.P1.Y := BoundingBox.P1.Y + FHeightMap.MaxHeight * FHeightMap.DepthScale;
  570.   FRandoms.InitSequence(0, 195);
  571.   Scattering := 1/Sqrt(FDensity);
  572.   FMap.CellWidthScale  := Scattering;
  573.   FMap.CellHeightScale := Scattering;
  574.   VBuf := VBPTR;
  575.   for i := 0 to FMap.Width-1 do
  576.     for j := 0 to FMap.Height-1 do
  577.       PutStamp((i-FMap.Width *0.5 + FRandoms.RndSymm(0.5))*Scattering,
  578.                (j-FMap.Height*0.5 + FRandoms.RndSymm(0.5))*Scattering, FMap[i, j]);
  579.   TesselationStatus[tbVertex].Status := tsTesselated;
  580.   LastTotalVertices := Result;
  581.   TotalPrimitives := Result div 3;
  582.   InvalidateBoundingBox
  583. end;
  584. begin
  585.   GlobalClassList.Add('C2Grass', GetUnitClassList);
  586. end.