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

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @Abstract(CAST II Engine tile 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.  Unit contains tilemap implementation classes
  6. *)
  7. {$Include GDefines.inc}
  8. {$Include C2Defines.inc}
  9. unit C2TileMaps;
  10. interface
  11. uses
  12.   TextFile, 
  13.   BaseMsg, Models,
  14.   {$IFDEF EDITORMODE} BaseGraph, C2MapEditMsg, {$ENDIF}
  15.   SysUtils,
  16.   BaseTypes, Basics, Props, BaseClasses, Resources, Base3D,
  17.   C2Types, C2Maps, CAST2, C2Visual,
  18.   C2Land;
  19. const
  20.   MinLightsCount = 8;
  21.   MaxVisibleWidth = 64;
  22.   MaxVisibleHeight = 64;
  23. type
  24.   TTileMapLight = record
  25.     Light: TLight;                  // Light source
  26.     LocalPos: TVector3s;            // Position of the light source in tile map's frame
  27.   end;
  28.   TTileMap = class;
  29.   TTileMapEditOp = class(C2Maps.TMapEditOp)
  30.   private
  31.   public
  32.     // Inits the operation and returns True if it's valid and can be applied
  33.     function Init(AMap: TMap; ATileX, ATileY, ACursorSize, AValue: Integer; AAligned: Boolean): Boolean;
  34.   end;
  35.   TTileMapTesselator = class(C2Visual.TMappedTesselator)
  36.   private
  37.     // Params
  38.     FUVMapRes:   Resources.TUVMapResource;
  39. //    LightMaps: array of BaseTypes.PDWordBuffer;
  40.     Phase: Single;
  41.     RandomGen: Basics.TRandomGenerator;
  42.     // Lighting
  43.     Lights: array of TTileMapLight;                       // Active lights
  44.     LightsActive: Integer;
  45.     LightVectorSet: Boolean;
  46.     LightVector: TVector3s;
  47.   protected
  48.     AttSeed: Integer;
  49.     InvCellWidthScale, InvCellHeightScale: Single;
  50.     procedure InitLightMaps; virtual;
  51.     procedure ObtainVisibleRange(Camera: TCamera; var IMin, IMax, JMin, JMax: Integer); virtual;
  52.   public
  53.     constructor Create; override;
  54.     destructor Destroy; override;
  55.     procedure BeginLighting; override;
  56.     function CalculateLighting(const ALight: TLight; const ALightToItem: TMatrix4s): Boolean; override;
  57.     procedure SetMap(const Map: C2Maps.TMap); override;
  58.     procedure Init; override;
  59.     function GetMaxVertices: Integer; override;
  60.     function TraceRay(Origin, Dir: TVector3s; out ISecPoint: TVector3s): Boolean;
  61.     function ObtainTileAt(X, Y: Single; out TileX, TileY: Integer): Boolean; virtual;
  62.     function GetTileCoords(TileX, TileY: Integer): TVector3s; virtual;
  63.     function Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer; override;
  64.   end;
  65.   TFgTileMapTesselator = class(TTileMapTesselator)
  66.   protected
  67.     procedure InitLightMaps; override;
  68.   public
  69. //    procedure BeginLighting; override;
  70. //    procedure CalculateLighting(const ALight: TLight; const ALightToItem: TMatrix4s); override;
  71.     procedure Init; override;
  72.     function GetMaxVertices: Integer; override;
  73.     function Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer; override;
  74.   end;
  75.   TTileMap = class(TMappedItem)
  76.   private
  77.     {$IFDEF EDITORMODE}
  78.     function CalcTile(Cursor: C2MapEditMsg.TMapCursor; Camera: TCamera; out TileX, TileY: Integer): Boolean;
  79.     {$ENDIF}
  80.   protected
  81.     {$IFDEF EDITORMODE}
  82.     function DrawCursor(Cursor: C2MapEditMsg.TMapCursor; Camera: TCamera; Screen: TScreen): Boolean; override;
  83.     procedure ModifyBegin(Cursor: TMapCursor; Camera: TCamera); override;
  84.     procedure Modify(Cursor: TMapCursor; Camera: TCamera); override;
  85.     procedure ModifyEnd(Cursor: TMapCursor; Camera: TCamera); override;
  86.     {$ENDIF}
  87.     procedure ResolveLinks; override;
  88.   public
  89.     constructor Create(AManager: TItemsManager); override;
  90.     function GetTesselatorClass: CTesselator; override;
  91.     procedure AddProperties(const Result: Props.TProperties); override;
  92.     procedure SetProperties(Properties: Props.TProperties); override;
  93.     procedure Process(const DeltaT: Float); override;
  94.     function ObtainTileAt(X, Y: Single; out TileX, TileY: Integer): Boolean;
  95.     function ObtainTileAtScreen(ScreenX, ScreenY: Integer; Camera: TCamera; out TileX, TileY: Integer): Boolean;
  96.     function TraceMap(X, Y, DirX, DirY: Single; out TileX, TileY: Integer): Single;
  97.     procedure HandleMessage(const Msg: TMessage); override;
  98.   end;
  99.   TFgTileMap = class(TTileMap)
  100.   public
  101.     function GetTesselatorClass: CTesselator; override;
  102.     procedure HandleMessage(const Msg: TMessage); override;
  103.   end;
  104.   // Returns list of classes introduced by the unit
  105.   function GetUnitClassList: TClassArray;
  106. implementation
  107. function GetUnitClassList: TClassArray;
  108. begin
  109.   Result := GetClassList([TMap, TTileMap, TFgTileMap]);
  110. end;
  111. { TileMapTesselator }
  112. function TTileMapTesselator.TraceRay(Origin, Dir: TVector3s; out ISecPoint: TVector3s): Boolean;
  113. var d: Single;
  114. begin
  115.   Result := False;
  116.   if Abs(Dir.Z) > epsilon then begin
  117.     ISecPoint.Z := 0;
  118.     d := (Origin.Z - ISecPoint.Z) / Dir.Z;
  119.     ISecPoint.X := Origin.X - Dir.X * d;
  120.     ISecPoint.Y := Origin.Y - Dir.Y * d;
  121.     Result := True;
  122.   end;
  123. end;
  124. function TTileMapTesselator.ObtainTileAt(X, Y: Single; out TileX, TileY: Integer): Boolean;
  125. begin
  126.   Result := False;
  127.   if not Assigned(FMap) then Exit;
  128.   TileX := Round((FMap.Width)*0.5  + X / FMap.CellWidthScale)-1;
  129.   TileY := Round((FMap.Height)*0.5 - Y / FMap.CellHeightScale)-1;
  130.   Result := (TileX >= 0) and (TileY >= 0) and (TileX < FMap.Width) and (TileY < FMap.Height);
  131. end;
  132. function TTileMapTesselator.GetTileCoords(TileX, TileY: Integer): TVector3s;
  133. begin
  134.   Result := GetVector3s((TileX - (FMap.Width-1)*0.5) * FMap.CellWidthScale, ((FMap.Height-1)*0.5 - TileY) * FMap.CellHeightScale, 0);
  135. end;
  136. procedure TTileMapTesselator.InitLightMaps;
  137. begin
  138. //  SetLength(LightMaps, 1);
  139. //  ReallocMem(LightMaps[0], FMap.Width * FMap.Height * 4);
  140. end;
  141. procedure TTileMapTesselator.ObtainVisibleRange(Camera: TCamera; var IMin, IMax, JMin, JMax: Integer);
  142. var Origin, Vec: TVector3s; IMins, IMaxs, JMins, JMaxs: Single;
  143. function GetFrustumRay(XSign, YSign: Single): TVector3s;
  144. begin
  145.   Result.X := XSign * Cos(pi/2 - Camera.HFoV/2);
  146.   Result.Y := YSign * Cos(pi/2 - Camera.HFoV/2)/Camera.CurrentAspectRatio;
  147.   Result.Z := Sin(pi/2 - Camera.HFoV/2);
  148.   {  d := 0.5*Camera.ScreenWidth / Sin(Camera.HFoV*pi/180/2)*Cos(Camera.HFoV*pi/180/2);
  149.   Ray.X := 0.5*Camera.ScreenWidth;
  150.   Ray.Y := (0.5*Camera.ScreenHeight)*Camera.ScreenWidth/Camera.ScreenHeight/Camera.CurrentAspectRatio;
  151.   Ray.Z := d;}
  152.   Result := Transform3Vector3s(InvertMatrix3s(CutMatrix3s(Camera.ViewMatrix)), Result);
  153.   Result := Transform3Vector3s(InvertMatrix3s(CutMatrix3s(Item.Transform)), Result);
  154. end;
  155. begin
  156.   Origin := Transform4Vector33s(InvertMatrix4s(Item.Transform), Camera.GetAbsLocation);
  157.   IMin := 0;
  158.   JMin := 0;
  159.   IMax := FMap.Width-1;
  160.   JMax := FMap.Height-1;
  161.   if TraceRay(Origin, GetFrustumRay(1, 1), Vec) then begin
  162.     IMins :=  Vec.X; IMaxs :=  Vec.X;
  163.     JMins := -Vec.Y; JMaxs := -Vec.Y;
  164.     if TraceRay(Origin, GetFrustumRay(-1, 1), Vec) then begin
  165.       IMins := MinS(IMins,  Vec.X);
  166.       IMaxs := MaxS(IMaxs,  Vec.X);
  167.       JMins := MinS(JMins, -Vec.Y);
  168.       JMaxs := MaxS(JMaxs, -Vec.Y);
  169.       if TraceRay(Origin, GetFrustumRay(1, -1), Vec) then begin
  170.         IMins := MinS(IMins,  Vec.X);
  171.         IMaxs := MaxS(IMaxs,  Vec.X);
  172.         JMins := MinS(JMins, -Vec.Y);
  173.         JMaxs := MaxS(JMaxs, -Vec.Y);
  174.         if TraceRay(Origin, GetFrustumRay(-1, -1), Vec) then begin
  175.           IMins := MinS(IMins,  Vec.X);
  176.           IMaxs := MaxS(IMaxs,  Vec.X);
  177.           JMins := MinS(JMins, -Vec.Y);
  178.           JMaxs := MaxS(JMaxs, -Vec.Y);
  179.           IMin := Round(MinS(FMap.Width-1,  MaxS(0, FMap.Width*0.5  + IMins / FMap.CellWidthScale-2)));
  180.           IMax := Round(MinS(FMap.Width-1,  MaxS(0, FMap.Width*0.5  + IMaxs / FMap.CellWidthScale)));
  181.           JMin := Round(MinS(FMap.Height-1, MaxS(0, FMap.Height*0.5 + JMins / FMap.CellHeightScale-2)));
  182.           JMax := Round(MinS(FMap.Height-1, MaxS(0, FMap.Height*0.5 + JMaxs / FMap.CellHeightScale)));
  183.         end;
  184.       end;
  185.     end;
  186.   end;
  187. //  IMin := Round(IMins / FMap.CellWidthScale);
  188. //  JMin := Round(JMins / FMap.CellHeightScale);
  189. end;
  190. constructor TTileMapTesselator.Create;
  191. begin
  192.   inherited;
  193.   SetLength(Lights, MinLightsCount);
  194.   RandomGen := Basics.TRandomGenerator.Create;
  195.   Phase := Random*pi;
  196. end;
  197. destructor TTileMapTesselator.Destroy;
  198. begin
  199.   FreeAndNil(RandomGen);
  200.   Lights := nil;
  201.   inherited;
  202. end;
  203. procedure TTileMapTesselator.BeginLighting;
  204. begin
  205. //  FillDWord(LightMaps[0]^, FMap.Width * FMap.Height, 0*$20202020);
  206.   LightVectorSet := False;
  207.   LightsActive := 0;
  208. end;
  209. const BlinkFactor = 0.1;
  210. function TTileMapTesselator.CalculateLighting(const ALight: TLight; const ALightToItem: TMatrix4s): Boolean;
  211. begin
  212.   Result := True;
  213.   if Length(Lights) <= LightsActive then SetLength(Lights, Length(Lights)+1);
  214.   Lights[LightsActive].Light       := ALight;
  215.   Transform4Vector33s(Lights[LightsActive].LocalPos, ALightToItem, ZeroVector3s);
  216.   Inc(LightsActive);
  217.   if not LightVectorSet and (ALight.Kind = ltPoint) then begin
  218.     LightVector := ALight.GetAbsLocation;
  219.     LightVectorSet := True;
  220.   end;
  221. end;
  222. procedure TTileMapTesselator.SetMap(const Map: C2Maps.TMap);
  223. begin
  224.   FMap := Map;
  225. end;
  226. procedure TTileMapTesselator.Init;
  227. begin
  228.   inherited;
  229.   TesselationStatus[tbVertex].TesselatorType := ttDynamic;
  230.   if Assigned(FMap) then begin
  231.     OldWidth           := FMap.Width;
  232.     OldHeight          := FMap.Height;
  233.     
  234.     TotalVertices   := MaxI(0, (FMap.Width-1) * (FMap.Height-1) * 6);
  235.     TotalPrimitives := MaxI(0, (FMap.Width-1) * (FMap.Height-1) * 2);
  236.     InvCellWidthScale  := 1/FMap.CellWidthScale;
  237.     InvCellHeightScale := 1/FMap.CellHeightScale;
  238.     InitLightMaps;
  239.   end else begin
  240.     TotalVertices   := 0;
  241.     TotalPrimitives := 0;
  242.   end;
  243.   PrimitiveType    := ptTRIANGLELIST;
  244.   InitVertexFormat(GetVertexFormat(False, False, True, True, False, 0, [2]));
  245. end;
  246. function TTileMapTesselator.GetMaxVertices: Integer;
  247. begin
  248.   Result := (MaxVisibleWidth) * (MaxVisibleHeight) * 6;
  249.   if (FMap.Width <> OldWidth) or (FMap.Height <> OldHeight) then Init;
  250. end;
  251. const Radius = 5;
  252. function TTileMapTesselator.Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer;
  253. var
  254.   i, j, TileCount, Tile: Integer;
  255.   HalfWidth, HalfHeight: Single;
  256.   UVMap: TUVMap; UVMapLen: Integer;
  257.   IMin, IMax, JMin, JMax: Integer;
  258.   Ang: Single;
  259.   FormFactor: TVector3s;
  260. function GetLitColorD(const Point: TVector3s): TColor;
  261. var
  262.   i: Integer; v: TVector3s; Dist: Single; Color: TColor4s;
  263. begin
  264.   Color := GetColor4S(0, 0, 0, 0);
  265.   for i := 0 to LightsActive-1 do begin
  266.     SubVector3s(v, Point, Lights[i].LocalPos);
  267.     if SqrMagnitude(v) > Sqr(Lights[i].Light.Range) then Continue;
  268. //    Dist := v.Z / SqrMagnitude(v);
  269.     Dist := Sqrt(( Sqr(v.X*FormFactor.X) + Sqr(v.Y*FormFactor.Y) ) / Sqr(Lights[i].Light.Range * FormFactor.Z));
  270.     if Dist < 1 then AddVector4s(Color.RGBA, Color.RGBA, ScaleVector4s(Lights[i].Light.Diffuse.RGBA, 1-Dist));
  271.   end;
  272.   Result := GetColorFrom4s(Color);
  273. end;
  274. function GetLitColorS(const Point: TVector3s): TColor;
  275. var i: Integer; v, LightDir: TVector3s; Dist, Weight: Single;
  276. begin
  277.   Result.C := $FF808080;
  278.   if LightsActive = 0 then Exit;
  279.   Weight := 0;
  280.   LightDir := GetVector3s(0, 0, 0);
  281.   for i := 0 to LightsActive-1 do begin
  282.     SubVector3s(v, Point, Lights[i].LocalPos);
  283.     Dist := SqrMagnitude(v);
  284.     if Dist > Sqr(Lights[i].Light.Range) then Continue;
  285.     Dist :=
  286.     1 - Dist/Sqr(Lights[i].Light.Range);
  287. //    AddVector3s(LightDir, LightDir, NormalizeVector3s(GetVector3s(-v.X * Dist, -v.Y * Dist, Dist * (2+v.Z))));
  288.     AddVector3s(LightDir, LightDir, GetVector3s(-v.X * Dist, -v.Y * Dist, Dist * v.Z));
  289.     Weight := Weight + Dist;
  290.   end;
  291.   if Weight = 0 then Exit;
  292.   LightDir := NormalizeVector3s(GetVector3s(LightDir.X/Weight, LightDir.Y/Weight, 2+LightDir.Z/Weight));
  293.   Result := VectorToColor(ScaleVector3s(LightDir, 1+0*Result.R/255));
  294. end;
  295. var v: TVector3s;
  296. begin
  297.   Result := 0;
  298.   if not Assigned(FUVMapRes) or (FUVMapRes.TotalElements = 0) or
  299.      not Assigned(FMap) or (FMap.Width = 0) or (FMap.Height = 0) or (FMap.Data = nil) then Exit;
  300.   UVMap    := FUVMapRes.Data;
  301.   UVMapLen := FUVMapRes.TotalElements;
  302.   HalfWidth  := (FMap.Width-1)  * FMap.CellWidthScale  * 0.5;
  303.   HalfHeight := (FMap.Height-1) * FMap.CellHeightScale * 0.5;
  304.   // Form factor for torch light blinking imitation
  305.   Ang := (AttSeed+Phase)*DegToRad;
  306.   FormFactor.X := (1+BlinkFactor)+(BlinkFactor*Sin(Ang));
  307.   FormFactor.Y := (1+BlinkFactor)+(BlinkFactor*Cos(Ang));
  308.   FormFactor.Z := 1;//(1+BlinkFactor)+(BlinkFactor*Sin(((AttSeed+Phase)+90)*DegToRad*1));
  309.   TileCount := 0;
  310.   ObtainVisibleRange(Params.Camera, IMin, IMax, JMin, JMax);
  311.   if IMax - IMin > MaxVisibleWidth  then IMax := IMin + MaxVisibleWidth;
  312.   if JMax - JMin > MaxVisibleHeight then JMax := JMin + MaxVisibleHeight;
  313.   for i := IMin to IMax-1 do begin
  314.     for j := JMin to JMax-1 do begin
  315.       Tile := MinI(FMap[i, j], UVMapLen)-1;
  316.       if Tile >= 0 then begin
  317.         v := GetVector3s(i * FMap.CellWidthScale - HalfWidth, -j * FMap.CellHeightScale + HalfHeight, 0);
  318.         SetVertexDataC(v, TileCount*6, VBPTR);
  319.         SetVertexDataD(GetLitColorD(v), TileCount*6, VBPTR);
  320.         SetVertexDataS(GetLitColorS(v), TileCount*6, VBPTR);
  321.         SetVertexDataUV(UVMap^[Tile].U, UVMap^[Tile].V, TileCount*6, VBPTR);
  322.         v := GetVector3s((i+1) * FMap.CellWidthScale - HalfWidth, -(j+0) * FMap.CellHeightScale + HalfHeight, 0);
  323.         SetVertexDataC(v, TileCount*6+1, VBPTR);
  324.         SetVertexDataD(GetLitColorD(v), TileCount*6+1, VBPTR);
  325.         SetVertexDataS(GetLitColorS(v), TileCount*6+1, VBPTR);
  326.         SetVertexDataUV(UVMap^[Tile].U + UVMap^[Tile].W, UVMap^[Tile].V, TileCount*6+1, VBPTR);
  327.         SetVertexDataC(v, TileCount*6+4, VBPTR);
  328.         SetVertexDataD(GetLitColorD(v), TileCount*6+4, VBPTR);
  329.         SetVertexDataS(GetLitColorS(v), TileCount*6+4, VBPTR);
  330.         SetVertexDataUV(UVMap^[Tile].U + UVMap^[Tile].W, UVMap^[Tile].V, TileCount*6+4, VBPTR);
  331.         v := GetVector3s((i+0) * FMap.CellWidthScale - HalfWidth, -(j+1) * FMap.CellHeightScale + HalfHeight, 0);
  332.         SetVertexDataC(v, TileCount*6+2, VBPTR);
  333.         SetVertexDataD(GetLitColorD(v), TileCount*6+2, VBPTR);
  334.         SetVertexDataS(GetLitColorS(v), TileCount*6+2, VBPTR);
  335.         SetVertexDataUV(UVMap^[Tile].U, UVMap^[Tile].V + UVMap^[Tile].H, TileCount*6+2, VBPTR);
  336.         SetVertexDataC(v, TileCount*6+3, VBPTR);
  337.         SetVertexDataD(GetLitColorD(v), TileCount*6+3, VBPTR);
  338.         SetVertexDataS(GetLitColorS(v), TileCount*6+3, VBPTR);
  339.         SetVertexDataUV(UVMap^[Tile].U, UVMap^[Tile].V + UVMap^[Tile].H, TileCount*6+3, VBPTR);
  340.         v := GetVector3s((i+1) * FMap.CellWidthScale - HalfWidth, -(j+1) * FMap.CellHeightScale + HalfHeight, 0);
  341.         SetVertexDataC(v, TileCount*6+5, VBPTR);
  342.         SetVertexDataD(GetLitColorD(v), TileCount*6+5, VBPTR);
  343.         SetVertexDataS(GetLitColorS(v), TileCount*6+5, VBPTR);
  344.         SetVertexDataUV(UVMap^[Tile].U + UVMap^[Tile].W, UVMap^[Tile].V + UVMap^[Tile].H, TileCount*6+5, VBPTR);
  345.         Inc(TileCount);
  346.       end;
  347.     end;
  348.   end;
  349. //  {$IFDEF LOGGING} Log.Log(Format('Tiles rendered: %D', [TileCount])); {$ENDIF}
  350.   TesselationStatus[tbVertex].Status := tsChanged;
  351.   Result            := TileCount*6;
  352.   TotalPrimitives   := TileCount*2;
  353.   TotalVertices     := Result;
  354.   LastTotalVertices := TotalVertices;
  355. end;
  356. { TFgTileMapTesselator }
  357. procedure TFgTileMapTesselator.InitLightMaps;
  358. begin
  359. //  SetLength(LightMaps, 2);
  360. //  ReallocMem(LightMaps[0], FMap.Width * FMap.Height * 4);
  361. //  ReallocMem(LightMaps[1], FMap.Width * FMap.Height * 4);
  362. end;
  363. procedure TFgTileMapTesselator.Init;
  364. begin
  365.   inherited;
  366.   if Assigned(FMap) then begin
  367.     TotalVertices   := MaxI(0, (FMap.Width-1) * (FMap.Height-1) * 6)*2;
  368.     TotalPrimitives := MaxI(0, (FMap.Width-1) * (FMap.Height-1) * 2)*2;
  369.   end else begin
  370.     TotalVertices   := 0;
  371.     TotalPrimitives := 0;
  372.   end;
  373.   PrimitiveType    := ptTRIANGLELIST;                                            // TODO -cOptimization : Switch to strips
  374.   InitVertexFormat(GetVertexFormat(False, False, True, True, False, 0, [2]));
  375. end;
  376. function TFgTileMapTesselator.GetMaxVertices: Integer;
  377. begin
  378.   Result := (MaxVisibleWidth) * (MaxVisibleHeight) * 6 * 2;
  379.   if (FMap.Width <> OldWidth) or (FMap.Height <> OldHeight) then Init;
  380. end;
  381. function TFgTileMapTesselator.Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer;
  382. var
  383.   i, j, QuadCount, Tile: Integer;
  384.   BlockExists: Boolean;
  385.   HalfWidth, HalfHeight, Y: Single;
  386.   UVMap: TUVMap; UVMapLen: Integer;
  387.   IMin, IMax, JMin, JMax: Integer;
  388.   Ang: Single;
  389.   FormFactor: TVector3s;
  390.   function GetLitColorD(const Point: TVector3s): TColor;
  391.   var
  392.     i: Integer; v: TVector3s; Dist: Single; Color: TColor4s;
  393.   begin
  394.     Color := GetColor4S(0, 0, 0, 0);
  395.     for i := 0 to LightsActive-1 do begin
  396.       SubVector3s(v, Point, Lights[i].LocalPos);
  397.       if SqrMagnitude(v) > Sqr(Lights[i].Light.Range) then Continue;
  398. //      Dist := v.Z / SqrMagnitude(v);
  399.       Dist := Sqrt(( Sqr(v.X*FormFactor.X) + Sqr(v.Y*FormFactor.Y) ) / Sqr(Lights[i].Light.Range * FormFactor.Z));
  400.       if Dist < 1 then AddVector4s(Color.RGBA, Color.RGBA, ScaleVector4s(Lights[i].Light.Diffuse.RGBA, 0.2*(1-Dist)));
  401.   //    v := NormalizeVector3s(v);
  402.     end;
  403.     Result := GetColorFrom4s(Color);
  404.   end;
  405.   function GetLitColorS(const Point: TVector3s): TColor;
  406.   var i, MinI: Integer; v: TVector3s; MinDist, Dist: Single;
  407.   begin
  408.     Result.C := $FF808080;
  409.     MinI := -1;
  410.     for i := 0 to LightsActive-1 do begin
  411.       Dist := SqrMagnitude(SubVector3s(Point, Lights[i].LocalPos));
  412.       if Dist > Sqr(Lights[i].Light.Range) then Continue;
  413.       if (MinI = -1) or (Dist < MinDist) then begin
  414.         MinDist := Dist;
  415.         MinI := i;
  416.       end;
  417.     end;
  418.     if MinI = -1 then Exit;
  419.     SubVector3s(v, Point, Lights[MinI].LocalPos);
  420.     v := NormalizeVector3s(GetVector3s(-v.X, v.Y, 1));
  421.     Result := VectorToColor(ScaleVector3s(v, 1+0*Result.R/255));
  422.   end;
  423.   function GetLitColorTopD(Point: TVector3s): TColor;
  424.   var
  425.     i: Integer; v: TVector3s; Dist: Single; Color: TColor4s;
  426.   begin
  427.     Color := GetColor4S(0, 0, 0, 0);
  428.     for i := 0 to LightsActive-1 do if Lights[i].LocalPos.Y - Point.Y > 0 then begin
  429.       SubVector3s(v, Point, Lights[i].LocalPos);
  430.       if SqrMagnitude(v) > Sqr(Lights[i].Light.Range) then Continue;
  431.   //    Dist := v.Z / SqrMagnitude(v);
  432.       Dist := Sqrt(( Sqr(v.X*FormFactor.X) + Sqr(v.Y*FormFactor.Y) ) / Sqr(Lights[i].Light.Range * FormFactor.Z));
  433.   //    Dist := 1+v.Y/SqrMagnitude(v);
  434.       if Dist < 1 then AddVector4s(Color.RGBA, Color.RGBA, ScaleVector4s(Lights[i].Light.Diffuse.RGBA, 1-Dist));
  435.   //    v := NormalizeVector3s(v);
  436.     end;
  437.     Result := GetColorFrom4s(Color);
  438.   end;
  439.   function GetLitColorTopS(const Point: TVector3s): TColor;
  440.   var i, MinI: Integer; v: TVector3s; MinDist, Dist: Single;
  441.   begin
  442.     Result.C := $FF808080;
  443.     MinI := -1;
  444.     for i := 0 to LightsActive-1 do if Lights[i].LocalPos.Y - Point.Y > 0 then begin
  445.       Dist := SqrMagnitude(SubVector3s(Point, Lights[i].LocalPos));
  446.       if Dist > Sqr(Lights[i].Light.Range) then Continue;
  447.       if (MinI = -1) or (Dist < MinDist) then begin
  448.         MinDist := Dist;
  449.         MinI := i;
  450.       end;
  451.     end;
  452.     if MinI = -1 then Exit;
  453.     SubVector3s(v, Point, Lights[MinI].LocalPos);
  454.     v := NormalizeVector3s(GetVector3s(-v.X, -v.y, 0.5));
  455.     Result := VectorToColor(ScaleVector3s(v, 1+0*Result.R/255));
  456.   end;
  457. var v: TVector3s;
  458. begin
  459.   Result := 0;
  460.   if not Assigned(FUVMapRes) or (FUVMapRes.TotalElements = 0) or
  461.      not Assigned(FMap) or (FMap.Width = 0) or (FMap.Height = 0) or (FMap.Data = nil) then Exit;
  462.   UVMap    := FUVMapRes.Data;
  463.   UVMapLen := FUVMapRes.TotalElements;
  464.   HalfWidth  := (FMap.Width-1)  * FMap.CellWidthScale  * 0.5;
  465.   HalfHeight := (FMap.Height-1) * FMap.CellHeightScale * 0.5;
  466.   // Form factor for torch light blinking imitation
  467.   Ang := (AttSeed+Phase)*DegToRad;
  468.   FormFactor.X := (1+BlinkFactor)+(BlinkFactor*Sin(Ang));
  469.   FormFactor.Y := (1+BlinkFactor)+(BlinkFactor*Cos(Ang));
  470.   FormFactor.Z := 1;//(1+BlinkFactor)+(BlinkFactor*Sin(((AttSeed+Phase)+90)*DegToRad*1));
  471.   ObtainVisibleRange(Params.Camera, IMin, IMax, JMin, JMax);
  472.   if IMax - IMin > MaxVisibleWidth  then IMax := IMin + MaxVisibleWidth;
  473.   if JMax - JMin > MaxVisibleHeight then JMax := JMin + MaxVisibleHeight;
  474.   QuadCount := 0;
  475.   for i := IMin to IMax-1 do begin
  476.     BlockExists := JMin <> 0;
  477.     for j := JMin to JMax-1 do begin
  478.       Tile := MinI(FMap[i, j]*3, UVMapLen)-3;
  479.       if Tile >= 0 then begin
  480.         if not BlockExists then begin                                                // Top surface
  481.           Y := -j * FMap.CellHeightScale + HalfHeight;
  482.           v := GetVector3s(i * FMap.CellWidthScale - HalfWidth, Y, 0);
  483.           SetVertexDataC(v, QuadCount*6, VBPTR);
  484.           SetVertexDataD(GetLitColorTopD(v), QuadCount*6, VBPTR);
  485.           SetVertexDataS(GetLitColorTopS(v), QuadCount*6, VBPTR);
  486.           SetVertexDataUV(UVMap^[Tile + 1].U, UVMap^[Tile + 1].V, QuadCount*6, VBPTR);
  487.           v := GetVector3s((i+1) * FMap.CellWidthScale - HalfWidth, Y, 0);
  488.           SetVertexDataC(v, QuadCount*6+1, VBPTR);
  489.           SetVertexDataD(GetLitColorTopD(v), QuadCount*6+1, VBPTR);
  490.           SetVertexDataS(GetLitColorTopS(v), QuadCount*6+1, VBPTR);
  491.           SetVertexDataUV(UVMap^[Tile + 1].U + UVMap^[Tile + 1].W, UVMap^[Tile + 1].V, QuadCount*6+1, VBPTR);
  492.           SetVertexDataC(v, QuadCount*6+4, VBPTR);
  493.           SetVertexDataD(GetLitColorTopD(v), QuadCount*6+4, VBPTR);
  494.           SetVertexDataS(GetLitColorTopS(v), QuadCount*6+4, VBPTR);
  495.           SetVertexDataUV(UVMap^[Tile + 1].U + UVMap^[Tile + 1].W, UVMap^[Tile + 1].V, QuadCount*6+4, VBPTR);
  496.           v := GetVector3s((i+0) * FMap.CellWidthScale - HalfWidth, Y, -FMap.DepthScale);
  497.           SetVertexDataC(v, QuadCount*6+2, VBPTR);
  498.           SetVertexDataD(GetLitColorTopD(v), QuadCount*6+2, VBPTR);
  499.           SetVertexDataS(GetLitColorTopS(v), QuadCount*6+2, VBPTR);
  500.           SetVertexDataUV(UVMap^[Tile + 1].U, UVMap^[Tile + 1].V + UVMap^[Tile + 1].H, QuadCount*6+2, VBPTR);
  501.           SetVertexDataC(v, QuadCount*6+3, VBPTR);
  502.           SetVertexDataD(GetLitColorTopD(v), QuadCount*6+3, VBPTR);
  503.           SetVertexDataS(GetLitColorTopS(v), QuadCount*6+3, VBPTR);
  504.           SetVertexDataUV(UVMap^[Tile + 1].U, UVMap^[Tile + 1].V + UVMap^[Tile + 1].H, QuadCount*6+3, VBPTR);
  505.           v := GetVector3s((i+1) * FMap.CellWidthScale - HalfWidth, Y, -FMap.DepthScale);
  506.           SetVertexDataC(v, QuadCount*6+5, VBPTR);
  507.           SetVertexDataD(GetLitColorTopD(v), QuadCount*6+5, VBPTR);
  508.           SetVertexDataS(GetLitColorTopS(v), QuadCount*6+5, VBPTR);
  509.           SetVertexDataUV(UVMap^[Tile + 1].U + UVMap^[Tile + 1].W, UVMap^[Tile + 1].V + UVMap^[Tile + 1].H, QuadCount*6+5, VBPTR);
  510.           Inc(QuadCount);
  511.         end;
  512. //        Color := $FF808080;
  513. {         or MinI($FF, (Sqr(Round(IMin * FMap.CellWidthScale  - i * FMap.CellWidthScale)) +
  514.                                          Sqr(Round(JMin * FMap.CellHeightScale - j * FMap.CellHeightScale))
  515.         ));}
  516.         v := GetVector3s(i * FMap.CellWidthScale - HalfWidth, -j * FMap.CellHeightScale + HalfHeight, -FMap.DepthScale);
  517.         SetVertexDataC(v, QuadCount*6, VBPTR);
  518.         SetVertexDataD(GetLitColorD(v), QuadCount*6, VBPTR);
  519.         SetVertexDataS(GetLitColorS(v), QuadCount*6, VBPTR);
  520.         SetVertexDataUV(UVMap^[Tile].U, UVMap^[Tile].V, QuadCount*6, VBPTR);
  521.         v := GetVector3s((i+1) * FMap.CellWidthScale - HalfWidth, -(j+0) * FMap.CellHeightScale + HalfHeight, -FMap.DepthScale);
  522.         SetVertexDataC(v, QuadCount*6+1, VBPTR);
  523.         SetVertexDataD(GetLitColorD(v), QuadCount*6+1, VBPTR);
  524.         SetVertexDataS(GetLitColorS(v), QuadCount*6+1, VBPTR);
  525.         SetVertexDataUV(UVMap^[Tile].U + UVMap^[Tile].W, UVMap^[Tile].V, QuadCount*6+1, VBPTR);
  526.         SetVertexDataC(v, QuadCount*6+4, VBPTR);
  527.         SetVertexDataD(GetLitColorD(v), QuadCount*6+4, VBPTR);
  528.         SetVertexDataS(GetLitColorS(v), QuadCount*6+4, VBPTR);
  529.         SetVertexDataUV(UVMap^[Tile].U + UVMap^[Tile].W, UVMap^[Tile].V, QuadCount*6+4, VBPTR);
  530.         v := GetVector3s((i+0) * FMap.CellWidthScale - HalfWidth, -(j+1) * FMap.CellHeightScale + HalfHeight, -FMap.DepthScale);
  531.         SetVertexDataC(v, QuadCount*6+2, VBPTR);
  532.         SetVertexDataD(GetLitColorD(v), QuadCount*6+2, VBPTR);
  533.         SetVertexDataS(GetLitColorS(v), QuadCount*6+2, VBPTR);
  534.         SetVertexDataUV(UVMap^[Tile].U, UVMap^[Tile].V + UVMap^[Tile].H, QuadCount*6+2, VBPTR);
  535.         SetVertexDataC(v, QuadCount*6+3, VBPTR);
  536.         SetVertexDataD(GetLitColorD(v), QuadCount*6+3, VBPTR);
  537.         SetVertexDataS(GetLitColorS(v), QuadCount*6+3, VBPTR);
  538.         SetVertexDataUV(UVMap^[Tile].U, UVMap^[Tile].V + UVMap^[Tile].H, QuadCount*6+3, VBPTR);
  539.         v := GetVector3s((i+1) * FMap.CellWidthScale - HalfWidth, -(j+1) * FMap.CellHeightScale + HalfHeight, -FMap.DepthScale);
  540.         SetVertexDataC(v, QuadCount*6+5, VBPTR);
  541.         SetVertexDataD(GetLitColorD(v), QuadCount*6+5, VBPTR);
  542.         SetVertexDataS(GetLitColorS(v), QuadCount*6+5, VBPTR);
  543.         SetVertexDataUV(UVMap^[Tile].U + UVMap^[Tile].W, UVMap^[Tile].V + UVMap^[Tile].H, QuadCount*6+5, VBPTR);
  544.         Inc(QuadCount);
  545.         BlockExists := True;
  546.       end else BlockExists := False;
  547.     end;
  548.   end;
  549. //  {$IFDEF LOGGING} Log.Log(Format('Quads rendered: %D', [QuadCount])); {$ENDIF}
  550.   TesselationStatus[tbVertex].Status := tsChanged;
  551.   Result            := QuadCount*6;
  552.   TotalPrimitives   := QuadCount*2;
  553.   TotalVertices     := Result;
  554.   LastTotalVertices := TotalVertices;
  555. end;
  556. { TTileMap }
  557. const UVMapPropName = 'UV Map';
  558. {$IFDEF EDITORMODE}
  559. function TTileMap.CalcTile(Cursor: TMapCursor; Camera: TCamera; out TileX, TileY: Integer): Boolean;
  560. // Returns true if cursor points to a valid tile
  561. var Point: TVector3s;
  562. begin
  563.   Result := Assigned(CurrentTesselator) and
  564.             (CurrentTesselator as TTileMapTesselator).TraceRay(Transform4Vector33s(InvertMatrix4s(Transform), Camera.GetAbsLocation),
  565.                                                         Camera.GetPickRayInWorld(Cursor.MouseX, Cursor.MouseY), Point) and
  566.             (CurrentTesselator as TTileMapTesselator).ObtainTileAt(Point.X, Point.Y, TileX, TileY);
  567. end;
  568. function TTileMap.DrawCursor(Cursor: TMapCursor; Camera: TCamera; Screen: TScreen): Boolean;
  569. var TileX, TileY, i, j, CursorSize: Integer; Point: TVector3s;
  570. begin
  571.   Result := False;
  572.   if not CalcTile(Cursor, Camera, TileX, TileY) then Exit;
  573.   CursorSize := ClampI(Cursor.Params.GetAsInteger('Size'), 1, MaxCursorSize);
  574.   for i := MinI(FMap.Width-1, MaxI(0, TileX - CursorSize div 2)) to MinI(FMap.Width-1, MaxI(0, TileX - CursorSize div 2 + CursorSize-1)) do
  575.     for j := MinI(FMap.Height-1, MaxI(0, TileY - CursorSize div 2)) to MinI(FMap.Height-1, MaxI(0, TileY - CursorSize div 2 + CursorSize-1)) do
  576.       with (CurrentTesselator as TTileMapTesselator) do begin
  577.         Point := Transform4Vector33s(Transform, GetTileCoords(i, j));
  578.         Screen.MoveToVec(Camera.Project(Point).xyz);
  579.         Point := Transform4Vector33s(Transform, GetTileCoords(i+1, j));
  580.         Screen.LineToVec(Camera.Project(Point).xyz);
  581.         Point := Transform4Vector33s(Transform, GetTileCoords(i+1, j+1));
  582.         Screen.LineToVec(Camera.Project(Point).xyz);
  583.         Point := Transform4Vector33s(Transform, GetTileCoords(i, j+1));
  584.         Screen.LineToVec(Camera.Project(Point).xyz);
  585.         Point := Transform4Vector33s(Transform, GetTileCoords(i, j));
  586.         Screen.LineToVec(Camera.Project(Point).xyz);
  587.     //    Screen.Bar(Transformed.X, Transformed.Y, Transformed.X+10, Transformed.Y+10);
  588.       end;
  589.   Result := True;
  590. end;
  591. procedure TTileMap.ModifyBegin(Cursor: TMapCursor; Camera: TCamera);
  592. begin
  593.   Modify(Cursor, Camera);
  594. end;
  595. procedure TTileMap.Modify(Cursor: TMapCursor; Camera: TCamera);
  596. var Tilex, TileY: Integer; Op: TTileMapEditOp;
  597. begin
  598.   if (Cursor.MouseX = Cursor.LastEditMouseX) and (Cursor.MouseY = Cursor.LastEditMouseY) then Exit;
  599.   if not CalcTile(Cursor, Camera, TileX, TileY) then Exit;
  600.   if (FMap as THeightMap).Data = nil then Exit;
  601.   Op := TTileMapEditOp.Create;
  602.   if Op.Init(FMap, TileX, TileY, ClampI(Cursor.Params.GetAsInteger('Size'), 1, MaxCursorSize), Cursor.Value, Cursor.Aligned) then begin
  603.     Cursor.Operation := Op;
  604.   end else Op.Free;
  605. end;
  606. procedure TTileMap.ModifyEnd(Cursor: TMapCursor; Camera: TCamera);
  607. begin
  608. //  Modify(Cursor, Camera);
  609. end;
  610. {$ENDIF}
  611. procedure TTileMap.ResolveLinks;
  612. var Item: TItem;
  613. begin
  614.   inherited;
  615.   if CurrentTesselator is TTileMapTesselator then begin
  616.     ResolveLink(UVMapPropName, Item);
  617.     if Assigned(Item) then begin
  618.       (CurrentTesselator as TTileMapTesselator).FUVMapRes := (Item as TUVMapResource);
  619.       CurrentTesselator.Init;
  620.       if Assigned((CurrentTesselator as TTileMapTesselator).FMap) then with (CurrentTesselator as TTileMapTesselator).FMap do begin
  621.         BoundingBox.P1 := GetVector3s(-Width * CellWidthScale * 0.5, -Height * CellHeightScale * 0.5, -DepthScale);
  622.         BoundingBox.P2 := GetVector3s( Width * CellWidthScale * 0.5,  Height * CellHeightScale * 0.5,  0);
  623.       end else begin
  624.         BoundingBox.P1 := GetVector3s(0, 0, 0);
  625.         BoundingBox.P2 := GetVector3s(0, 0, 0);
  626.       end;
  627.     end;
  628.   end;
  629. end;
  630. constructor TTileMap.Create(AManager: TItemsManager);
  631. begin
  632.   FCustomLighting := True;
  633.   inherited;
  634. end;
  635. function TTileMap.GetTesselatorClass: CTesselator; begin Result := TTileMapTesselator; end;
  636. procedure TTileMap.AddProperties(const Result: Props.TProperties);
  637. begin
  638.   inherited;
  639.   if Assigned(Result) then begin
  640.   end;
  641.   AddItemLink(Result, UVMapPropName, [], 'TUVMapResource');
  642. end;
  643. procedure TTileMap.SetProperties(Properties: Props.TProperties);
  644. begin
  645.   inherited;
  646.   if Properties.Valid(UVMapPropName) then SetLinkProperty(UVMapPropName, Properties[UVMapPropName]);
  647.   ResolveLinks;
  648. end;
  649. procedure TTileMap.HandleMessage(const Msg: TMessage);
  650. begin
  651.   inherited;
  652.   {$IFDEF EDITORMODE}
  653. {  if Msg.ClassType = TMapDrawCursorMsg then with TMapDrawCursorMsg(Msg) do DrawCursor(Cursor, Cursor.Camera, Cursor.Screen);
  654.   if (Msg.ClassType = TMapModifyBeginMsg) or (Msg.ClassType = TMapModifyMsg) then with TMapEditorMessage(Msg) do Modify(Cursor, Cursor.Camera);}
  655.   if Msg.ClassType = TRequestMapEditVisuals then with TRequestMapEditVisuals(Msg) do begin
  656.     if Assigned(CurTechnique) and Assigned(CurTechnique.Passes[0]) then
  657.       CurTechnique.Passes[0].ObtainLinkedItemName('Stage #0Texture', Cursor.MainTextureName);
  658.     ObtainLinkedItemName(UVMapPropName, Cursor.UVMapName);
  659.     Cursor.UVMapStep := 1;
  660.   end;
  661.   {$ENDIF}
  662. end;
  663. function TTileMap.ObtainTileAt(X, Y: Single; out TileX, TileY: Integer): Boolean;
  664. begin
  665.   Result := (CurrentTesselator is TTileMapTesselator) and TTileMapTesselator(CurrentTesselator).ObtainTileAt(X, Y, TileX, TileY);
  666. end;
  667. function TTileMap.ObtainTileAtScreen(ScreenX, ScreenY: Integer; Camera: TCamera; out TileX, TileY: Integer): Boolean;
  668. var Point: TVector3s;
  669. begin
  670.   Result := Assigned(CurrentTesselator) and
  671.             (CurrentTesselator as TTileMapTesselator).TraceRay(Transform4Vector33s(InvertMatrix4s(Transform), Camera.GetAbsLocation),
  672.                                                         Camera.GetPickRayInWorld(ScreenX, ScreenY), Point) and
  673.             (CurrentTesselator as TTileMapTesselator).ObtainTileAt(Point.X, Point.Y, TileX, TileY);
  674. end;
  675. function TTileMap.TraceMap(X, Y, DirX, DirY: Single; out TileX, TileY: Integer): Single;
  676. // Traces ray to next tile and returns squared distance to it
  677. var Ofs: TVector3s;
  678. begin
  679.   Result := 0;
  680.   if not (CurrentTesselator is TTileMapTesselator) or not TTileMapTesselator(CurrentTesselator).ObtainTileAt(X, Y, TileX, TileY) then Exit;
  681.   if Sqr(DirX) + Sqr(DirY) < epsilon then Exit;
  682.   Ofs := TTileMapTesselator(CurrentTesselator).GetTileCoords(TileX, TileY);
  683.   Ofs.X := X - Ofs.X;
  684.   Ofs.Y := Ofs.Y - Y;
  685.   Assert((Ofs.X >= 0) and (Ofs.Y >= 0), Format('%F / %F', [Ofs.X, Ofs.Y]));
  686.   if (Abs(DirX) < epsilon) then begin                    // up/down case
  687.     Inc(TileY, 1-Ord(DirY > 0)*2);
  688.     if DirY > 0 then Result := Ofs.Y else Result := FMap.CellHeightScale - Ofs.Y;
  689.   end;
  690.   if (Abs(DirY) < epsilon) then begin                    // left/cight case
  691.     Inc(TileX, Ord(DirX > 0)*2-1);
  692.     if DirX > 0 then Result := Ofs.X else Result := FMap.CellWidthScale - Ofs.X;
  693.   end;
  694. {  TileX := Round((FMap.Width)*0.5  + X / FMap.CellWidthScale)-1;
  695.   TileY := Round((FMap.Height)*0.5 - Y / FMap.CellHeightScale)-1;
  696.   Result := (TileX >= 0) and (TileY >= 0) and (TileX < FMap.Width) and (TileY < FMap.Height);}
  697. end;
  698. procedure TTileMap.Process(const DeltaT: Float);
  699. begin
  700.   inherited;
  701.   if not (CurrentTesselator is TTileMapTesselator) then Exit;
  702.   Inc(TTileMapTesselator(CurrentTesselator).AttSeed, 30+Random(30));
  703. //  TTileMapTesselator(CurrentTesselator).RandomGen.InitSequence(1, Round(TimeProcessed));
  704. end;
  705. { TFgTileMap }
  706. function TFgTileMap.GetTesselatorClass: CTesselator; begin Result := TFgTileMapTesselator; end;
  707. procedure TFgTileMap.HandleMessage(const Msg: TMessage);
  708. begin
  709.   inherited;
  710.   {$IFDEF EDITORMODE}
  711.   if Msg.ClassType = TRequestMapEditVisuals then with TRequestMapEditVisuals(Msg) do Cursor.UVMapStep := 3;
  712.   {$ENDIF}
  713. end;
  714. { TTileMapEditOp }
  715. function TTileMapEditOp.Init(AMap: TMap; ATileX, ATileY, ACursorSize, AValue: Integer; AAligned: Boolean): Boolean;
  716. var i, j, Value1, Value2, StartI, StartJ: Integer;
  717.   function GetValue(LX, LY: Integer): Integer;
  718.   begin
  719.     if AAligned then
  720.       Result := AValue + (LX mod CursorSize) + (LY mod CursorSize) * CursorSize else
  721.         Result := Value2;
  722.   end;
  723. begin
  724.   Result := False;
  725.   if (ACursorSize = 0) or not Assigned(AMap) then Exit;
  726.   Map        := AMap;
  727.   CellX      := ATileX;
  728.   CellZ      := ATileY;
  729.   CursorSize := ACursorSize;
  730.   GetMem(Buffer, CursorSize * CursorSize * Map.ElementSize);
  731.   Result := True;
  732.   Value1 := AValue;
  733.   StartI := MaxI(0, CellX - CursorSize div 2);
  734.   StartJ := MaxI(0, CellZ - CursorSize div 2);
  735.   for j := StartJ to MinI(Map.Height-1, CellZ - CursorSize div 2 + CursorSize-1) do begin
  736.     Value2 := Value1;
  737.     for i := StartI to MinI(Map.Width-1, CellX - CursorSize div 2 + CursorSize-1) do begin
  738.       case Map.ElementSize of
  739.         1:  PByteBuffer(Buffer)^[(j-StartJ)* CursorSize + i - StartI] := Byte(GetValue(i, j));
  740.         2:  PWordBuffer(Buffer)^[(j-StartJ)* CursorSize + i - StartI] := Word(GetValue(i, j));
  741.         4: PDWordBuffer(Buffer)^[(j-StartJ)* CursorSize + i - StartI] := Cardinal(GetValue(i, j));
  742.       end;
  743. //      Inc(Value2);
  744.     end;
  745.     Inc(Value1, CursorSize);
  746.   end;
  747. end;
  748. begin
  749.   GlobalClassList.Add('C2TileMaps', GetUnitClassList);
  750. end.