anchor.diff:    MK: TKMTileMaskKind;
     MT: TKMTileMaskType;
     MST: TKMTileMaskSubType;
  -  TerrainId, MaskId: Word;
  -  MaskFullType: PKMMaskFullType;
  -  GenTerrainInfo: TKMGenTerrainInfo;
  -
  -  TexId,{ K,} L, M, {P, }Q, MId, Tmp: Integer;
  -  GenTilesCnt, GenTilesCntTemp: Integer;
  -  StraightPixel{, RotatePixel}: Cardinal;
  -  GeneratedMasks: TStringList;
  +  terrainId, maskId: Word;
  +  maskFullType: TKMMaskFullType;
  +  genTerrainInfo: TKMGenTerrainInfo;
  +
  +  texId,{ K,} L, M, tmp, totalTex, uniqueTex: Integer;
  +  genTilesCnt, genTilesCntTemp: Integer;
  +  straightPx{, RotatePixel}: Cardinal;
  +  generatedMasks: TDictionary<Integer, TKMMaskFullType>;
   begin
     Assert(not aLegacyGeneration or (aSprites = nil));
  -  
  +
  +  gLog.AddTime('GenerateTerrainTransitions started. Legacy = ' + BoolToStr(aLegacyGeneration, True));
  +
     if aLegacyGeneration then
     begin
       //static arrays could be reset via its variable
       FillChar(gGenTerrainTransitionsLegacy, SizeOf(gGenTerrainTransitionsLegacy), #0); //Init array, it could be init on previous tileset load
  -    TexId := 4999;
  -    fGenTexIdStartILegacy := TexId;
  -    GenTilesCntTemp := (Integer(High(TKMTerrainKind)) - 1)*Integer(High(TKMTileMaskKind))
  +    texId := 4999;
  +    fGenTexIdStartILegacy := texId;
  +    genTilesCntTemp := (Integer(High(TKMTerrainKind)) - 1)*Integer(High(TKMTileMaskKind))
                      *Integer(High(TKMTileMaskType))*(Integer(High(TKMTileMaskSubType)) + 1);
  -    SetLength(fGenTerrainToTerKindLegacy, GenTilesCntTemp);
  +    SetLength(fGenTerrainToTerKindLegacy, genTilesCntTemp);
       FillChar(fGenTerrainToTerKindLegacy[0], SizeOf(fGenTerrainToTerKindLegacy[0])*GenTilesCntTemp, #0);
  +    gLog.AddTime(Format('Legacy: TexId = %d GenTilesCntTemp = %d', [texId, genTilesCntTemp]));
     end
     else
     begin
       //static arrays could be reset via its variable
       FillChar(gGenTerrainTransitions, SizeOf(gGenTerrainTransitions), #0); //Init array, it could be init on previous tileset load
  -    TexId := Length(aSprites.fRXData.RGBA) + 1;
  -    fGenTexIdStartI := TexId;
  -    GenTilesCnt := Integer(High(TKMTerrainKind))*Integer(High(TKMTileMaskKind))
  +    texId := Length(aSprites.fRXData.RGBA) + 1;
  +    fGenTexIdStartI := texId;
  +    genTilesCnt := Integer(High(TKMTerrainKind))*Integer(High(TKMTileMaskKind))
                      *Integer(High(TKMTileMaskType))*(Integer(High(TKMTileMaskSubType)) + 1);
  -    SetLength(fGenTerrainToTerKind, GenTilesCnt);
  -    aSprites.Allocate(TexId + GenTilesCnt);
  +    SetLength(fGenTerrainToTerKind, genTilesCnt);
  +    aSprites.Allocate(texId + genTilesCnt);
       FillChar(fGenTerrainToTerKind[0], SizeOf(fGenTerrainToTerKind[0])*GenTilesCnt, #0);
  -  end;
  -  GeneratedMasks := TStringList.Create;
  +    gLog.AddTime(Format('TexId = %d GenTilesCnt = %d', [texId, genTilesCnt]));
  +  end;
  +
  +  generatedMasks := TDictionary<Integer, TKMMaskFullType>.Create;
  +  totalTex := 0;
  +  uniqueTex := 0;
   //  K := 0;
     try
       //for all Terrain Kinds
  -    for TK := Low(TKMTerrainKind) to High(TKMTerrainKind) do
  -    begin
  -      if TK = tkCustom then Continue;
  -
  +    for TK := Succ(tkCustom) to High(TKMTerrainKind) do
  +    begin
         if aLegacyGeneration and (TK = tkSnowOnGrass) then Continue;
   
  -      TerrainId := BASE_TERRAIN[TK] + 1; // in fRXData Tiles are 1-based
  +      terrainId := BASE_TERRAIN[TK] + 1; // in fRXData Tiles are 1-based
   
         //for all Mask Kinds
  -      for MK := Low(TKMTileMaskKind) to High(TKMTileMaskKind) do
  +      for MK := Succ(mkNone) to High(TKMTileMaskKind) do
         begin
  -        if MK = mkNone then Continue;
  -
           if aLegacyGeneration and (MK = mkSoft2) then Continue;
   
           //for all Mask Types
  -        for MT := Low(TKMTileMaskType) to High(TKMTileMaskType) do
  +        for MT := Succ(mtNone) to High(TKMTileMaskType) do
           begin
  -          if MT = mtNone then Continue;
  -
             // for all Mask subtypes
             for MST := Low(TKMTileMaskSubType) to High(TKMTileMaskSubType) do //Mask subtypes (actual masks for layers)
             begin
  -            MaskId := TILE_MASKS_FOR_LAYERS[MK, MT, MST] + 1;
  -            if MaskId = 0 then Continue;   //Ignore non existent masks
  +            maskId := TILE_MASKS_FOR_LAYERS[MK, MT, MST] + 1;
  +            if maskId = 0 then Continue;   //Ignore non existent masks
  +
  +            Inc(totalTex);
   
               // We could use same mask image for several masktypes/subtypes
  -            MId := GeneratedMasks.IndexOf(IntToStr(MaskId));
  -            if MId > -1 then
  +            if generatedMasks.TryGetValue(maskId, maskFullType) then
               begin
  -              MaskFullType := PKMMaskFullType(GeneratedMasks.Objects[MId]);
  -
                 if aLegacyGeneration then
  -                Tmp := gGenTerrainTransitionsLegacy[TK, MaskFullType.Kind, MaskFullType.MType, MaskFullType.SubType]
  +                tmp := gGenTerrainTransitionsLegacy[TK, maskFullType.Kind, maskFullType.MType, maskFullType.SubType]
                 else
  -                Tmp := gGenTerrainTransitions[TK, MaskFullType.Kind, MaskFullType.MType, MaskFullType.SubType];
  -                
  -              if Tmp <> 0 then
  +                tmp := gGenTerrainTransitions[TK, maskFullType.Kind, maskFullType.MType, maskFullType.SubType];
  +
  +              if tmp <> 0 then
                 begin
                   if aLegacyGeneration then
  -                  gGenTerrainTransitionsLegacy[TK, MK, MT, MST] := Tmp
  +                  gGenTerrainTransitionsLegacy[TK, MK, MT, MST] := tmp
                   else
  -                  gGenTerrainTransitions[TK, MK, MT, MST] := Tmp;
  +                  gGenTerrainTransitions[TK, MK, MT, MST] := tmp;
                   Continue;
                 end;
               end else begin
  -              System.New(MaskFullType);
  -              MaskFullType.Kind := MK;
  -              MaskFullType.MType := MT;
  -              MaskFullType.SubType := MST;
  -              GeneratedMasks.AddObject(IntToStr(MaskId), TObject(MaskFullType));
  +              maskFullType.Kind := MK;
  +              maskFullType.MType := MT;
  +              maskFullType.SubType := MST;
  +              generatedMasks.Add(maskId, maskFullType);
               end;
   
       //        for K := 0 to 3 do //Rotation
       //        begin
  -              GenTerrainInfo.TerKind := TK;
  -              GenTerrainInfo.Mask.Kind := MK;
  -              GenTerrainInfo.Mask.MType := MT;
  -              GenTerrainInfo.Mask.SubType := MST;
  +              genTerrainInfo.TerKind := TK;
  +              genTerrainInfo.Mask.Kind := MK;
  +              genTerrainInfo.Mask.MType := MT;
  +              genTerrainInfo.Mask.SubType := MST;
                 
                 if aLegacyGeneration then
                 begin
  -                gGenTerrainTransitionsLegacy[TK, MK, MT, MST] := TexId - 1;
  -                fGenTerrainToTerKindLegacy[TexId - fGenTexIdStartILegacy] := GenTerrainInfo;
  +                gGenTerrainTransitionsLegacy[TK, MK, MT, MST] := texId - 1;
  +                fGenTerrainToTerKindLegacy[texId - fGenTexIdStartILegacy] := genTerrainInfo;
                 end
                 else
                 begin
  -                SetLength(aSprites.fRXData.RGBA[TexId], aSprites.fRXData.Size[TerrainId].X*aSprites.fRXData.Size[TerrainId].Y); //32*32 actually...
  -                SetLength(aSprites.fRXData.Mask[TexId], aSprites.fRXData.Size[TerrainId].X*aSprites.fRXData.Size[TerrainId].Y);
  -                aSprites.fRXData.Flag[TexId] := aSprites.fRXData.Flag[TerrainId];
  -                aSprites.fRXData.Size[TexId].X := aSprites.fRXData.Size[TerrainId].X;
  -                aSprites.fRXData.Size[TexId].Y := aSprites.fRXData.Size[TerrainId].Y;
  -                aSprites.fRXData.Pivot[TexId] := aSprites.fRXData.Pivot[TerrainId];
  -                aSprites.fRXData.HasMask[TexId] := False;
  -                gGenTerrainTransitions[TK, MK, MT, MST] := TexId - 1; //TexId is 1-based, but textures we use - 0 based
  -                fGenTerrainToTerKind[TexId - fGenTexIdStartI] := GenTerrainInfo;
  +                SetLength(aSprites.fRXData.RGBA[texId], aSprites.fRXData.Size[terrainId].X*aSprites.fRXData.Size[terrainId].Y); //32*32 actually...
  +                SetLength(aSprites.fRXData.Mask[texId], aSprites.fRXData.Size[terrainId].X*aSprites.fRXData.Size[terrainId].Y);
  +                aSprites.fRXData.Flag[texId] := aSprites.fRXData.Flag[terrainId];
  +                aSprites.fRXData.Size[texId].X := aSprites.fRXData.Size[terrainId].X;
  +                aSprites.fRXData.Size[texId].Y := aSprites.fRXData.Size[terrainId].Y;
  +                aSprites.fRXData.Pivot[texId] := aSprites.fRXData.Pivot[terrainId];
  +                aSprites.fRXData.HasMask[texId] := False;
  +                gGenTerrainTransitions[TK, MK, MT, MST] := texId - 1; //TexId is 1-based, but textures we use - 0 based
  +                fGenTerrainToTerKind[texId - fGenTexIdStartI] := genTerrainInfo;
                 
       //          gLog.AddTime(Format('TerKind: %10s Mask: %10s TexId: %d ', [GetEnumName(TypeInfo(TKMTerrainKind), Integer(I)),
       //                                                        GetEnumName(TypeInfo(TKMTileMaskType), Integer(J)), TexId]));
   
       //          fGenTerrainToTerKind.Add(IntToStr(TexId) + '=' + IntToStr(Integer(I)));
  -                for L := 0 to aSprites.fRXData.Size[TerrainId].Y - 1 do
  -                  for M := 0 to aSprites.fRXData.Size[TerrainId].X - 1 do
  +                for L := 0 to aSprites.fRXData.Size[terrainId].Y - 1 do
  +                  for M := 0 to aSprites.fRXData.Size[terrainId].X - 1 do
                     begin
         //              Rotate(K, L, M, P, Q, aSprites.fRXData.Size[TerrainId].X - 1);
  -                    StraightPixel := L * aSprites.fRXData.Size[TerrainId].X  + M;
  +                    straightPx := L * aSprites.fRXData.Size[terrainId].X  + M;
         //              RotatePixel := StraightPixel; //P * aSprites.fRXData.Size[TerrainId].X  + Q;
  -                    aSprites.fRXData.RGBA[TexId, StraightPixel] := ($FFFFFF or (aSprites.fRXData.RGBA[MaskId, StraightPixel] shl 24))
  -                                                       and aSprites.fRXData.RGBA[TerrainId, StraightPixel{RotatePixel}];
  +                    aSprites.fRXData.RGBA[texId, straightPx] := ($FFFFFF or (aSprites.fRXData.RGBA[maskId, straightPx] shl 24))
  +                                                       and aSprites.fRXData.RGBA[terrainId, straightPx{RotatePixel}];
                     end;
                 end;
  -              Inc(TexId);
  +              Inc(uniqueTex);
  +              Inc(texId);
       //        end;
             end;
           end;
         end;
       end;
  +
       if aLegacyGeneration then
  -      SetLength(fGenTerrainToTerKindLegacy, TexId - fGenTexIdStartILegacy)
  +    begin
  +      SetLength(fGenTerrainToTerKindLegacy, texId - fGenTexIdStartILegacy);
  +      gLog.AddTime(Format('TexId = %d; TexId - fGenTexIdStartILegacy = %d; uniqueTex = %d; totalTex = %d', [texId, texId - fGenTexIdStartILegacy, uniqueTex, totalTex]));
  +    end
       else
       begin
         // There could be usused place in arrays, as we could use same mask image for different purposes
  -      aSprites.Allocate(TexId);
  -      SetLength(fGenTerrainToTerKind, TexId - fGenTexIdStartI);
  +      aSprites.Allocate(texId);
  +      SetLength(fGenTerrainToTerKind, texId - fGenTexIdStartI);
  +      gLog.AddTime(Format('TexId = %d; TexId - fGenTexIdStartI = %d; uniqueTex = %d; totalTex = %d', [texId, texId - fGenTexIdStartI, uniqueTex, totalTex]));
       end;
  -    
  +
     finally
  -    for Q := 0 to GeneratedMasks.Count - 1 do
  -      System.Dispose(PKMMaskFullType(GeneratedMasks.Objects[Q]));
  -    FreeAndNil(GeneratedMasks);
  -  end;
  +    gLog.AddTime('GeneratedMasks cnt = ' + IntToStr(generatedMasks.Count));
  +    generatedMasks.Free;
  +  end;
  +  gLog.AddTime('GenerateTerrainTransitions Done.');
   end;
   
   
  
positive.code: interface
  uses
    {$IFDEF Unix} LCLIntf, LCLType, {$ENDIF}
    Classes, Graphics, Math, SysUtils,
    KM_CommonTypes, KM_Defaults, KM_Pics, KM_PNG, KM_Render, KM_ResTexts, KM_ResTileset, KM_ResHouses
    {$IFDEF FPC}, zstream {$ENDIF}
    {$IFDEF WDC}, ZLib {$ENDIF};
  
negative.code:       if Assigned(fStepCaption) then
          fStepCaption('Reading ' + RXInfo[RT].FileName + ' ...');
  
        gLog.AddTime('Reading ' + RXInfo[RT].FileName + '.rx');
        LoadSprites(RT, RT = rxGUI); //Only GUI needs alpha shadows
        fSprites[RT].MakeGFX(RT = rxGUI);
  
  