- reorganized loading of textures.

Due to dependencies on initializing some data in app_init it was not possible to cleanly set up the fonts.
This adds a game-side function for loading the entire palettes before starting with the texture data and another one for loading game-side texture data.
This now allows fully setting up the palettes before starting with the textures and to fully set up the textures before reading the .def files.

All this is needed because to properly initialize, the fonts need to be able to access the fully initialized texture state, including replacements and hires substitutions from the .def files.
This commit is contained in:
Christoph Oelckers 2021-06-01 11:05:26 +02:00
parent a0bf16d8fe
commit 454816299e
17 changed files with 136 additions and 91 deletions

View file

@ -639,7 +639,6 @@ int32_t engineInit(void)
{
engineLoadTables();
g_visibility = 512;
if (!mdinited) mdinit();
return 0;
}

View file

@ -105,6 +105,7 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FGameTexture
auto pic = charlumps[i];
Chars[i].OriginalPic = MakeGameTexture(pic->GetTexture(), nullptr, ETextureType::FontChar);
Chars[i].OriginalPic->CopySize(pic, true);
Chars[i].OriginalPic->SetName(FStringf("@@%s.%d", name, i));
TexMan.AddGameTexture(Chars[i].OriginalPic);
Chars[i].XMove = (int)Chars[i].OriginalPic->GetDisplayWidth();
if (sysCallbacks.FontCharCreated) sysCallbacks.FontCharCreated(pic, Chars[i].OriginalPic);

View file

