Ignore:
Timestamp:
Mar 26, 2021, 2:16:04 PM (3 years ago)
Author:
chronos
Message:
  • Modified: Reworker IsoEngine unit to support multiple iso maps with different tile sizes.
  • Modified: Changing tile size in main windows map doesn't affect other tile drawing on panel and in other windows like help window.
  • Modified: Optimized tile size switching. Graphic assets needed for given tile size is prepared only once. Then switching between them is just about changing references to objects and redrawing.
  • Modified: Code cleanup.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/LocalPlayer/IsoEngine.pas

    r327 r330  
    55
    66uses
    7   Protocol, ClientTools, ScreenTools, Tribes, {$IFNDEF SCR}Term, {$ENDIF}
     7  Protocol, ClientTools, ScreenTools, Tribes,
    88  LCLIntf, LCLType, SysUtils, Classes, Graphics, UPixelPointer, UGraphicSet;
     9
     10const
     11  TerrainIconLines = 21;
     12  TerrainIconCols = 9;
    913
    1014type
    1115  TInitEnemyModelEvent = function(emix: integer): boolean;
     16  TTileSize = (tsSmall, tsMedium, tsBig);
     17
     18  TTerrainSpriteSize = array of TRect;
     19
     20  { TCitiesPictures }
     21
     22  TCitiesPictures = class
     23    Pictures: array [2..3, 0..3] of TCityPicture;
     24    procedure Prepare(HGrCities: TGraphicSet; xxt, yyt: Integer);
     25  end;
    1226
    1327  { TIsoMap }
     
    1529  TIsoMap = class
    1630  private
     31    FTileSize: TTileSize;
    1732    const
    1833      Dirx: array [0..7] of Integer = (1, 2, 1, 0, -1, -2, -1, 0);
     
    2136    function IsShoreTile(Loc: integer): boolean;
    2237    procedure MakeDark(Line: PPixelPointer; Length: Integer);
     38    procedure SetTileSize(AValue: TTileSize);
    2339    procedure ShadeOutside(x0, y0, Width, Height, xm, ym: integer);
    2440  protected
     
    3652    DataCanvas: TCanvas;
    3753    MaskCanvas: TCanvas;
     54    LandPatch: TBitmap;
     55    OceanPatch: TBitmap;
     56    Borders: TBitmap;
     57    BordersOK: PInteger;
     58    CitiesPictures: TCitiesPictures;
    3859    function Connection4(Loc, Mask, Value: integer): integer;
    3960    function Connection8(Loc, Mask: integer): integer;
     
    4869    procedure Sprite(HGr: TGraphicSet; xDst, yDst, Width, Height, xGr, yGr: integer);
    4970    procedure TSprite(xDst, yDst, grix: integer; PureBlack: boolean = false);
     71    procedure ApplyTileSize(ATileSize: TTileSize);
    5072  public
     73    xxt: Integer; // half of tile size x/y
     74    yyt: Integer; // half of tile size x/y
     75    TSpriteSize: TTerrainSpriteSize;
     76    HGrTerrain: TGraphicSet;
     77    HGrCities: TGraphicSet;
     78    MapOptions: TMapOptions;
     79    pDebugMap: Integer; // -1 for off
    5180    constructor Create;
     81    destructor Destroy; override;
     82    procedure Reset;
    5283    procedure SetOutput(Output: TBitmap);
    5384    procedure SetPaintBounds(Left, Top, Right, Bottom: integer);
     
    6394    procedure AttackEffect(const ShowMove: TShowMove);
    6495    procedure AttackEnd;
     96    procedure ReduceTerrainIconsSize;
    6597    property AdviceLoc: integer read FAdviceLoc write FAdviceLoc;
    66   end;
    67 
    68 var
    69   NoMap: TIsoMap;
    70   MapOptions: TMapOptions;
    71   pDebugMap: Integer; // -1 for off
     98    property TileSize: TTileSize read FTileSize write SetTileSize;
     99  end;
     100
     101  { TIsoMapCache }
     102
     103  TIsoMapCache = class
     104    LandPatch: TBitmap;
     105    OceanPatch: TBitmap;
     106    Borders: TBitmap;
     107    BordersOk: Integer;
     108    TSpriteSize: TTerrainSpriteSize;
     109    HGrTerrain: TGraphicSet;
     110    HGrCities: TGraphicSet;
     111    CitiesPictures: TCitiesPictures;
     112    procedure AssignToIsoMap(IsoMap: TIsoMap);
     113    constructor Create;
     114    destructor Destroy; override;
     115  end;
     116
     117const
     118  DefaultTileSize: TTileSize = tsMedium;
     119  TileSizes: array [TTileSize] of TPoint = ((X: 33; Y: 16), (X: 48; Y: 24),
     120    (X: 72; Y: 36));
    72121
    73122function IsJungle(y: integer): boolean;
    74123procedure Init(InitEnemyModelHandler: TInitEnemyModelEvent);
    75 function ApplyTileSize(ATileSize: TTileSize): boolean;
    76 procedure Done;
    77 procedure IsoEngineReset;
     124
    78125
    79126implementation
     127
     128uses
     129  Term;
    80130
    81131const
    82132  ShoreDither = fGrass;
    83   TerrainIconLines = 21;
    84   TerrainIconCols = 9;
    85133
    86134  // sprites indexes
     
    111159
    112160var
    113   BordersOK: integer;
    114161  OnInitEnemyModel: TInitEnemyModelEvent;
    115   LandPatch: TBitmap;
    116   OceanPatch: TBitmap;
    117   Borders: TBitmap;
    118   TSpriteSize: array [0 .. TerrainIconLines * TerrainIconCols - 1] of TRect;
    119162  DebugMap: ^TTileList;
    120   CitiesPictures: array [2 .. 3, 0 .. 3] of TCityPicture;
    121163  FoW: Boolean;
    122164  ShowLoc: Boolean;
     
    127169  ShowGrWall: Boolean;
    128170  ShowDebug: Boolean;
     171  IsoMapCache: array[TTileSize] of TIsoMapCache;
    129172
    130173function IsJungle(y: integer): boolean;
     
    136179begin
    137180  OnInitEnemyModel := InitEnemyModelHandler;
    138   if NoMap <> nil then
    139     FreeAndNil(NoMap);
    140   NoMap := TIsoMap.Create;
    141 end;
    142 
    143 procedure ReduceTerrainIconsSize;
     181end;
     182
     183{ TCitiesPictures }
     184
     185procedure TCitiesPictures.Prepare(HGrCities: TGraphicSet; xxt, yyt: Integer);
     186var
     187  Age: Integer;
     188  Size: Integer;
     189begin
     190  // prepare age 2+3 cities
     191  for age := 2 to 3 do
     192    for size := 0 to 3 do
     193      with Pictures[Age, Size] do
     194        FindPosition(HGrCities, Size * (xxt * 2 + 1), (Age - 2) * (yyt * 3 + 1),
     195          xxt * 2 - 1, yyt * 3 - 1, $00FFFF, xShield, yShield);
     196end;
     197
     198{ TIsoMapCache }
     199
     200procedure TIsoMapCache.AssignToIsoMap(IsoMap: TIsoMap);
     201begin
     202  IsoMap.HGrTerrain := HGrTerrain;
     203  IsoMap.HGrCities := HGrCities;
     204  IsoMap.Borders := Borders;
     205  IsoMap.BordersOK := @BordersOk;
     206  IsoMap.LandPatch := LandPatch;
     207  IsoMap.OceanPatch := OceanPatch;
     208  IsoMap.TSpriteSize := TSpriteSize;
     209  IsoMap.CitiesPictures := CitiesPictures;
     210end;
     211
     212constructor TIsoMapCache.Create;
     213begin
     214  LandPatch := TBitmap.Create;
     215  LandPatch.PixelFormat := pf24bit;
     216  OceanPatch := TBitmap.Create;
     217  OceanPatch.PixelFormat := pf24bit;
     218  Borders := TBitmap.Create;
     219  Borders.PixelFormat := pf24bit;
     220  HGrTerrain := nil;
     221  HGrCities := nil;
     222  SetLength(TSpriteSize, TerrainIconLines * TerrainIconCols);
     223  CitiesPictures := TCitiesPictures.Create;
     224end;
     225
     226destructor TIsoMapCache.Destroy;
     227begin
     228  FreeAndNil(CitiesPictures);
     229  FreeAndNil(LandPatch);
     230  FreeAndNil(OceanPatch);
     231  FreeAndNil(Borders);
     232  inherited;
     233end;
     234
     235procedure TIsoMap.ReduceTerrainIconsSize;
    144236var
    145237  MaskLine: array of TPixelPointer;
     
    206298end;
    207299
    208 function ApplyTileSize(ATileSize: TTileSize): boolean;
     300procedure TIsoMap.ApplyTileSize(ATileSize: TTileSize);
    209301var
    210302  x: Integer;
     
    212304  xSrc: Integer;
    213305  ySrc: Integer;
    214   HGrTerrainNew: TGraphicSet;
    215   HGrCitiesNew: TGraphicSet;
    216   Age: Integer;
    217   Size: Integer;
    218306  LandMore: TBitmap;
    219307  OceanMore: TBitmap;
    220308  DitherMask: TBitmap;
    221   xxtNew: Integer;
    222   yytNew: Integer;
    223 begin
    224   xxtNew := TileSizes[ATileSize].X;
    225   yytNew := TileSizes[ATileSize].Y;
    226   result := false;
    227   HGrTerrainNew := LoadGraphicSet(Format('Terrain%dx%d.png',
    228     [xxtNew * 2, yytNew * 2]));
    229   if not Assigned(HGrTerrainNew) then
    230     exit;
    231   HGrCitiesNew := LoadGraphicSet(Format('Cities%dx%d.png',
    232     [xxtNew * 2, yytNew * 2]));
    233   if not Assigned(HGrCitiesNew) then
    234     exit;
    235   xxt := xxtNew;
    236   yyt := yytNew;
    237   TileSize := ATileSize;
    238   HGrTerrain := HGrTerrainNew;
    239   HGrCities := HGrCitiesNew;
    240   Result := true;
    241 
    242   // prepare age 2+3 cities
    243   for age := 2 to 3 do
    244     for size := 0 to 3 do
    245       with CitiesPictures[age, size] do
    246         FindPosition(HGrCities, size * (xxt * 2 + 1), (age - 2) * (yyt * 3 + 1),
    247           xxt * 2 - 1, yyt * 3 - 1, $00FFFF, xShield, yShield);
     309  FileName: string;
     310begin
     311  FTileSize := ATileSize;
     312  xxt := TileSizes[ATileSize].X;
     313  yyt := TileSizes[ATileSize].Y;
     314
     315  if Assigned(IsoMapCache[ATileSize]) then begin
     316    IsoMapCache[ATileSize].AssignToIsoMap(Self);
     317    Exit;
     318  end;
     319  IsoMapCache[ATileSize] := TIsoMapCache.Create;
     320
     321  FileName := Format('Terrain%dx%d.png', [xxt * 2, yyt * 2]);
     322  IsoMapCache[ATileSize].HGrTerrain := LoadGraphicSet(FileName);
     323  if not Assigned(IsoMapCache[ATileSize].HGrTerrain) then
     324    raise Exception.Create(FileName + ' not found.');
     325
     326  FileName := Format('Cities%dx%d.png', [xxt * 2, yyt * 2]);
     327  IsoMapCache[ATileSize].HGrCities := LoadGraphicSet(FileName);
     328  if not Assigned(IsoMapCache[ATileSize].HGrCities) then
     329    raise Exception.Create(FileName + ' not found.');
     330
     331  IsoMapCache[ATileSize].AssignToIsoMap(Self);
     332
     333  CitiesPictures.Prepare(HGrCities, xxt, yyt);
    248334
    249335  { prepare dithered ground tiles }
    250   if not Assigned(LandPatch) then begin
    251     LandPatch := TBitmap.Create;
    252     LandPatch.PixelFormat := pf24bit;
    253   end;
    254336  LandPatch.Canvas.Brush.Color := 0;
    255337  LandPatch.SetSize(xxt * 18, yyt * 9);
    256338  LandPatch.Canvas.FillRect(0, 0, LandPatch.Width, LandPatch.Height);
    257   if not Assigned(OceanPatch) then begin
    258     OceanPatch := TBitmap.Create;
    259     OceanPatch.PixelFormat := pf24bit;
    260   end;
    261339  OceanPatch.Canvas.Brush.Color := 0;
    262340  OceanPatch.SetSize(xxt * 8, yyt * 4);
     
    437515  ReduceTerrainIconsSize;
    438516
    439   if not Assigned(Borders) then begin
    440     Borders := TBitmap.Create;
    441     Borders.PixelFormat := pf24bit;
    442   end;
    443517  Borders.SetSize(xxt * 2, (yyt * 2) * nPl);
    444518  Borders.Canvas.FillRect(0, 0, Borders.Width, Borders.Height);
    445   BordersOK := 0;
    446 end;
    447 
    448 procedure Done;
    449 begin
    450   FreeAndNil(NoMap);
    451   FreeAndNil(LandPatch);
    452   FreeAndNil(OceanPatch);
    453   FreeAndNil(Borders);
    454 end;
    455 
    456 procedure IsoEngineReset;
    457 begin
    458   BordersOK := 0;
     519  BordersOK^ := 0;
     520end;
     521
     522procedure TIsoMap.Reset;
     523begin
     524  BordersOK^ := 0;
    459525end;
    460526
     
    469535  DefLoc := -1;
    470536  FAdviceLoc := -1;
     537  TileSize := DefaultTileSize;
     538end;
     539
     540destructor TIsoMap.Destroy;
     541begin
     542  inherited;
    471543end;
    472544
     
    711783    else
    712784    begin
    713       cpic := CitiesPictures[age, xGr];
     785      cpic := CitiesPictures.Pictures[age, xGr];
    714786      xShield := x - xxt + cpic.xShield;
    715787      yShield := y - 2 * yyt + cpic.yShield;
     
    10241096  begin
    10251097    if ShowBorder and (Loc >= 0) and (Loc < G.lx * G.ly) and
    1026       (Tile and fTerrain <> fUNKNOWN) then
    1027     begin
     1098      (Tile and fTerrain <> fUNKNOWN) then begin
    10281099      p1 := MyRO.Territory[Loc];
    1029       if (p1 >= 0) and (ShowMyBorder or (p1 <> me)) then
    1030       begin
    1031         if BordersOK and (1 shl p1) = 0 then
    1032         begin
     1100      if (p1 >= 0) and (ShowMyBorder or (p1 <> me)) then begin
     1101        if BordersOK^ and (1 shl p1) = 0 then begin
    10331102          UnshareBitmap(Borders);
    10341103          BitBltCanvas(Borders.Canvas, 0, p1 * (yyt * 2), xxt * 2,
     
    10491118          end;
    10501119          Borders.EndUpdate;
    1051           BordersOK := BordersOK or 1 shl p1;
     1120          BordersOK^ := BordersOK^ or 1 shl p1;
    10521121        end;
    10531122        for dy := 0 to 1 do
    1054           for dx := 0 to 1 do
    1055           begin
     1123          for dx := 0 to 1 do begin
    10561124            Loc1 := dLoc(Loc, dx * 2 - 1, dy * 2 - 1);
    10571125            begin
     
    10711139              end;
    10721140            end;
    1073           end
     1141          end;
    10741142      end;
    10751143    end;
     
    13471415    Line^.NextPixel;
    13481416  end;
     1417end;
     1418
     1419procedure TIsoMap.SetTileSize(AValue: TTileSize);
     1420begin
     1421  if FTileSize = AValue then Exit;
     1422  FTileSize := AValue;
     1423  ApplyTileSize(AValue);
    13491424end;
    13501425
     
    16411716end;
    16421717
    1643 initialization
    1644 
    1645 NoMap := nil;
    1646 LandPatch := nil;
    1647 OceanPatch := nil;
    1648 Borders := nil;
     1718procedure IsoEngineDone;
     1719var
     1720  I: TTileSize;
     1721begin
     1722  for I := Low(IsoMapCache) to High(IsoMapCache) do
     1723    FreeAndNil(IsoMapCache[I]);
     1724end;
     1725
     1726finalization
     1727
     1728IsoEngineDone;
    16491729
    16501730end.
Note: See TracChangeset for help on using the changeset viewer.