Complete BigTask
Sync changed files to Google Drive / sync (push) Successful in 24s

This commit is contained in:
admin_d committed 2026-10-04 22:50:25 +05:00
1 parent 2444723bd3
commit d8360d49e5
2 files changed
+17 -229

No files matched your search

@@ -175,7 +175,6 @@ var
SHOW_UNITS_IN_HOUSE :Boolean = False; //Should we hide units when they are in house ?
IGNORE_MOUSE_SCROLLING :Boolean = False; //Ignore mouse scrolling
SKIP_RENDER :Boolean = False; //Skip all the rendering in favor of faster logic
DO_NOT_SKIP_LOAD_TILESET:Boolean = False; //Do not skip load tileset even if SKIP_RENDER is set
SKIP_SOUND :Boolean = False; //Skip all the sounds in favor of faster logic
SKIP_LOADING_CURSOR :Boolean = False; //Skip loading and setting cursor
SKIP_SETTINGS_SAVE :Boolean = False; //Skip save main/game settings into the ini file
@@ -217,11 +216,9 @@ var
SHOW_WALK_CONNECT :Boolean = False; //Show floodfill areas of interconnected areas
SHOW_GROUP_MEMBERS_POS :Boolean = False; //Show group members position
TEST_VIEW_CLIP_INSET :Boolean = False; //Renders smaller area to see if everything gets clipped well
OUTLINE_ALL_SPRITES :Boolean = False; //Render outline around every sprite
SHOW_ATTACK_RADIUS :Boolean = False; //Render towers/archers attack radius
DISPLAY_SOUNDS :Boolean = False; //Display sounds on map
RENDER_3D :Boolean = False; //Experimental 3D render
LINEAR_FILTER_SPRITES :Boolean = False; //To check pixel sampling alignment issues (bouncing) at 100% zoom
HOUSE_BUILDING_STEP :Single = 0;
WATER_LIGHT_MULTIPLIER :Single = DEFAULT_WATER_LIGHT_MULTIPLIER; //Terrain light multiplier
OVERLAY_NAVMESH :Boolean = False; //Show navmesh
+17 -226
View File
@@ -46,11 +46,9 @@ type
fTemp: Boolean;
fPad: Byte; // Padding between sprites to avoid neighbour edge visibility
{$IFNDEF NO_OGL}
procedure SetGFXData(aTexID: Cardinal; aSpriteInfo: TKMBinItem; aAtlasType: TKMSpriteAtlasType);
procedure PrepareAtlases(aSpriteInfo: TBinArray; aMode: TKMSpriteAtlasType; aTexType: TKMTexFormat; var aBaseRAM, aColorRAM, aTexCount: Cardinal;
procedure PrepareAtlases(aSpriteInfo: TBinArray; aMode: TKMSpriteAtlasType; aTexType: TKMTexFormat;
aFillGFXData: Boolean = True; aOnCheckTerminated: TBooleanFuncSimple = nil);
{$ENDIF}
protected
fRT: TRXType;
fRXData: TRXData;
@@ -62,9 +60,9 @@ type
procedure ReadRXZHeader(aStream: TStream; out aFormat: TKMRXXFormat);
procedure CollectSpriteFilesToOverloadInFolder(const aFolder: string; aFileList: TStringList);
{$IFNDEF NO_OGL}
procedure MakeGFX_BinPacking(aTexType: TKMTexFormat; aIDList: TList<Integer>; var aBaseRAM, aColorRAM, aTexCount: Cardinal;
procedure MakeGFX_BinPacking(aTexType: TKMTexFormat; aIDList: TList<Integer>;
aFillGFXData: Boolean = True; aOnCheckTerminated: TBooleanFuncSimple = nil; aMaxAtlasSize: Integer = -1); overload;
procedure MakeGFX_BinPacking(aTexType: TKMTexFormat; aStartingIndex: Integer; var aBaseRAM, aColorRAM, aTexCount: Cardinal;
procedure MakeGFX_BinPacking(aTexType: TKMTexFormat; aStartingIndex: Integer;
aFillGFXData: Boolean = True; aOnCheckTerminated: TBooleanFuncSimple = nil); overload;
procedure MakeGFXInternal(aAlphaShadows: Boolean; aIDList: TList<Integer>; aFillGFXData: Boolean;
aOnCheckTerminated: TBooleanFuncSimple; aMaxAtlasSize: Integer);
@@ -112,11 +110,6 @@ type
function IsEmpty: Boolean;
procedure ExportAllSpritesFromRXData(const aFolder: string);
procedure ExportFullImageData(const aFolder: string; aIndex: Integer);
procedure ExportImage(const aFile: string; aIndex: Integer);
procedure ExportMask(const aFile: string; aIndex: Integer);
procedure ClearGameResGenTemp;
procedure GenerateTexturesFromLoadedRXZ;
@@ -206,8 +199,6 @@ type
function LoadSprites(aRT: TRXType; aAlphaShadows: Boolean): Boolean;
function LoadRXASprites(aRT: TRXType): Boolean;
function LoadRXASpritesAndGenTextures(aRT: TRXType): Boolean;
procedure ExportToPNG(aRT: TRXType);
property AlphaShadows: Boolean read fAlphaShadows;
property FileName[aRX: TRXType]: string read GetRXFileName;
@@ -251,18 +242,15 @@ uses
{$ENDIF}
KromUtils,
KM_SoftShadows, KM_Resource, KM_ResUnits,
{$IFNDEF NO_OGL}
KM_Render,
{$ENDIF}
TypInfo,
KM_Log, KM_CommonClasses,
KM_FileIO, KaMResourceInput, KaMGeneratedTerrainBridge,
KaMResourceInput, KaMGeneratedTerrainBridge,
KM_CommonUtils, KM_Utils, KM_Points,
KM_GameSettings;
const
MAX_GAME_ATLAS_SIZE = 2048; //Max atlas size for KaM. No need for bigger atlases
LOG_EXTRA_GFX: Boolean = False;
OVERLOAD_SKIP_MASK = 'skip';
var
@@ -272,9 +260,7 @@ var
function GetMaxAtlasSize: Integer;
begin
Result := MAX_GAME_ATLAS_SIZE;
{$IFNDEF NO_OGL}
Result := Min(Result, TKMRender.MaxTextureSize);
{$ENDIF}
end;
@@ -295,7 +281,6 @@ end;
//This is a crude solution to allow Campaigns to delete sprites they add
procedure TKMSpritePack.DeleteSpriteTexture(aIndex: Integer);
begin
{$IFNDEF NO_OGL}
if gGFXData[fRT, aIndex].Tex.TexID <> 0 then
TKMRender.DeleteTexture(gGFXData[fRT, aIndex].Tex.TexID);
if gGFXData[fRT, aIndex].Alt.TexID <> 0 then
@@ -303,7 +288,6 @@ begin
gGFXData[fRT, aIndex].Tex.TexID := 0;
gGFXData[fRT, aIndex].Alt.TexID := 0;
{$ENDIF}
end;
@@ -804,11 +788,6 @@ var
decompressionStream: TDecompressionStream;
rxxFormat: TKMRXXFormat;
begin
case fRT of
rxTiles: if SKIP_RENDER and not DO_NOT_SKIP_LOAD_TILESET then Exit;
else if SKIP_RENDER then Exit;
end;
ReadRXZHeader(aStream, rxxFormat);
// Not sure what to do yet, silently "fail" for now
@@ -877,11 +856,6 @@ var
{$ENDIF}
begin
{$IFNDEF NO_OGL}
case fRT of
rxTiles: if SKIP_RENDER and not DO_NOT_SKIP_LOAD_TILESET then Exit;
else if SKIP_RENDER then Exit;
end;
ReadRXZHeader(aStream, rxxFormat);
// Not sure what to do yet, silently "fail" for now
@@ -1018,7 +992,6 @@ procedure TKMSpritePack.OverloadGeneratedFromFolder(aAlphaShadows: Boolean; cons
var
idList: TList<Integer>;
begin
if SKIP_RENDER then Exit;
if not DirectoryExists(aFolder) then Exit;
{$IFDEF WDC}
@@ -1113,7 +1086,6 @@ procedure TKMSpritePack.OverloadRXDataFromFolder(const aFolder: string; aOnProgr
end;
{$ENDIF}
begin
if SKIP_RENDER then Exit;
if not DirectoryExists(aFolder) then Exit;
{$IFDEF WDC}
@@ -1123,132 +1095,6 @@ begin
end;
// Export RX to Bitmaps without need to have GraphicsEditor, also this way we preserve image indexes
procedure TKMSpritePack.ExportAllSpritesFromRXData(const aFolder: string);
var
I: Integer;
begin
ForceDirectories(aFolder);
for I := 1 to fRXData.Count do
if not TThread.CheckTerminated then
ExportFullImageData(aFolder, I);
end;
procedure TKMSpritePack.ExportFullImageData(const aFolder: string; aIndex: Integer);
var
s: string;
begin
if fRXData.Flag[aIndex] <> 1 then Exit;
ExportImage(aFolder + Format('%d_%.4d.png', [Ord(fRT)+1, aIndex]), aIndex);
if fRXData.HasMask[aIndex] then
ExportMask(aFolder + Format('%d_%.4da.png', [Ord(fRT)+1, aIndex]), aIndex);
// Pivot
s := IntToStr(fRXData.Pivot[aIndex].x) + sLineBreak + IntToStr(fRXData.Pivot[aIndex].y) + sLineBreak;
//SizeNoShadow is used only for Units
if fRT = rxUnits then
s := s + IntToStr(fRXData.SizeNoShadow[aIndex].Left) + sLineBreak +
IntToStr(fRXData.SizeNoShadow[aIndex].Top) + sLineBreak +
IntToStr(fRXData.SizeNoShadow[aIndex].Right) + sLineBreak +
IntToStr(fRXData.SizeNoShadow[aIndex].Bottom) + sLineBreak;
WriteTextUtf8(s, aFolder + Format('%d_%.4d.txt', [Ord(fRT)+1, aIndex]));
end;
procedure TKMSpritePack.ExportImage(const aFile: string; aIndex: Integer);
var
I, K: Integer;
M: Byte;
treatMask: Boolean;
pngWidth, pngHeight: Word;
pngData: TKMCardinalArray;
begin
pngWidth := fRXData.Size[aIndex].X;
pngHeight := fRXData.Size[aIndex].Y;
SetLength(pngData, pngWidth * pngHeight);
//Export RGB values
for I := 0 to pngHeight - 1 do
for K := 0 to pngWidth - 1 do
begin
treatMask := fRXData.HasMask[aIndex] and (fRXData.Mask[aIndex, I*pngWidth + K] > 0);
if (fRT = rxHouses)
and ((aIndex < 680)
or (aIndex = 1657)
or (aIndex = 1659)
or (aIndex = 1681)
or (aIndex = 1683)
or (aIndex > 2050)) then
treatMask := False;
if treatMask then
begin
M := fRXData.Mask[aIndex, I*pngWidth + K];
//Replace background with corresponding brightness of Red
if fRXData.RGBA[aIndex, I*pngWidth + K] = FLAG_COLOR_DARK then
//Brightness < 0.5, mix with black
pngData[I*pngWidth + K] := M
else
//Brightness > 0.5, mix with white
pngData[I*pngWidth + K] := $FF + (255 - M) * $010100;
end
else
pngData[I*pngWidth + K] := fRXData.RGBA[aIndex, I*pngWidth + K] and $FFFFFF;
pngData[I*pngWidth + K] := pngData[I*pngWidth + K] or (fRXData.RGBA[aIndex, I*pngWidth + K] and $FF000000);
end;
//Mark pivot location with a dot
// K := pngWidth + fRXData.Pivot[aIndex].x;
// I := pngHeight + fRXData.Pivot[aIndex].y;
// if InRange(I, 0, pngHeight-1) and InRange(K, 0, pngWidth-1) then
// pngData[I*pngWidth + K] := $FFFF00FF;
SaveToPng(pngWidth, pngHeight, pngData, aFile);
end;
procedure TKMSpritePack.ExportMask(const aFile: string; aIndex: Integer);
var
I, K: Integer;
pngWidth, pngHeight: Word;
pngData: TKMCardinalArray;
maskColor: Cardinal;
begin
pngWidth := fRXData.Size[aIndex].X;
pngHeight := fRXData.Size[aIndex].Y;
SetLength(pngData, pngWidth * pngHeight);
//Export Mask
if fRXData.HasMask[aIndex] then
begin
for I := 0 to pngHeight - 1 do
for K := 0 to pngWidth - 1 do
begin
if fRT = rxHouses then
begin
maskColor := fRXData.Mask[aIndex, I * pngWidth + K];
if maskColor <> 0 then
maskColor := GetGreyColor(maskColor) or $FF000000;
end else
maskColor := (Byte(fRXData.Mask[aIndex, I * pngWidth + K] > 0) * $FFFFFF) or $FF000000;
pngData[I * pngWidth + K] := maskColor;
end;
SaveToPng(pngWidth, pngHeight, pngData, aFile);
end;
end;
function TKMSpritePack.GetAverageSpriteColors(aCount: Integer): TKMColor3bArray;
var
I, L, M: Integer;
@@ -1315,11 +1161,8 @@ end;
procedure TKMSpritePack.MakeGFXInternal(aAlphaShadows: Boolean; aIDList: TList<Integer>; aFillGFXData: Boolean;
aOnCheckTerminated: TBooleanFuncSimple; aMaxAtlasSize: Integer);
var
I, K: Integer;
texType: TKMTexFormat;
baseRAM, idealRAM, colorRAM, texCount: Cardinal;
begin
if SKIP_RENDER then Exit;
if fRXData.Count = 0 then Exit;
if aAlphaShadows and (fRT in [rxTrees,rxHouses,rxUnits,rxGui,rxTiles]) or not aAlphaShadows and (fRT = rxGuiMain) then
@@ -1327,24 +1170,9 @@ begin
else
texType := tfRGB5A1;
MakeGFX_BinPacking(texType, aIDList, baseRAM, colorRAM, texCount, aFillGFXData, aOnCheckTerminated, aMaxAtlasSize);
if LOG_EXTRA_GFX then
begin
idealRAM := 0;
for K := 0 to aIDList.Count - 1 do
begin
I := aIDList[K];
if fRXData.Flag[I] <> 0 then
Inc(idealRAM, fRXData.Size[I].X * fRXData.Size[I].Y * TEX_FORMAT_SIZE[texType]);
end;
gLog.AddTime(IntToStr(texCount) + ' Textures created');
gLog.AddNoTime(Format('%d/%d', [baseRAM div 1024, idealRAM div 1024]) +
' Kbytes allocated/ideal for ' + RX_INFO[fRT].FileName + ' GFX when using Packing');
gLog.AddNoTime(IntToStr(colorRAM div 1024) + ' KBytes for team colors');
end;
MakeGFX_BinPacking(texType, aIDList, aFillGFXData, aOnCheckTerminated, aMaxAtlasSize);
end;
{$ENDIF}
@@ -1377,7 +1205,8 @@ begin
end;
procedure TKMSpritePack.MakeGFX_BinPacking(aTexType: TKMTexFormat; aStartingIndex: Integer; var aBaseRAM, aColorRAM, aTexCount: Cardinal;
{$IFNDEF NO_OGL}
procedure TKMSpritePack.MakeGFX_BinPacking(aTexType: TKMTexFormat; aStartingIndex: Integer;
aFillGFXData: Boolean = True; aOnCheckTerminated: TBooleanFuncSimple = nil);
var
I: Integer;
@@ -1388,14 +1217,15 @@ begin
for I := aStartingIndex to fRXData.Count do
idList.Add(I);
MakeGFX_BinPacking(aTexType, idList, aBaseRAM, aColorRAM, aTexCount, aFillGFXData, aOnCheckTerminated);
MakeGFX_BinPacking(aTexType, idList, aFillGFXData, aOnCheckTerminated);
finally
idList.Free;
end;
end;
{$ENDIF}
procedure TKMSpritePack.PrepareAtlases(aSpriteInfo: TBinArray; aMode: TKMSpriteAtlasType; aTexType: TKMTexFormat; var aBaseRAM, aColorRAM, aTexCount: Cardinal;
procedure TKMSpritePack.PrepareAtlases(aSpriteInfo: TBinArray; aMode: TKMSpriteAtlasType; aTexType: TKMTexFormat;
aFillGFXData: Boolean = True; aOnCheckTerminated: TBooleanFuncSimple = nil);
var
I, K, L, M: Integer;
@@ -1403,7 +1233,6 @@ var
texID: Cardinal;
ID: Integer;
atlasData: TKMCardinalArray;
texFilter: TKMFilterType;
begin
// gLog.AddTime('Length(aSpriteInfo) = ' + IntToStr(Length(aSpriteInfo)));
//Prepare atlases
@@ -1458,23 +1287,12 @@ begin
if (L = fRXData.Size[ID].Y - 1) then atlasData[Pixel + aSpriteInfo[I].Width] := atlasData[Pixel];
end;
//Sprite outline
if OUTLINE_ALL_SPRITES and (
(L = 0) or (M = 0)
or (L = fRXData.Size[ID].Y - 1)
or (M = fRXData.Size[ID].X - 1)) then
atlasData[Pixel] := $FF0000FF;
end;
end;
if aFillGFXData then
begin
//Generate texture once
texFilter := ftNearest;
if LINEAR_FILTER_SPRITES and (fRT in [rxTrees, rxHouses, rxUnits]) then
texFilter := ftLinear;
texID := TKMRender.GenTexture(aSpriteInfo[I].Width, aSpriteInfo[I].Height, @atlasData[0], aTexType, texFilter, texFilter);
texID := TKMRender.GenTexture(aSpriteInfo[I].Width, aSpriteInfo[I].Height, @atlasData[0], aTexType, ftNearest, ftNearest);
//Now that we know texture IDs we can fill GFXData structure
SetGFXData(texID, aSpriteInfo[I], aMode);
@@ -1488,19 +1306,13 @@ begin
fAtlases[aMode, I].Data := atlasData;
end;
if aMode = saBase then
Inc(aBaseRAM, aSpriteInfo[I].Width * aSpriteInfo[I].Height * TEX_FORMAT_SIZE[aTexType])
else
Inc(aColorRAM, aSpriteInfo[I].Width * aSpriteInfo[I].Height * TEX_FORMAT_SIZE[aTexType]);
Inc(aTexCount);
end;
end;
// This algorithm is planned to take advantage of more efficient 2D bin packing
procedure TKMSpritePack.MakeGFX_BinPacking(aTexType: TKMTexFormat; aIDList: TList<Integer>; var aBaseRAM, aColorRAM, aTexCount: Cardinal;
{$IFNDEF NO_OGL}
procedure TKMSpritePack.MakeGFX_BinPacking(aTexType: TKMTexFormat; aIDList: TList<Integer>;
aFillGFXData: Boolean = True; aOnCheckTerminated: TBooleanFuncSimple = nil; aMaxAtlasSize: Integer = -1);
function CheckTerminated: Boolean;
begin
@@ -1513,8 +1325,6 @@ var
spriteInfo: TBinArray;
atlasSize, allTilesAtlasSize, maxAtlasSize: Integer;
begin
aBaseRAM := 0;
aColorRAM := 0;
//Prepare base atlases
SetLength(spriteSizes, aIDList.Count);// fRXData.Count - aStartingIndex + 1);
K := 0;
@@ -1555,7 +1365,7 @@ begin
SetLength(fAtlases[saBase], Length(spriteInfo));
PrepareAtlases(spriteInfo, saBase, aTexType, aBaseRAM, aColorRAM, aTexCount, aFillGFXData, aOnCheckTerminated);
PrepareAtlases(spriteInfo, saBase, aTexType, aFillGFXData, aOnCheckTerminated);
if CheckTerminated then Exit;
@@ -1579,7 +1389,7 @@ begin
BinPack(spriteSizes, atlasSize, fPad, spriteInfo);
if CheckTerminated then Exit;
SetLength(fAtlases[saMask], Length(spriteInfo));
PrepareAtlases(spriteInfo, saMask, tfAlpha8, aBaseRAM, aColorRAM, aTexCount, aFillGFXData, aOnCheckTerminated);
PrepareAtlases(spriteInfo, saMask, tfAlpha8, aFillGFXData, aOnCheckTerminated);
end;
{$ENDIF}
@@ -1598,31 +1408,22 @@ end;
// Texture generating task can be done only by main thread, as OpenGL does not work with multiple threads
// Note: this could be from the loader thread by using `Synchronise` procedure
procedure TKMSpritePack.GenerateTexturesFromLoadedRXZ;
{$IFNDEF NO_OGL}
var
I: Integer;
SAT: TKMSpriteAtlasType;
texID: Cardinal;
texFilter: TKMFilterType;
{$ENDIF}
begin
{$IFNDEF NO_OGL}
for SAT := Low(fAtlases) to High(fAtlases) do
for I := Low(fAtlases[SAT]) to High(fAtlases[SAT]) do
begin
with fAtlases[SAT,I] do
begin
texFilter := ftNearest;
if LINEAR_FILTER_SPRITES and (fRT in [rxTrees, rxHouses, rxUnits]) then
texFilter := ftLinear;
texID := TKMRender.GenTexture(Container.Width, Container.Height, @Data[0], TexType, texFilter, texFilter);
texID := TKMRender.GenTexture(Container.Width, Container.Height, @Data[0], TexType, ftNearest, ftNearest);
//Now that we know texture IDs we can fill GFXData structure
SetGFXData(texID, Container, SAT);
end;
end;
{$ENDIF}
end;
@@ -2352,16 +2153,6 @@ begin
end;
procedure TKMResSprites.ExportToPNG(aRT: TRXType);
begin
if LoadSprites(aRT, False) then
begin
fSprites[aRT].ExportAllSpritesFromRXData(ExeDir + 'Export' + PathDelim + RX_INFO[aRT].FileName + '.rx' + PathDelim);
ClearTemp;
end;
end;
constructor TKMGameResourceWorker.Create(aOwner: TKMResSprites; aSerial: QWord; aRT: TRXType; aAlphaShadows, aInputIsRXA: Boolean; aInput: TStream);
begin
inherited Create(True);