@ -140,7 +140,7 @@ void LoadScripts();
void MainLoop();
void SetConsoleNotifyBuffer();
bool PreBindTexture(FRenderState* state, FGameTexture*& tex, EUpscaleFlags& flags, int& scaleflags, int& clampmode, int& translation, int& overrideshader);
void PostLoadSetup();
void highTileSetup();
void FontCharCreated(FGameTexture* base, FGameTexture* untranslated);
void LoadVoxelModels();
@ -880,6 +880,33 @@ void GetGames()
//
//==========================================================================
static void InitTextures()
{
TexMan.Init([]() {}, [](BuildInfo&) {});
StartScreen->Progress();
mdinit();
TileFiles.Init();
TileFiles.LoadArtSet("tiles%03d.art"); // it's the same for all games.
voxInit();
gi->LoadGameTextures(); // loads game-side data that must be present before processing the .def files.
LoadDefinitions();
InitFont(); // InitFonts may only be called once all texture data has been initialized.
lookups.postLoadTables();
highTileSetup();
lookups.postLoadLookups();
SetupFontSubstitution();
V_LoadTranslations(); // loading the translations must be delayed until the palettes have been fully set up.
TileFiles.SetBackup();
}
//==========================================================================
//
//
//
//==========================================================================
int RunGame()
{
GameStartupInfo.FgColor = 0xffffff;
@ -985,12 +1012,8 @@ int RunGame()
GPalette.Init(MAXPALOOKUPS + 2); // one slot for each translation, plus a separate one for the base palettes and the internal one
gi->loadPalette();
StartScreen->Progress();
TexMan.Init([]() {}, [](BuildInfo &) {});
StartScreen->Progress();
TileFiles.Init();
TileFiles.LoadArtSet("tiles%03d.art"); // it's the same for all games.
InitTextures();
InitFont();
StartScreen->Progress();
I_InitSound();
StartScreen->Progress();
@ -1010,7 +1033,6 @@ int RunGame()
gameinfo.mBackButton = "engine/graphics/m_back.png";
StartScreen->Progress();
voxInit();
engineInit();
gi->app_init();
StartScreen->Progress();
@ -1023,12 +1045,6 @@ int RunGame()
if (!(paletteloaded & PALETTE_MAIN))
I_FatalError("No palette found.");
lookups.postLoadTables();
PostLoadSetup();
lookups.postLoadLookups();
duke_menufont.Callback();
V_LoadTranslations(); // loading the translations must be delayed until the palettes have been fully set up.
FMaterial::SetLayerCallback(setpalettelayer);
if (GameStartupInfo.Name.IsNotEmpty()) I_SetWindowTitle(GameStartupInfo.Name);
DeleteStartupScreen();
@ -1526,8 +1542,6 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Raze, GetBuildTime, I_GetBuildTime)
ACTION_RETURN_INT(I_GetBuildTime());
}
bool PickTexture(FRenderState* state, FGameTexture* tex, int paletteid, TexturePick& pick);
DEFINE_ACTION_FUNCTION(_Raze, PickTexture)
{
PARAM_PROLOGUE;

View file

@ -66,6 +66,7 @@ struct GameInterface
virtual ~GameInterface() {}
virtual bool GenerateSavePic() { return false; }
virtual void app_init() = 0;
virtual void LoadGameTextures() {}
virtual void loadPalette();
virtual void clearlocalinputstate() {}
virtual void UpdateScreenSize() {}

View file

@ -38,7 +38,8 @@
#include "i_interface.h"
#include "vm.h"
#include "gstrings.h"
#include "textures.h"
#include "texturemanager.h"
#include "buildtiles.h"
FGameTexture* GetBaseForChar(FGameTexture* t);
void FontCharCreated(FGameTexture* base, FGameTexture* glyph);
@ -60,28 +61,7 @@ CUSTOM_CVAR(Int, duke_menufont, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOIN
}
}
static int compareChar(int code, FFont* gamefont, FFont* myfont)
{
auto c1 = gamefont->GetChar(code, CR_UNDEFINED, nullptr);
auto c2 = myfont->GetChar(code, CR_UNDEFINED, nullptr);
if (c1 == nullptr || c2 == nullptr) return 1; // this should never happen unless one of the fonts is broken.
if (c1->GetTexelHeight() != c2->GetTexelHeight()) return 0;
if (c1->GetTexelWidth() != c2->GetTexelWidth()) return 0;
auto t1 = c1->GetTexture();
auto t2 = c2->GetTexture();
auto buf1 = t1->CreateTexBuffer(0);
auto buf2 = t2->CreateTexBuffer(0);
// at this point the palette has not yet been fully set up so the alpha channel is not consistent.
// We have to mask it out here to be able to compare the two buffers.
for (int i = 0; i < buf1.mWidth * buf1.mHeight * 4; i++)
{
buf1.mBuffer[i] = buf2.mBuffer[i] = 0;
}
int res = memcmp(buf1.mBuffer, buf2.mBuffer, buf1.mWidth * buf1.mHeight * 4);
return res == 0;
}
#if 0
static void SetupHires(FFont *font)
{
if (!font) return;
@ -105,6 +85,7 @@ static void SetupHires(FFont *font)
FontCharCreated(base, mychar);
}
}
#endif
void InitFont()
{
@ -115,18 +96,50 @@ void InitFont()
IndexFont = V_GetFont("IndexFont");
DigiFont = V_GetFont("DigiFont");
SetupHires(BigFont);
SetupHires(SmallFont);
//SetupHires(BigFont);
//SetupHires(SmallFont);
if (g_gameType & GAMEFLAG_DUKE)
{
BigFont13 = V_GetFont("BigFont13");
BigFont15 = V_GetFont("BigFont15");
BigFont = new FFont(0, "BigFont");
BigFont->CopyFrom(*BigFont15);
}
OriginalSmallFont = SmallFont;
OriginalBigFont = BigFont;
}
static int compareChar(int code, FFont* gamefont, FFont* myfont)
{
auto c1 = gamefont->GetChar(code, CR_UNDEFINED, nullptr);
auto c2 = myfont->GetChar(code, CR_UNDEFINED, nullptr);
if (c1 == nullptr || c2 == nullptr) return 1; // this should never happen unless one of the fonts is broken.
if (c1->GetTexelHeight() != c2->GetTexelHeight()) return 0;
if (c1->GetTexelWidth() != c2->GetTexelWidth()) return 0;
// If there's a hires version attached to the base, treat this as the base being different.
TexturePick pick;
if (PickTexture(nullptr, c1, 0, pick) && pick.texture != c1) return 0;
auto t1 = c1->GetTexture();
auto t2 = c2->GetTexture();
auto buf1 = t1->CreateTexBuffer(0);
auto buf2 = t2->CreateTexBuffer(0);
// at this point the palette has not yet been fully set up so the alpha channel is not consistent.
// We have to mask it out here to be able to compare the two buffers.
for (int i = 3; i < buf1.mWidth * buf1.mHeight * 4; i+=4)
{
buf1.mBuffer[i] = buf2.mBuffer[i] = 0;
}
int res = memcmp(buf1.mBuffer, buf2.mBuffer, buf1.mWidth * buf1.mHeight * 4);
return res == 0;
}
void SetupFontSubstitution()
{
auto tilesmallfont = V_GetFont("tilesmallfont");
auto tilebigfont = V_GetFont("tilebigfont");

View file

@ -8,5 +8,6 @@ extern FFont* IndexFont;
extern FFont* DigiFont;
void InitFont();
void SetupFontSubstitution();
FFont* PickBigFont(const char* txt = nullptr);
FFont* PickSmallFont(const char* txt = nullptr);

View file

@ -489,3 +489,7 @@ struct SetAnim
};
void processSetAnim(const char* cmd, FScriptPosition& pos, SetAnim& imp);
class FRenderState;
class FGameTexture;
bool PickTexture(FRenderState* state, FGameTexture* tex, int paletteid, TexturePick& pick);

