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

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @abstract(CAST II Engine maps 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: Feb 13, 2007 <br>
  6.  Unit contains basic classes for various maps (tilemaps, heightmaps, etc)
  7. *)
  8. {$Include GDefines.inc}
  9. {$Include C2Defines.inc}
  10. unit C2Maps;
  11. interface
  12. uses SysUtils, BaseTypes, BaseMsg, Basics, Props, Base3D, BaseClasses, Models, ItemMsg;
  13. type
  14.   // Base class for height maps, tile maps, etc
  15.   TMap = class(TItem)
  16.   private
  17.     OneOverCellWidthScale, OneOverCellHeightScale: Single;
  18.   protected
  19.     FElementSize: Integer;
  20.     FWidth, FHeight, FMaxHeight: Integer;
  21.     FCellWidthScale, FCellHeightScale, FDepthScale: Single;
  22.     function GetData: Pointer; virtual; abstract;
  23.     procedure SetCellWidthScale(const Value: Single); virtual;
  24.     procedure SetCellHeightScale(const Value: Single); virtual;
  25.     procedure SetHeightScale(const Value: Single); virtual;
  26.     function GetRawHeight(XI, ZI: Integer): Integer; virtual; abstract;
  27.     procedure SetRawHeight(XI, ZI: Integer; const Value: Integer); virtual; abstract;
  28.     function GetCellHeight(XI, ZI: Integer): Single;
  29.     // Calculate coefficients for interpolation between values given at a rectangle corners
  30.     procedure CalcCoeffs(xo, zo: Single; out k11, k12, k21, k22: Single);
  31.   public
  32.     class function IsAbstract: Boolean; override;
  33.     constructor Create(AManager: TItemsManager); override;
  34.     procedure AddProperties(const Result: Props.TProperties); override;
  35.     procedure SetProperties(Properties: Props.TProperties); override;
  36.     // Returns True if the map object is ready to handle requests
  37.     function IsReady: Boolean; virtual;
  38.     procedure SetDimensions(AWidth, AHeight: Integer); virtual;
  39.     // Returns an interpolated height at the given point
  40.     function GetHeight(X, Z: Single): Single; virtual;
  41.     // Returns a normal at the given cell
  42.     function GetCellNormal(XI,ZI :Integer): TVector3s; virtual;
  43.     // Returns an interpolated normal at the given point
  44.     function GetNormal(X,Z: Single): TVector3s; virtual;
  45.     // Returns indices of map cell containing the given point
  46.     procedure ObtainCell(X, Z: Single; out CellX, CellZ: Integer);
  47.     // Copies a rectangular area of the map to a caller-allocated buffer
  48.     procedure ObtainRectHeights(const ARect: TRect; ABuf: Pointer); virtual;
  49.     // Swaps a rectangular area of the map with the contents of the specified buffer
  50.     procedure SwapRectHeights(const ARect: TRect; ABuf: Pointer); virtual;
  51.     // Adds a rectangular area of the map and the contents of the specified buffer contaning values of type Single
  52.     procedure AddRectHeights(const ARect: TRect; ABuf: Pointer; Scale: Single); virtual;
  53.     // Returns True if the specified in map (model) space ray intersects with the map. Also returns the point of intersection.
  54.     function TraceRay(const Origin, Dir: TVector3s; out Point: TVector3s): Boolean; virtual;
  55.     // Map width
  56.     property Width:  Integer read FWidth;
  57.     // Map height
  58.     property Height: Integer read FHeight;
  59.     // Map cell width
  60.     property CellWidthScale:  Single read FCellWidthScale  write SetCellWidthScale;
  61.     // Map cell height
  62.     property CellHeightScale: Single read FCellHeightScale  write SetCellHeightScale;
  63.     property DepthScale: Single read FDepthScale write SetHeightScale;
  64.     property MaxHeight: Integer read FMaxHeight;
  65.     // Size of single element of raw data
  66.     property ElementSize: Integer read FElementSize;
  67.     // Raw data
  68.     property Data: Pointer read GetData;
  69.     // Raw heights
  70.     property RawHeights[XI, ZI: Integer]: Integer read GetRawHeight write SetRawHeight; default;
  71.   end;
  72.   TMapEditOp = class(Models.TOperation)
  73.   protected
  74.     Map: TMap;
  75.     CellX, CellZ, CursorSize: Integer;
  76.     Buffer: Pointer;
  77.     // Applies the operation. Repeated call will undo the operation.
  78.     procedure DoApply; override;
  79.   public
  80.     destructor Destroy; override;
  81.   end;
  82. implementation
  83. { TMap }
  84. procedure TMap.SetCellWidthScale(const Value: Single);
  85. begin
  86.   FCellWidthScale := Value;
  87.   if Abs(FCellWidthScale) > epsilon then OneOverCellWidthScale := 1/FCellWidthScale else OneOverCellWidthScale := 0;
  88. end;
  89. procedure TMap.SetCellHeightScale(const Value: Single);
  90. begin
  91.   FCellHeightScale := Value;
  92.   if Abs(FCellHeightScale) > epsilon then OneOverCellHeightScale := 1/FCellHeightScale else OneOverCellHeightScale := 0;
  93. end;
  94. procedure TMap.SetHeightScale(const Value: Single);
  95. begin
  96.   FDepthScale := Value;
  97. end;
  98. function TMap.GetCellHeight(XI, ZI: Integer): Single;
  99. begin
  100.   Result := GetRawHeight(XI, ZI) * DepthScale;
  101. end;
  102. procedure TMap.CalcCoeffs(xo, zo: Single; out k11, k12, k21, k22: Single);
  103. var k: Single;
  104. begin
  105.   if xo > zo then k := xo-zo else k := zo-xo;
  106.   k22 := (xo+zo)*0.5 * (1-k);
  107.   k11 := (1-(xo+zo)*0.5) * (1-k);
  108.   if xo > zo then k21 := k else k21 := 0;
  109.   if zo > xo then k12 := k else k12 := 0;
  110. end;
  111. class function TMap.IsAbstract: Boolean; begin Result := Self = TMap; end;
  112. constructor TMap.Create(AManager: TItemsManager);
  113. begin
  114.   inherited;
  115. end;
  116. procedure TMap.AddProperties(const Result: Props.TProperties);
  117. begin
  118.   inherited;
  119.   if not Assigned(Result) then Exit;
  120.   Result.Add('Width',           vtInt,    [], IntToStr(FWidth),             '');
  121.   Result.Add('Height',          vtInt,    [], IntToStr(FHeight),            '');
  122.   Result.Add('CellWidthScale',  vtSingle, [], FloatToStr(FCellWidthScale),  '0.1-32');
  123.   Result.Add('CellHeightScale', vtSingle, [], FloatToStr(FCellHeightScale), '0.1-32');
  124.   Result.Add('DepthScale',      vtSingle, [], FloatToStr(FDepthScale),      '0-10');
  125. end;
  126. procedure TMap.SetProperties(Properties: Props.TProperties);
  127. var NWidth, NHeight: Integer;
  128. begin
  129.   inherited;
  130.   NWidth  := FWidth;
  131.   NHeight := FHeight;
  132.   if Properties.Valid('Width')  then NWidth  := StrToIntDef(Properties['Width'],  FWidth);
  133.   if Properties.Valid('Height') then NHeight := StrToIntDef(Properties['Height'], FHeight);
  134.   if (NWidth <> FWidth) or (NHeight <> FHeight) then SetDimensions(NWidth, NHeight);
  135.   if Properties.Valid('CellWidthScale')  then CellWidthScale   := StrToFloatDef(Properties['CellWidthScale'],  FCellWidthScale);
  136.   if Properties.Valid('CellHeightScale') then CellHeightScale  := StrToFloatDef(Properties['CellHeightScale'], FCellHeightScale);
  137.   if Properties.Valid('DepthScale')      then DepthScale       := StrToFloatDef(Properties['DepthScale'],      FDepthScale);
  138. end;
  139. function TMap.IsReady: Boolean;
  140. begin
  141.   Result := (FElementSize <> 0) and (FWidth > 0) and (FHeight > 0);
  142. end;
  143. procedure TMap.SetDimensions(AWidth, AHeight: Integer);
  144. begin
  145.   FWidth := AWidth; FHeight := AHeight;
  146. end;
  147. {function TMap.GetCellNormal(XI, ZI: Integer): TVector3s;
  148. var NX1, NZ1, NX2, NZ2: Integer; InvDist: Single;
  149. begin
  150.   Assert((XI >= 0) and (ZI >= 0) and (XI < Width) and (ZI < Height), '');
  151.   NX1 := MaxI(0, XI-1);
  152.   NZ1 := MaxI(0, ZI-1);
  153.   NX2 := MinI(Width-1,  XI+1);
  154.   NZ2 := MinI(Height-1, ZI+1);
  155.   CrossProductVector3s(Result, GetVector3s(0, GetCellHeight(XI, NZ2) - GetCellHeight(XI, NZ1), CellHeightScale*2),
  156.                                GetVector3s(CellWidthScale*2, GetCellHeight(NX2, ZI) - GetCellHeight(NX1, ZI), 0) );
  157.   Result.Y := Result.Y;
  158.   InvDist := InvSqrt(SqrMagnitude(Result));
  159.   Result.X := Result.X * InvDist;
  160.   Result.Y := Result.Y * InvDist;
  161.   Result.Z := Result.Z * InvDist;
  162. end;}
  163. function TMap.GetCellNormal(XI, ZI: Integer): TVector3s;
  164. begin
  165.   Result := GetVector3s(
  166.              GetCellHeight(MaxI(0, XI-1), ZI) - GetCellHeight(MinI(Width-1,  XI+1), ZI),
  167.              CellWidthScale+CellHeightScale,
  168.              GetCellHeight(XI, MaxI(0, ZI-1)) - GetCellHeight(XI, MinI(Height-1, ZI+1)));
  169.   FastNormalizeVector3s(Result);
  170. end;
  171. function TMap.GetHeight(X, Z: Single): Single;                // ToDo: Test with x=2048.0
  172. var k11, k12, k21, k22, xo, zo: Single; X1, Z1, X2, Z2: Integer;
  173. begin
  174.   Result := 0;
  175.   if (X < -Width  * FCellWidthScale  * 0.5 + epsilon) or (X > Width  * FCellWidthScale  * 0.5 - epsilon) or
  176.      (Z < -Height * FCellHeightScale * 0.5 + epsilon) or (Z > Height * FCellHeightScale * 0.5 - epsilon) then Exit;
  177.   X := X + Width  * FCellWidthScale  * 0.5;
  178.   Z := Z + Height * FCellHeightScale * 0.5;
  179. //  X1 := MinI(Width-1,  MaxI(0, Trunc(X * OneOverCellWidthScale )));     { TODO -cOptimization : Optimize }
  180. //  Z1 := MinI(Height-1, MaxI(0, Trunc(Z * OneOverCellHeightScale)));
  181.   X1 := Trunc(X * OneOverCellWidthScale );
  182.   Z1 := Trunc(Z * OneOverCellHeightScale);
  183.   X2 := MinI(Width-1,  X1 + 1);
  184.   Z2 := MinI(Height-1, Z1 + 1);
  185.   xo := (X - X1 * CellWidthScale) * OneOverCellWidthScale;
  186.   zo := (Z - Z1 * CellHeightScale) * OneOverCellHeightScale;
  187.   Assert((xo >= 0) and (zo >= 0));
  188.   if not ((xo <= 1) and (zo <= 1)) then begin
  189.     Assert((xo <= 1) and (zo <= 1));
  190.   end;
  191. //  CalcCoeffs(xo, zo, k11, k12, k21, k22);
  192. //  Result := GetCellHeight(X1, Z1) * K11 + GetCellHeight(X2, Z2) * K22 + GetCellHeight(X2, Z1) * K21 + GetCellHeight(X1, Z2) * K12;
  193.     k11 := GetCellHeight(X1, Z1);
  194.     k12 := GetCellHeight(X1, Z2);
  195.     k21 := GetCellHeight(X2, Z1);
  196.     k22 := GetCellHeight(X2, Z2);
  197.     Result := (k11 * (1-zo) + k12 * zo) * (1-xo) + (k21 * (1-zo) + k22 * zo) * xo;
  198. end;
  199. function TMap.GetNormal(X, Z: Single): TVector3s;
  200. //var k11, k12, k21, k22, xo, zo: Single; X1, Z1, X2, Z2: Integer;
  201. begin
  202.   Result := GetVector3s(0, 1, 0);
  203.   if (X < -Width  * FCellWidthScale  * 0.5) or (X >= Width  * FCellWidthScale  * 0.5) or
  204.      (Z < -Height * FCellHeightScale * 0.5) or (Z >= Height * FCellHeightScale * 0.5) then Exit;
  205. {  X := X + Width  * FCellWidthScale  * 0.5;
  206.   Z := Z + Height * FCellHeightScale * 0.5;
  207.   X1 := Trunc(X * OneOverCellWidthScale );
  208.   Z1 := Trunc(Z * OneOverCellHeightScale);
  209.   X2 := MinI(Width-1,  X1 + 1);
  210.   Z2 := MinI(Height-1, Z1 + 1);
  211.   xo := (X - X1 * CellWidthScale) * OneOverCellWidthScale;
  212.   zo := (Z - Z1 * CellHeightScale) * OneOverCellHeightScale;
  213.   CalcCoeffs(xo, zo, k11, k12, k21, k22);
  214.   Result.X := GetCellNormal(X1, Z1).X * K11 + GetCellNormal(X2, Z2).X * K22 + GetCellNormal(X2, Z1).X * K21 + GetCellNormal(X1, Z2).X * K12;
  215.   Result.Y := GetCellNormal(X1, Z1).Y * K11 + GetCellNormal(X2, Z2).Y * K22 + GetCellNormal(X2, Z1).Y * K21 + GetCellNormal(X1, Z2).Y * K12;
  216.   Result.Z := GetCellNormal(X1, Z1).Z * K11 + GetCellNormal(X2, Z2).Z * K22 + GetCellNormal(X2, Z1).Z * K21 + GetCellNormal(X1, Z2).Z * K12;
  217.  }
  218.   CrossProductVector3s(Result, GetVector3s(0, GetHeight(X, Z + CellHeightScale) - GetHeight(X, Z - CellHeightScale), CellHeightScale*2),
  219.                                GetVector3s(CellWidthScale*2, GetHeight(X+ CellWidthScale, Z) - GetHeight(X - CellWidthScale, Z), 0) );
  220. end;
  221. procedure TMap.ObtainCell(X, Z: Single; out CellX, CellZ: Integer);
  222. begin
  223.   CellX := Round((X + (Width -1) * CellWidthScale  * 0.5) / CellWidthScale);
  224.   CellZ := Round((Z + (Height-1) * CellHeightScale * 0.5) / CellHeightScale);
  225. end;
  226. function TMap.TraceRay(const Origin, Dir: TVector3s; out Point: TVector3s): Boolean;
  227. var i: Integer; Step: TVector3s;
  228. begin
  229.   Result := False;
  230.   if not IsReady then Exit;
  231.   Point := Origin;
  232.   ScaleVector3s(Step, Dir, MinS(FCellWidthScale, FCellHeightScale) * 0.5);
  233.   Result := True;
  234.   Point := Origin;
  235.   for i := 0 to 10000 do begin //Trunc(0.5 + SQRT2 * RenderPars.ZFar / Landscape.HeightMap.TileSize) do begin
  236.     if GetHeight(Point.X, Point.Z) >= Point.Y then begin
  237.       Exit;
  238.     end;
  239.     Point.X := Point.X + Step.X;
  240.     Point.Y := Point.Y + Step.Y;
  241.     Point.Z := Point.Z + Step.Z;
  242.   end;
  243.   Result := False;
  244. end;
  245. procedure TMap.ObtainRectHeights(const ARect: TRect; ABuf: Pointer);
  246. var DataBuf: PByteBuffer; i, StartI, Ofs, Size: Integer;
  247. begin
  248.   DataBuf := Data;
  249.   if DataBuf = nil then Exit;
  250.   Ofs  := MaxI(0, ARect.Left);
  251.   Size := MinI(Width-1, ARect.Right-1) - Ofs;
  252.   StartI := MaxI(0, ARect.Top);
  253.   for i := StartI to MinI(Height-1, ARect.Bottom-1) do
  254.     Move(DataBuf^[(i * Width + Ofs) * FElementSize], PByteBuffer(ABuf)^[((i - StartI) * (ARect.Right-ARect.Left+1) + ARect.Left) * FElementSize], Size);
  255. end;
  256. procedure TMap.SwapRectHeights(const ARect: TRect; ABuf: Pointer);
  257. var DataBuf, TempBuf: PByteBuffer; i, StartI, Ofs, Size: Integer;
  258. begin
  259.   DataBuf := Data;
  260.   if DataBuf = nil then Exit;
  261.   Ofs  := MaxI(0, ARect.Left);
  262.   Size := MinI(Width, ARect.Right) - Ofs;
  263.   if Size <= 0 then Exit;
  264.   StartI := MaxI(0, ARect.Top);
  265.   GetMem(TempBuf, Size * FElementSize);
  266.   for i := StartI to MinI(Height-1, ARect.Bottom-1) do begin
  267.     Move(DataBuf^[(i * Width + Ofs) * FElementSize], TempBuf^, Size);
  268.     Move(          PByteBuffer(ABuf)^[((i - StartI) * (ARect.Right-ARect.Left) + Ofs - ARect.Left) * FElementSize], DataBuf^[(i * Width + Ofs) * FElementSize], Size);
  269.     Move(TempBuf^, PByteBuffer(ABuf)^[((i - StartI) * (ARect.Right-ARect.Left) + Ofs - ARect.Left) * FElementSize], Size);
  270.   end;
  271.   FreeMem(TempBuf);
  272. end;
  273. procedure TMap.AddRectHeights(const ARect: TRect; ABuf: Pointer; Scale: Single);
  274. var DataBuf: Pointer; i, j, StartI, StartJ: Integer; Value: Single;
  275. begin
  276.   DataBuf := Data;
  277.   if DataBuf = nil then Exit;
  278.   StartI := MaxI(0, ARect.Left);
  279.   StartJ := MaxI(0, ARect.Top);
  280.   for j := StartJ to MinI(Height-1, ARect.Bottom-1) do
  281.     for i := StartI to MinI(Width-1, ARect.Right-1) do begin
  282.       Value := PSingleBuffer(ABuf)^[((j - StartJ) * (ARect.Right-ARect.Left+1) + ARect.Left)] * Scale;
  283.       case FElementSize of
  284.         1: Inc(PByteBuffer(DataBuf)^[(j * Width + StartI + i)], Round(Value));
  285.         2: Inc(PWordBuffer(DataBuf)^[(j * Width + StartI + i) * 2], Round(Value));
  286.         4: Inc(PDWordBuffer(DataBuf)^[(j * Width + StartI + i) * 4], Round(Value));
  287.       end;
  288.     end;
  289. end;
  290. { TMapEditOp }
  291. procedure TMapEditOp.DoApply;
  292. begin
  293.   if not Assigned(Buffer) then Exit;
  294.   Map.SwapRectHeights(GetRect(CellX - CursorSize div 2, CellZ - CursorSize div 2,
  295.                               CellX - CursorSize div 2 + CursorSize, CellZ - CursorSize div 2 + CursorSize), Buffer);
  296.   Map.SendMessage(TItemModifiedMsg.Create(Map), nil, [mfCore, mfBroadcast]);
  297. end;
  298. destructor TMapEditOp.Destroy;
  299. begin
  300.   if Assigned(Buffer) then FreeMem(Buffer);
  301.   inherited;
  302. end;
  303. end.