anchor.diff:        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);
   
  
positive.code:     PxWidth, PxHeight: Word;
    end;
  
    gGenTerrainTransitions: array[TKMTerrainKind]
                              of array[TKMTileMaskKind]
                                of array[TKMTileMaskType]
                                  of array[TKMTileMaskSubType] //mask components (subtypes)
  //                                  of array[0..3] //Terrain Rotation
                                      of Word;
  
    gGenTerrainTransitionsLegacy: array[TKMTerrainKind]
                              of array[TKMTileMaskKind]
                                of array[TKMTileMaskType]
                                  of array[TKMTileMaskSubType] //mask components (subtypes)
  //                                  of array[0..3] //Terrain Rotation
                                      of Word;
  implementation
  uses
    KromUtils,
  
negative.code:   MK: TKMTileMaskKind;
    MT: TKMTileMaskType;
    MST: TKMTileMaskSubType;
    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))
                     *Integer(High(TKMTileMaskType))*(Integer(High(TKMTileMaskSubType)) + 1);
      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))
                     *Integer(High(TKMTileMaskType))*(Integer(High(TKMTileMaskSubType)) + 1);
      SetLength(fGenTerrainToTerKind, genTilesCnt);
      aSprites.Allocate(texId + genTilesCnt);
      FillChar(fGenTerrainToTerKind[0], SizeOf(fGenTerrainToTerKind[0])*GenTilesCnt, #0);
      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 := 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
  
        //for all Mask Kinds
        for MK := Succ(mkNone) to High(TKMTileMaskKind) do
        begin
          if aLegacyGeneration and (MK = mkSoft2) then Continue;
  
          //for all Mask Types
          for MT := Succ(mtNone) to High(TKMTileMaskType) do
          begin
            // 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
  
              Inc(totalTex);
  
              // We could use same mask image for several masktypes/subtypes
              if generatedMasks.TryGetValue(maskId, maskFullType) then
              begin
                if aLegacyGeneration then
                  tmp := gGenTerrainTransitionsLegacy[TK, maskFullType.Kind, maskFullType.MType, maskFullType.SubType]
                else
                  tmp := gGenTerrainTransitions[TK, maskFullType.Kind, maskFullType.MType, maskFullType.SubType];
  
                if tmp <> 0 then
                begin
                  if aLegacyGeneration then
                    gGenTerrainTransitionsLegacy[TK, MK, MT, MST] := tmp
                  else
                    gGenTerrainTransitions[TK, MK, MT, MST] := tmp;
                  Continue;
                end;
              end else begin
                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;
                
                if aLegacyGeneration then
                begin
                  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;
                
      //          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
                    begin
        //              Rotate(K, L, M, P, Q, aSprites.fRXData.Size[TerrainId].X - 1);
                      straightPx := L * aSprites.fRXData.Size[terrainId].X  + M;
        //              RotatePixel := StraightPixel; //P * aSprites.fRXData.Size[TerrainId].X  + Q;
                      aSprites.fRXData.RGBA[texId, straightPx] := ($FFFFFF or (aSprites.fRXData.RGBA[maskId, straightPx] shl 24))
                                                         and aSprites.fRXData.RGBA[terrainId, straightPx{RotatePixel}];
                    end;
                end;
                Inc(uniqueTex);
                Inc(texId);
      //        end;
            end;
          end;
        end;
      end;
  
      if aLegacyGeneration then
      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);
        gLog.AddTime(Format('TexId = %d; TexId - fGenTexIdStartI = %d; uniqueTex = %d; totalTex = %d', [texId, texId - fGenTexIdStartI, uniqueTex, totalTex]));
      end;
  
    finally
      gLog.AddTime('GeneratedMasks cnt = ' + IntToStr(generatedMasks.Count));
      generatedMasks.Free;
    end;
    gLog.AddTime('GenerateTerrainTransitions Done.');
  end;
  
  
  