View file

@ -75,6 +75,7 @@ FGameTexture* GetBaseForChar(FGameTexture* t)
void FontCharCreated(FGameTexture* base, FGameTexture* glyph)
{
if (base->GetName().IsNotEmpty())
deferredChars.Insert(glyph, base);
}
@ -155,7 +156,7 @@ FGameTexture* SkyboxReplacement(FTextureID picnum, int palnum)
//
//==========================================================================
void PostLoadSetup()
void highTileSetup()
{
for(int i=0;i<MAXTILES;i++)
{
@ -163,8 +164,33 @@ void PostLoadSetup()
if (!tex->isValid()) continue;
auto Hightile = tileReplacements.CheckKey(i);
if (!Hightile) continue;
textureReplacements.Insert(tex->GetID().GetIndex(), std::move(*Hightile));
}
tileReplacements.Clear();
FGameTexture* detailTex = nullptr, * glowTex = nullptr, * normalTex = nullptr, *specTex = nullptr;
decltype(deferredChars)::Iterator it(deferredChars);
decltype(deferredChars)::Pair* pair;
while (it.NextPair(pair))
{
auto rep = textureReplacements.CheckKey(pair->Value->GetID().GetIndex());
if (rep)
{
auto myrep = *rep; // don't create copies directly from the map we're inserting in!
auto chk = textureReplacements.CheckKey(pair->Key->GetID().GetIndex());
if (!chk) textureReplacements.Insert(pair->Key->GetID().GetIndex(), std::move(myrep));
}
}
deferredChars.Clear();
decltype(textureReplacements)::Iterator it2(textureReplacements);
decltype(textureReplacements)::Pair* pair2;
while (it2.NextPair(pair2))
{
auto tex = TexMan.GameByIndex(pair2->Key);
if (!tex->isValid()) continue;
auto Hightile = &pair2->Value;
if (!Hightile) continue;
FGameTexture* detailTex = nullptr, * glowTex = nullptr, * normalTex = nullptr, * specTex = nullptr;
float scalex = 1.f, scaley = 1.f;
for (auto& rep : *Hightile)
{
@ -207,22 +233,6 @@ void PostLoadSetup()
}
}
}
textureReplacements.Insert(tex->GetID().GetIndex(), std::move(*Hightile));
}
tileReplacements.Clear();
int i = 0;
decltype(deferredChars)::Iterator it(deferredChars);
decltype(deferredChars)::Pair* pair;
while (it.NextPair(pair))
{
i++;
auto rep = textureReplacements.CheckKey(pair->Value->GetID().GetIndex());
if (rep)
{
auto chk = textureReplacements.CheckKey(pair->Key->GetID().GetIndex());
if (!chk) textureReplacements.Insert(pair->Key->GetID().GetIndex(), *rep);
}
}
}

View file

@ -422,18 +422,15 @@ void GameInterface::app_init()
HookReplaceFunctions();
Printf(PRINT_NONOTIFY, "Loading tiles\n");
if (!tileInit())
I_FatalError("TILES###.ART files not found");
Printf(PRINT_NONOTIFY, "Loading texture tables\n");
tileInit();
levelLoadDefaults();
LoadDefinitions();
//---------
SetTileNames();
C_InitConback(TexMan.CheckForTexture("BACKTILE", ETextureType::Any), true, 0.25);
TileFiles.SetBackup();
Printf(PRINT_NONOTIFY, "Loading cosine table\n");
trigInit();
Printf(PRINT_NONOTIFY, "Initializing view subsystem\n");

View file

@ -26,6 +26,7 @@ struct GameInterface : public ::GameInterface
{
const char* Name() override { return "Duke"; }
void app_init() override;
void loadPalette();
void clearlocalinputstate() override;
bool GenerateSavePic() override;
void PlayHudSound() override;

View file

@ -39,6 +39,7 @@ Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au)
#include "i_interface.h"
#include "prediction.h"
#include "gamestate.h"
#include "razefont.h"
BEGIN_DUKE_NS
@ -265,6 +266,12 @@ static void SetTileNames()
#undef y
void GameInterface::loadPalette()
{
paletteLoadFromDisk();
genspriteremaps();
}
//---------------------------------------------------------------------------
//
// set up the game module's state
@ -309,6 +316,7 @@ void GameInterface::app_init()
loadcons();
fi.initactorflags();
duke_menufont.Callback(); // depends on the .CON files so it must be after loadcons
OnEvent(EVENT_INIT);
@ -316,7 +324,6 @@ void GameInterface::app_init()
initTiles();
setupbackdrop();
genspriteremaps();
SetupGameButtons();
InitCheats();
checkcommandline();
@ -324,9 +331,7 @@ void GameInterface::app_init()
screenpeek = myconnectindex;
LoadDefinitions();
SetTileNames();
TileFiles.SetBackup();
C_InitConback(TexMan.CheckForTexture("MENUSCREEN", ETextureType::Any), false, 0.75);
if (ud.multimode > 1)

View file

@ -72,8 +72,9 @@ void ResetEngine()
resettiming();
}
void InstallEngine()
void GameInterface::loadPalette()
{
paletteLoadFromDisk();
uploadCinemaPalettes();
LoadPaletteLookups();
}
@ -493,13 +494,8 @@ void GameInterface::app_init()
nTotalPlayers += nNetPlayerCount;
}
// temp - moving InstallEngine(); before FadeOut as we use nextpage() in FadeOut
InstallEngine();
LoadDefinitions();
SetTileNames();
TileFiles.SetBackup();
InitFX();
seq_LoadSequences();
InitStatus();

View file

@ -219,6 +219,7 @@ struct GameInterface : public ::GameInterface
const char* Name() override { return "Exhumed"; }
void app_init() override;
void clearlocalinputstate() override;
void loadPalette() override;
bool GenerateSavePic() override;
void MenuOpened() override;
void MenuSound(EMenuSounds snd) override;

View file

@ -110,8 +110,7 @@ static COLOR_MAP PlayerColorMap[PLAYER_COLOR_MAPS][1] =
};
void
InitPalette(void)
void GameInterface::loadPalette(void)
{
static COLOR_MAP AllToRed[] =
{
@ -216,6 +215,17 @@ InitPalette(void)
short play;
uint8_t tempbuf[256];
paletteLoadFromDisk();
auto pal = fileSystem.LoadFile("3drealms.pal", 0);
if (pal.Size() >= 768)
{
for (auto& c : pal)
c <<= 2;
paletteSetColorTable(DREALMSPAL, pal.Data(), true, true);
}
//
// Dive palettes
//

View file

@ -165,6 +165,11 @@ static void SetTileNames()
}
#undef x
void GameInterface::LoadGameTextures()
{
LoadKVXFromScript("swvoxfil.txt"); // Load voxels from script file
}
//---------------------------------------------------------------------------
//
//
@ -195,17 +200,6 @@ void GameInterface::app_init()
registerosdcommands();
auto pal = fileSystem.LoadFile("3drealms.pal", 0);
if (pal.Size() >= 768)
{
for (auto& c : pal)
c <<= 2;
paletteSetColorTable(DREALMSPAL, pal.Data(), true, true);
}
InitPalette();
// sets numplayers, connecthead, connectpoint2, myconnectindex
numplayers = 1; myconnectindex = 0;
connecthead = 0; connectpoint2[0] = -1;
@ -225,14 +219,11 @@ void GameInterface::app_init()
for (int i = 0; i < MAX_SW_PLAYERS; i++)
INITLIST(&Player[i].PanelSpriteList);
LoadKVXFromScript("swvoxfil.txt"); // Load voxels from script file
LoadCustomInfoFromScript("engine/swcustom.txt"); // load the internal definitions. These also apply to the shareware version.
if (!SW_SHAREWARE)
LoadCustomInfoFromScript("swcustom.txt"); // Load user customisation information
LoadDefinitions();
SetTileNames();
TileFiles.SetBackup();
userConfig.AddDefs.reset();
InitFX();
}

View file

@ -2233,6 +2233,8 @@ struct GameInterface : public ::GameInterface
{
const char* Name() override { return "ShadowWarrior"; }
void app_init() override;
void LoadGameTextures();
void loadPalette();
void clearlocalinputstate() override;
void FreeGameData() override;
void FreeLevelData() override;

View file

@ -16,7 +16,6 @@ void DoTheCache(void);
void InitCheats();
void MapColors(short num,COLOR_MAP cm,short create);
void InitPalette(void);
int32_t CONFIG_ReadSetup(void);
bool WarpPlaneSectorInfo(short sectnum, SPRITEp* sp_ceiling, SPRITEp* sp_floor);