diff --git a/src/d_main.cpp b/src/d_main.cpp index 98042bcd8..3a45e34ce 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2979,7 +2979,6 @@ void D_Cleanup() V_ClearFonts(); // must clear global font pointers ColorSets.Clear(); PainFlashes.Clear(); - R_DeinitTranslationTables(); // some tables are initialized from outside the translation code. gameinfo.~gameinfo_t(); new (&gameinfo) gameinfo_t; // Reset gameinfo S_Shutdown(); // free all channels and delete playlist diff --git a/src/g_game.cpp b/src/g_game.cpp index 5fcb3df56..77cc53a76 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1614,7 +1614,7 @@ void FLevelLocals::QueueBody (AActor *body) GetTranslationType(body->Translation) == TRANSLATION_PlayersExtra) { // This needs to be able to handle multiple levels, in case a level with dead players is used as a secondary one later. - CopyTranslation(TRANSLATION(TRANSLATION_PlayerCorpses, modslot), body->Translation); + palMgr.CopyTranslation(TRANSLATION(TRANSLATION_PlayerCorpses, modslot), body->Translation); body->Translation = TRANSLATION(TRANSLATION_PlayerCorpses, modslot); } diff --git a/src/gamedata/fonts/font.cpp b/src/gamedata/fonts/font.cpp index 85053ad32..a677a36b4 100644 --- a/src/gamedata/fonts/font.cpp +++ b/src/gamedata/fonts/font.cpp @@ -666,7 +666,7 @@ void FFont::SetDefaultTranslation(uint32_t *othercolors) } } } - Translations[CR_UNTRANSLATED] = remap.StoreTranslation(TRANSLATION_Font); + Translations[CR_UNTRANSLATED] = palMgr.StoreTranslation(TRANSLATION_Font, &remap); forceremap = true; } @@ -797,7 +797,7 @@ void FFont::BuildTranslations (const double *luminosity, const uint8_t *identity remap.Palette[j] = GPalette.BaseColors[identity[j]] | MAKEARGB(255, 0, 0, 0); } } - Translations.Push(remap.StoreTranslation(TRANSLATION_Font)); + Translations.Push(palMgr.StoreTranslation(TRANSLATION_Font, &remap)); } else { @@ -837,7 +837,7 @@ void FFont::BuildTranslations (const double *luminosity, const uint8_t *identity remap.Palette[j] = PalEntry(255,r,g,b); } if (post) post(&remap); - Translations.Push(remap.StoreTranslation(TRANSLATION_Font)); + Translations.Push(palMgr.StoreTranslation(TRANSLATION_Font, &remap)); // Advance to the next color range. while (parmstart[1].RangeStart > parmstart[0].RangeEnd) diff --git a/src/gamedata/fonts/hexfont.cpp b/src/gamedata/fonts/hexfont.cpp index fde86bc3d..e26f2d7d3 100644 --- a/src/gamedata/fonts/hexfont.cpp +++ b/src/gamedata/fonts/hexfont.cpp @@ -417,7 +417,7 @@ public: } } } - Translations[CR_UNTRANSLATED] = remap.StoreTranslation(TRANSLATION_Font); + Translations[CR_UNTRANSLATED] = palMgr.StoreTranslation(TRANSLATION_Font, &remap); forceremap = true; } diff --git a/src/gamedata/textures/formats/buildtexture.cpp b/src/gamedata/textures/formats/buildtexture.cpp index 3a9eae259..5210adaf3 100644 --- a/src/gamedata/textures/formats/buildtexture.cpp +++ b/src/gamedata/textures/formats/buildtexture.cpp @@ -84,7 +84,7 @@ FBuildTexture::FBuildTexture(const FString &pathprefix, int tilenum, const uint8 TArray FBuildTexture::CreatePalettedPixels(int conversion) { TArray Pixels(Width * Height, true); - FRemapTable *Remap = GetTranslation(TRANSLATION_Standard, Translation); + FRemapTable *Remap = palMgr.GetTranslation(TRANSLATION_Standard, Translation); for (int i = 0; i < Width*Height; i++) { auto c = RawPixels[i]; @@ -95,7 +95,7 @@ TArray FBuildTexture::CreatePalettedPixels(int conversion) int FBuildTexture::CopyPixels(FBitmap *bmp, int conversion) { - PalEntry *Remap = GetTranslation(TRANSLATION_Standard, Translation)->Palette; + PalEntry *Remap = palMgr.GetTranslation(TRANSLATION_Standard, Translation)->Palette; bmp->CopyPixelData(0, 0, RawPixels, Width, Height, Height, 1, 0, Remap); return -1; @@ -280,7 +280,7 @@ static int BuildPaletteTranslation(int lump) opal.Remap[255] = 0; // Store the remap table in the translation manager so that we do not need to keep track of it ourselves. // Slot 0 for internal translations is a convenient location because normally it only contains a small number of translations. - return GetTranslationIndex(opal.StoreTranslation(TRANSLATION_Standard)); + return GetTranslationIndex(palMgr.StoreTranslation(TRANSLATION_Standard, &opal)); } diff --git a/src/gamedata/textures/formats/imgztexture.cpp b/src/gamedata/textures/formats/imgztexture.cpp index 913690f56..d5f3799af 100644 --- a/src/gamedata/textures/formats/imgztexture.cpp +++ b/src/gamedata/textures/formats/imgztexture.cpp @@ -203,6 +203,6 @@ TArray FIMGZTexture::CreatePalettedPixels(int conversion) int FIMGZTexture::CopyPixels(FBitmap *bmp, int conversion) { if (!isalpha) return FImageSource::CopyPixels(bmp, conversion); - else return CopyTranslatedPixels(bmp, GetTranslation(TRANSLATION_Standard, STD_Grayscale)->Palette); + else return CopyTranslatedPixels(bmp, palMgr.GetTranslation(TRANSLATION_Standard, STD_Grayscale)->Palette); } diff --git a/src/gamedata/textures/formats/multipatchtexture.cpp b/src/gamedata/textures/formats/multipatchtexture.cpp index 8166db645..e858e61c7 100644 --- a/src/gamedata/textures/formats/multipatchtexture.cpp +++ b/src/gamedata/textures/formats/multipatchtexture.cpp @@ -92,7 +92,7 @@ static uint8_t *GetBlendMap(PalEntry blend, uint8_t *blendwork) switch (blend.a==0 ? int(blend) : -1) { case BLEND_ICEMAP: - return TranslationToTable(TRANSLATION(TRANSLATION_Standard, 7))->Remap; + return palMgr.TranslationToTable(TRANSLATION(TRANSLATION_Standard, 7))->Remap; default: if (blend >= BLEND_SPECIALCOLORMAP1 && blend < BLEND_SPECIALCOLORMAP1 + SpecialColormaps.Size()) diff --git a/src/gamedata/textures/formats/patchtexture.cpp b/src/gamedata/textures/formats/patchtexture.cpp index 7ce3a5d88..b20d9b7a5 100644 --- a/src/gamedata/textures/formats/patchtexture.cpp +++ b/src/gamedata/textures/formats/patchtexture.cpp @@ -263,7 +263,7 @@ TArray FPatchTexture::CreatePalettedPixels(int conversion) int FPatchTexture::CopyPixels(FBitmap *bmp, int conversion) { if (!isalpha) return FImageSource::CopyPixels(bmp, conversion); - else return CopyTranslatedPixels(bmp, GetTranslation(TRANSLATION_Standard, STD_Grayscale)->Palette); + else return CopyTranslatedPixels(bmp, palMgr.GetTranslation(TRANSLATION_Standard, STD_Grayscale)->Palette); } //========================================================================== diff --git a/src/gamedata/textures/formats/shadertexture.cpp b/src/gamedata/textures/formats/shadertexture.cpp index 3814e4628..cbeaa9f73 100644 --- a/src/gamedata/textures/formats/shadertexture.cpp +++ b/src/gamedata/textures/formats/shadertexture.cpp @@ -122,7 +122,7 @@ public: int CopyPixels(FBitmap *bmp, int conversion) override { - bmp->CopyPixelData(0, 0, Pixels, Width, Height, Height, 1, 0, GetTranslation(TRANSLATION_Standard, STD_Gray)->Palette); + bmp->CopyPixelData(0, 0, Pixels, Width, Height, Height, 1, 0, palMgr.GetTranslation(TRANSLATION_Standard, STD_Gray)->Palette); return 0; } diff --git a/src/gamedata/textures/imagehelpers.h b/src/gamedata/textures/imagehelpers.h index f9475e6eb..967876508 100644 --- a/src/gamedata/textures/imagehelpers.h +++ b/src/gamedata/textures/imagehelpers.h @@ -55,7 +55,7 @@ namespace ImageHelpers { if (wantluminance) { - return GetTranslation(TRANSLATION_Standard, srcisgrayscale ? STD_Gray : STD_Grayscale)->Remap; + return palMgr.GetTranslation(TRANSLATION_Standard, srcisgrayscale ? STD_Gray : STD_Grayscale)->Remap; } else { diff --git a/src/gamedata/textures/texture.cpp b/src/gamedata/textures/texture.cpp index 2506744f0..c573ec5de 100644 --- a/src/gamedata/textures/texture.cpp +++ b/src/gamedata/textures/texture.cpp @@ -701,11 +701,11 @@ FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags) buffer = new unsigned char[W*(H + 1) * 4]; memset(buffer, 0, W * (H + 1) * 4); - auto remap = translation <= 0 ? nullptr : FUniquePalette::GetPalette(translation); + auto remap = translation <= 0 ? nullptr : palMgr.TranslationToTable(translation); FBitmap bmp(buffer, W * 4, W, H); int trans; - auto Pixels = GetBgraBitmap(remap, &trans); + auto Pixels = GetBgraBitmap(remap? remap->Palette : nullptr, &trans); bmp.Blit(exx, exx, Pixels); if (remap == nullptr) diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index adcd093fd..5b6d530d0 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -1025,7 +1025,7 @@ void FLevelLocals::Serialize(FSerializer &arc, bool hubload) arc("polyobjs", Polyobjects); SerializeSubsectors(arc, "subsectors"); StatusBar->SerializeMessages(arc); - FRemapTable::StaticSerializeTranslations(arc); + StaticSerializeTranslations(arc); canvasTextureInfo.Serialize(arc); SerializePlayers(arc, hubload); SerializeSounds(arc); diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 85fffe888..4e7f2da1d 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -406,7 +406,7 @@ void P_SetupLevel(FLevelLocals *Level, int position, bool newGame) { Level->Players[i]->mo = nullptr; } - ClearTranslationSlot(TRANSLATION_LevelScripted); + palMgr.ClearTranslationSlot(TRANSLATION_LevelScripted); // Initial height of PointOfView will be set by player think. diff --git a/src/playsim/p_acs.cpp b/src/playsim/p_acs.cpp index 25d9ae6b5..f1ecd26e5 100644 --- a/src/playsim/p_acs.cpp +++ b/src/playsim/p_acs.cpp @@ -9590,7 +9590,7 @@ scriptwait: case PCD_ENDTRANSLATION: if (translation != NULL) { - UpdateTranslation(TRANSLATION(TRANSLATION_LevelScripted, transi), translation); + palMgr.UpdateTranslation(TRANSLATION(TRANSLATION_LevelScripted, transi), translation); delete translation; translation = NULL; } diff --git a/src/r_data/r_translate.cpp b/src/r_data/r_translate.cpp index c31d5410d..eb413c272 100644 --- a/src/r_data/r_translate.cpp +++ b/src/r_data/r_translate.cpp @@ -50,57 +50,103 @@ #include "v_text.h" #include "m_crc32.h" #include "g_levellocals.h" +#include "palutil.h" #include "gi.h" -static FMemArena remapArena; -static TAutoGrowArray TranslationTables[NUM_TRANSLATION_TABLES]; +PaletteContainer palMgr; -inline FRemapTable* AllocRemap(FRemapTable *remap) +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +void PaletteContainer::Init() // This cannot be a constructor!!! { + Clear(); + // Make sure that index 0 is always the identity translation. + FRemapTable remap; + remap.MakeIdentity(); + remap.Inactive = true; + AddRemap(&remap); +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +void PaletteContainer::Clear() +{ + remapArena.FreeAllBlocks(); + uniqueRemaps.Reset(); + for (auto& slot : TranslationTables) slot.Reset(); +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +FRemapTable* PaletteContainer::AddRemap(FRemapTable* remap) +{ + if (!remap) return uniqueRemaps[0]; + + remap->crc32 = CalcCRC32((uint8_t*)remap->Palette, sizeof(remap->Palette)); + + for (auto uremap : uniqueRemaps) + { + if (uremap->crc32 == remap->crc32 && uremap->NumEntries == remap->NumEntries && *uremap == *remap) + return uremap; + } auto newremap = (FRemapTable*)remapArena.Alloc(sizeof(FRemapTable)); - if (remap) *newremap = *remap; - else newremap->MakeIdentity(); + *newremap = *remap; + auto index = uniqueRemaps.Push(newremap); + newremap->Index = index; return newremap; } -void UpdateTranslation(int trans, FRemapTable* remap) +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +void PaletteContainer::UpdateTranslation(int trans, FRemapTable* remap) { - auto newremap = AllocRemap(remap); + auto newremap = AddRemap(remap); TranslationTables[GetTranslationType(trans)].SetVal(GetTranslationIndex(trans), newremap); - remap->UpdateNative(); } -int AddTranslation(int slot, FRemapTable* remap, int count) +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +int PaletteContainer::AddTranslation(int slot, FRemapTable* remap, int count) { uint32_t id; for (int i = 0; i < count; i++) { - auto newremap = AllocRemap(&remap[i]); + auto newremap = AddRemap(&remap[i]); id = TranslationTables[slot].Push(newremap); } return TRANSLATION(slot, id); } -FRemapTable* GetTranslation(int slot, int index) -{ - return TranslationTables[slot].GetVal(index); -} +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- -void CopyTranslation(int dest, int src) +void PaletteContainer::CopyTranslation(int dest, int src) { - *TranslationTables[GetTranslationType(dest)][GetTranslationType(src)] = *TranslationToTable(src); - TranslationTables[GetTranslationType(dest)][GetTranslationType(src)]->UpdateNative(); -} - -void ClearTranslationSlot(int slot) -{ - TranslationTables[slot].Clear(); -} - -unsigned NumTranslations(int slot) -{ - return TranslationTables[slot].Size(); + TranslationTables[GetTranslationType(dest)][GetTranslationType(src)] = TranslationToTable(src); } //---------------------------------------------------------------------------- @@ -109,7 +155,7 @@ unsigned NumTranslations(int slot) // //---------------------------------------------------------------------------- -FRemapTable *TranslationToTable(int translation) +FRemapTable *PaletteContainer::TranslationToTable(int translation) { unsigned int type = GetTranslationType(translation); unsigned int index = GetTranslationIndex(translation); @@ -121,6 +167,34 @@ FRemapTable *TranslationToTable(int translation) return GetTranslation(type, index); } +//---------------------------------------------------------------------------- +// +// Stores a copy of this translation in the DECORATE translation table +// +//---------------------------------------------------------------------------- + +int PaletteContainer::StoreTranslation(int slot, FRemapTable *remap) +{ + unsigned int i; + + auto size = NumTranslations(slot); + for (i = 0; i < size; i++) + { + if (*remap == *palMgr.TranslationToTable(TRANSLATION(slot, i))) + { + // A duplicate of this translation already exists + return TRANSLATION(slot, i); + } + } + if (size >= MAX_DECORATE_TRANSLATIONS) + { + I_Error("Too many DECORATE translations"); + } + return AddTranslation(slot, remap); +} + + + const uint8_t IcePalette[16][3] = { @@ -166,58 +240,6 @@ static bool IndexOutOfRange(const int start1, const int end1, const int start2, return IndexOutOfRange(start2, end2) || outOfRange; } - - -TArray FUniquePalette::AllPalettes; - -//---------------------------------------------------------------------------- -// -// Helper class to deal with frequently changing translations from ACS -// -//---------------------------------------------------------------------------- - -bool FUniquePalette::Update() -{ - PalData pd; - - memset(pd.pe, 0, sizeof(pd.pe)); - memcpy(pd.pe, remap->Palette, remap->NumEntries * sizeof(*remap->Palette)); - pd.crc32 = CalcCRC32((uint8_t*)pd.pe, sizeof(pd.pe)); - for (unsigned int i = 0; i< AllPalettes.Size(); i++) - { - if (pd.crc32 == AllPalettes[i].crc32) - { - if (!memcmp(pd.pe, AllPalettes[i].pe, sizeof(pd.pe))) - { - Index = 1 + i; - return true; - } - } - } - Index = 1 + AllPalettes.Push(pd); - return true; -} - -/****************************************************/ -/****************************************************/ - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -int FRemapTable::GetUniqueIndex() -{ - if (Inactive) return 0; - if (Native == nullptr) - { - Native = new FUniquePalette(this); - Native->Update(); - } - return Native->GetIndex(); -} - //---------------------------------------------------------------------------- // // @@ -239,16 +261,14 @@ bool FRemapTable::operator==(const FRemapTable &o) // //---------------------------------------------------------------------------- -void FRemapTable::Serialize(FSerializer &arc) +static void SerializeRemap(FSerializer &arc, FRemapTable &remap) { - int n = NumEntries; - - arc("numentries", NumEntries); - arc.Array("remap", Remap, NumEntries); - arc.Array("palette", Palette, NumEntries); + arc("numentries", remap.NumEntries); + arc.Array("remap", remap.Remap, remap.NumEntries); + arc.Array("palette", remap.Palette, remap.NumEntries); } -void FRemapTable::StaticSerializeTranslations(FSerializer &arc) +void StaticSerializeTranslations(FSerializer &arc) { if (arc.BeginArray("translations")) { @@ -257,16 +277,16 @@ void FRemapTable::StaticSerializeTranslations(FSerializer &arc) int w; if (arc.isWriting()) { - auto size = NumTranslations(TRANSLATION_LevelScripted); + auto size = palMgr.NumTranslations(TRANSLATION_LevelScripted); for (unsigned int i = 0; i < size; ++i) { - trans = TranslationToTable(TRANSLATION(TRANSLATION_LevelScripted, i)); + trans = palMgr.TranslationToTable(TRANSLATION(TRANSLATION_LevelScripted, i)); if (trans != NULL && !trans->IsIdentity()) { if (arc.BeginObject(nullptr)) { arc("index", i); - trans->Serialize(arc); + SerializeRemap(arc, *trans); arc.EndObject(); } } @@ -278,8 +298,8 @@ void FRemapTable::StaticSerializeTranslations(FSerializer &arc) { arc("index", w); FRemapTable remap; - remap.Serialize(arc); - UpdateTranslation(TRANSLATION(TRANSLATION_LevelScripted, w), &remap); + SerializeRemap(arc, remap); + palMgr.UpdateTranslation(TRANSLATION(TRANSLATION_LevelScripted, w), &remap); arc.EndObject(); } } @@ -335,35 +355,6 @@ bool FRemapTable::IsIdentity() const // //---------------------------------------------------------------------------- -void FRemapTable::KillNative() -{ - if (Native != NULL) - { - delete Native; - Native = NULL; - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void FRemapTable::UpdateNative() -{ - if (Native != NULL) - { - Native->Update(); - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - bool FRemapTable::AddIndexRange(int start, int end, int pal1, int pal2) { if (IndexOutOfRange(start, end, pal1, pal2)) @@ -761,46 +752,6 @@ bool FRemapTable::AddColors(int start, int count, const uint8_t*colors) } -//---------------------------------------------------------------------------- -// -// Stores a copy of this translation in the DECORATE translation table -// -//---------------------------------------------------------------------------- - -int FRemapTable::StoreTranslation(int slot) -{ - unsigned int i; - - auto size = NumTranslations(slot); - for (i = 0; i < size; i++) - { - if (*this == *TranslationToTable(TRANSLATION(slot, i))) - { - // A duplicate of this translation already exists - return TRANSLATION(slot, i); - } - } - if (size >= MAX_DECORATE_TRANSLATIONS) - { - I_Error("Too many DECORATE translations"); - } - return AddTranslation(slot, this); -} - - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -static void PushIdentityTable(int slot) -{ - FRemapTable table; - table.MakeIdentity(); - AddTranslation(slot, &table); -} - //---------------------------------------------------------------------------- // // @@ -816,7 +767,7 @@ int CreateBloodTranslation(PalEntry color) if (BloodTranslationColors.Size() == 0) { // Don't use the first slot. - PushIdentityTable(TRANSLATION_Blood); + palMgr.PushIdentityTable(TRANSLATION_Blood); BloodTranslationColors.Push(0); } @@ -846,7 +797,7 @@ int CreateBloodTranslation(PalEntry color) trans.Palette[i] = pe; trans.Remap[i] = entry; } - AddTranslation(TRANSLATION_Blood, &trans); + palMgr.AddTranslation(TRANSLATION_Blood, &trans); return BloodTranslationColors.Push(color); } @@ -868,12 +819,12 @@ void R_InitTranslationTables () // maps until then so they won't be invalid. for (i = 0; i < MAXPLAYERS; ++i) { - PushIdentityTable(TRANSLATION_Players); - PushIdentityTable(TRANSLATION_PlayersExtra); - PushIdentityTable(TRANSLATION_RainPillar); + palMgr.PushIdentityTable(TRANSLATION_Players); + palMgr.PushIdentityTable(TRANSLATION_PlayersExtra); + palMgr.PushIdentityTable(TRANSLATION_RainPillar); } // The menu player also gets a separate translation table - PushIdentityTable(TRANSLATION_Players); + palMgr.PushIdentityTable(TRANSLATION_Players); // The three standard translations from Doom or Heretic (seven for Strife), // plus the generic ice translation. @@ -887,7 +838,7 @@ void R_InitTranslationTables () // color if the player who created them changes theirs. for (i = 0; i < FLevelLocals::BODYQUESIZE; ++i) { - PushIdentityTable(TRANSLATION_PlayerCorpses); + palMgr.PushIdentityTable(TRANSLATION_PlayerCorpses); } // Create the standard translation tables @@ -1023,26 +974,10 @@ void R_InitTranslationTables () remap->Remap[i] = v; remap->Palette[i] = PalEntry(255, v, v, v); } - AddTranslation(TRANSLATION_Standard, stdremaps, 10); + palMgr.AddTranslation(TRANSLATION_Standard, stdremaps, 10); } -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void R_DeinitTranslationTables() -{ - for (int i = 0; i < NUM_TRANSLATION_TABLES; ++i) - { - ClearTranslationSlot(i); - } - BloodTranslationColors.Clear(); - remapArena.FreeAllBlocks(); -} - //---------------------------------------------------------------------------- // // [RH] Create a player's translation table based on a given mid-range color. @@ -1153,7 +1088,6 @@ static void R_CreatePlayerTranslation (float h, float s, float v, const FPlayerC if (start == 0 && end == 0) { table->Inactive = true; - table->UpdateNative(); return; } @@ -1242,7 +1176,6 @@ static void R_CreatePlayerTranslation (float h, float s, float v, const FPlayerC SetRemap(alttable, i, r, g, b); SetPillarRemap(pillartable, i, h, s, v); } - alttable->UpdateNative(); } } else if (gameinfo.gametype == GAME_Hexen) @@ -1300,10 +1233,8 @@ static void R_CreatePlayerTranslation (float h, float s, float v, const FPlayerC SetRemap(alttable, i, r, g, b); } } - alttable->UpdateNative(); } - table->UpdateNative(); -} + } //---------------------------------------------------------------------------- // @@ -1321,9 +1252,9 @@ void R_BuildPlayerTranslation (int player) FRemapTable remaps[3]; R_CreatePlayerTranslation (h, s, v, colorset, &Skins[players[player].userinfo.GetSkin()], &remaps[0], &remaps[1], &remaps[2]); - UpdateTranslation(TRANSLATION(TRANSLATION_Players, player), &remaps[0]); - UpdateTranslation(TRANSLATION(TRANSLATION_PlayersExtra, player), &remaps[1]); - UpdateTranslation(TRANSLATION(TRANSLATION_RainPillar, player), &remaps[2]); + palMgr.UpdateTranslation(TRANSLATION(TRANSLATION_Players, player), &remaps[0]); + palMgr.UpdateTranslation(TRANSLATION(TRANSLATION_PlayersExtra, player), &remaps[1]); + palMgr.UpdateTranslation(TRANSLATION(TRANSLATION_RainPillar, player), &remaps[2]); } //---------------------------------------------------------------------------- @@ -1370,7 +1301,7 @@ DEFINE_ACTION_FUNCTION(_Translation, SetPlayerTranslation) FRemapTable remap; R_GetPlayerTranslation(PlayerColor, GetColorSet(cls->Type, PlayerColorset), &Skins[PlayerSkin], &remap); - UpdateTranslation(TRANSLATION(tgroup, tnum), &remap); + palMgr.UpdateTranslation(TRANSLATION(tgroup, tnum), &remap); } ACTION_RETURN_BOOL(true); } @@ -1434,7 +1365,7 @@ DEFINE_ACTION_FUNCTION(_Translation, GetID) void R_ParseTrnslate() { customTranslationMap.Clear(); - ClearTranslationSlot(TRANSLATION_Custom); + palMgr.ClearTranslationSlot(TRANSLATION_Custom); int lump; int lastlump = 0; @@ -1457,7 +1388,7 @@ void R_ParseTrnslate() { sc.ScriptError("Translation must be in the range [0,%d]", max); } - NewTranslation = *TranslationToTable(TRANSLATION(TRANSLATION_Standard, sc.Number)); + NewTranslation = *palMgr.TranslationToTable(TRANSLATION(TRANSLATION_Standard, sc.Number)); } else if (sc.TokenType == TK_Identifier) { @@ -1466,7 +1397,7 @@ void R_ParseTrnslate() { sc.ScriptError("Base translation '%s' not found in '%s'", sc.String, newtrans.GetChars()); } - NewTranslation = *TranslationToTable(tnum); + NewTranslation = *palMgr.TranslationToTable(tnum); } else { @@ -1505,7 +1436,7 @@ void R_ParseTrnslate() } } while (sc.CheckToken(',')); - int trans = NewTranslation.StoreTranslation(TRANSLATION_Custom); + int trans = palMgr.StoreTranslation(TRANSLATION_Custom, &NewTranslation); customTranslationMap[newtrans] = trans; } } @@ -1532,7 +1463,7 @@ DEFINE_ACTION_FUNCTION(_Translation, AddTranslation) { NewTranslation.Remap[i] = ColorMatcher.Pick(self->colors[i]); } - int trans = NewTranslation.StoreTranslation(TRANSLATION_Custom); + int trans = palMgr.StoreTranslation(TRANSLATION_Custom, &NewTranslation); ACTION_RETURN_INT(trans); } diff --git a/src/r_data/r_translate.h b/src/r_data/r_translate.h index e86c47658..58c839ecc 100644 --- a/src/r_data/r_translate.h +++ b/src/r_data/r_translate.h @@ -3,27 +3,10 @@ #include "doomtype.h" #include "tarray.h" +#include "palutil.h" class FSerializer; -enum -{ - TRANSLATION_Invalid, - TRANSLATION_Players, - TRANSLATION_PlayersExtra, - TRANSLATION_Standard, - TRANSLATION_LevelScripted, - TRANSLATION_Decals, - TRANSLATION_PlayerCorpses, - TRANSLATION_Decorate, - TRANSLATION_Blood, - TRANSLATION_RainPillar, - TRANSLATION_Custom, - TRANSLATION_Font, - - NUM_TRANSLATION_TABLES -}; - enum EStandardTranslations { STD_Ice = 7, @@ -31,115 +14,11 @@ enum EStandardTranslations STD_Grayscale = 9, // desaturated version of the palette. }; -struct FRemapTable; - -class FUniquePalette -{ - friend struct FRemapTable; - struct PalData - { - int crc32; - PalEntry pe[256]; - }; - static TArray AllPalettes; - - int Index; - FRemapTable *remap; - - FUniquePalette(FRemapTable *r) { remap = r; Index = -1; } - -public: - - static PalEntry *GetPalette(unsigned int index) - { - return index > 0 && index <= AllPalettes.Size() ? AllPalettes[index - 1].pe : NULL; - } - bool Update(); - int GetIndex() const { return Index; } -}; - - -struct FRemapTable -{ - FRemapTable(int count = 256) { NumEntries = count; } - FRemapTable(const FRemapTable& o) = default; - - bool operator==(const FRemapTable &o); - void MakeIdentity(); - void KillNative(); - void UpdateNative(); - bool IsIdentity() const; - void Serialize(FSerializer &arc); - static void StaticSerializeTranslations(FSerializer &arc); - bool AddIndexRange(int start, int end, int pal1, int pal2); - bool AddColorRange(int start, int end, int r1,int g1, int b1, int r2, int g2, int b2); - bool AddDesaturation(int start, int end, double r1, double g1, double b1, double r2, double g2, double b2); - bool AddColourisation(int start, int end, int r, int g, int b); - bool AddTint(int start, int end, int r, int g, int b, int amount); - bool AddToTranslation(const char * range); - bool AddColors(int start, int count, const uint8_t*); - int StoreTranslation(int slot); - int GetUniqueIndex(); - - uint8_t Remap[256]; // For the software renderer - PalEntry Palette[256]; // The ideal palette this maps to - FUniquePalette *Native = nullptr; // The index into the list of unique palettes (this is to avoid frequent texture recreation with changing ACS translations) - //int crc32; - int NumEntries; // # of elements in this table (usually 256) - bool Inactive = false; // This table is inactive and should be treated as if it was passed as NULL - -private: -}; - -// A class that initializes unusued pointers to NULL. This is used so that when -// the TAutoGrowArray below is expanded, the new elements will be NULLed. -class FRemapTablePtr -{ -public: - FRemapTablePtr() throw() : Ptr(0) {} - FRemapTablePtr(FRemapTable *p) throw() : Ptr(p) {} - FRemapTablePtr(const FRemapTablePtr &p) throw() : Ptr(p.Ptr) {} - operator FRemapTable *() const throw() { return Ptr; } - FRemapTablePtr &operator= (FRemapTable *p) throw() { Ptr = p; return *this; } - FRemapTablePtr &operator= (FRemapTablePtr &p) throw() { Ptr = p.Ptr; return *this; } - FRemapTable &operator*() const throw() { return *Ptr; } - FRemapTable *operator->() const throw() { return Ptr; } -private: - FRemapTable *Ptr; -}; - - -#define TRANSLATION_SHIFT 16 -#define TRANSLATION_MASK ((1<> TRANSLATION_SHIFT; -} -inline int GetTranslationIndex(uint32_t trans) -{ - return (trans&TRANSLATION_MASK); -} -// Retrieve the FRemapTable that an actor's translation value maps to. -FRemapTable *TranslationToTable(int translation); -void UpdateTranslation(int trans, FRemapTable* remap); -int AddTranslation(int slot, FRemapTable* remap, int count = 1); -FRemapTable* GetTranslation(int slot, int index); -void CopyTranslation(int dest, int src); -void ClearTranslationSlot(int slot); - - #define MAX_ACS_TRANSLATIONS 65535 #define MAX_DECORATE_TRANSLATIONS 65535 // Initialize color translation tables, for player rendering etc. void R_InitTranslationTables (void); -void R_DeinitTranslationTables(); void R_BuildPlayerTranslation (int player); // [RH] Actually create a player's translation table. void R_GetPlayerTranslation (int color, const struct FPlayerColorSet *colorset, class FPlayerSkin *skin, struct FRemapTable *table); @@ -150,6 +29,7 @@ int CreateBloodTranslation(PalEntry color); int R_FindCustomTranslation(FName name); void R_ParseTrnslate(); +void StaticSerializeTranslations(FSerializer& arc); struct TextureManipulation { diff --git a/src/rendering/gl/system/gl_framebuffer.cpp b/src/rendering/gl/system/gl_framebuffer.cpp index a69172c63..c1bfd9713 100644 --- a/src/rendering/gl/system/gl_framebuffer.cpp +++ b/src/rendering/gl/system/gl_framebuffer.cpp @@ -475,7 +475,7 @@ FTexture *OpenGLFrameBuffer::WipeStartScreen() const auto &viewport = screen->mScreenViewport; auto tex = new FWrapperTexture(viewport.width, viewport.height, 1); - tex->GetSystemTexture()->CreateTexture(nullptr, viewport.width, viewport.height, 0, false, 0, "WipeStartScreen"); + tex->GetSystemTexture()->CreateTexture(nullptr, viewport.width, viewport.height, 0, false, "WipeStartScreen"); glFinish(); static_cast(tex->GetSystemTexture())->Bind(0, false); @@ -497,7 +497,7 @@ FTexture *OpenGLFrameBuffer::WipeEndScreen() GLRenderer->Flush(); const auto &viewport = screen->mScreenViewport; auto tex = new FWrapperTexture(viewport.width, viewport.height, 1); - tex->GetSystemTexture()->CreateTexture(NULL, viewport.width, viewport.height, 0, false, 0, "WipeEndScreen"); + tex->GetSystemTexture()->CreateTexture(NULL, viewport.width, viewport.height, 0, false, "WipeEndScreen"); glFinish(); static_cast(tex->GetSystemTexture())->Bind(0, false); GLRenderer->mBuffers->BindCurrentFB(); diff --git a/src/rendering/gl/textures/gl_hwtexture.cpp b/src/rendering/gl/textures/gl_hwtexture.cpp index c864eedd2..177e35057 100644 --- a/src/rendering/gl/textures/gl_hwtexture.cpp +++ b/src/rendering/gl/textures/gl_hwtexture.cpp @@ -85,7 +85,7 @@ unsigned int FHardwareTexture::lastbound[FHardwareTexture::MAX_TEXTURES]; // //=========================================================================== -unsigned int FHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) +unsigned int FHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, const char *name) { int rh,rw; int texformat = GL_RGBA8;// TexFormat[gl_texture_format]; @@ -317,9 +317,6 @@ bool FHardwareTexture::BindOrCreate(FTexture *tex, int texunit, int clampmode, i { int usebright = false; - auto remap = TranslationToTable(translation); - translation = remap == nullptr ? 0 : remap->GetUniqueIndex(); - bool needmipmap = (clampmode <= CLAMP_XY); // Bind it to the system. @@ -343,7 +340,7 @@ bool FHardwareTexture::BindOrCreate(FTexture *tex, int texunit, int clampmode, i w = tex->GetWidth(); h = tex->GetHeight(); } - if (!CreateTexture(texbuffer.mBuffer, w, h, texunit, needmipmap, translation, "FHardwareTexture.BindOrCreate")) + if (!CreateTexture(texbuffer.mBuffer, w, h, texunit, needmipmap, "FHardwareTexture.BindOrCreate")) { // could not create texture return false; diff --git a/src/rendering/gl/textures/gl_hwtexture.h b/src/rendering/gl/textures/gl_hwtexture.h index db01f3637..faaa4febb 100644 --- a/src/rendering/gl/textures/gl_hwtexture.h +++ b/src/rendering/gl/textures/gl_hwtexture.h @@ -64,7 +64,7 @@ public: void AllocateBuffer(int w, int h, int texelsize); uint8_t *MapBuffer(); - unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name); + unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, const char *name); unsigned int GetTextureHandle(int translation); }; diff --git a/src/rendering/hwrenderer/textures/hw_ihwtexture.h b/src/rendering/hwrenderer/textures/hw_ihwtexture.h index 741bfd1bc..24b92c926 100644 --- a/src/rendering/hwrenderer/textures/hw_ihwtexture.h +++ b/src/rendering/hwrenderer/textures/hw_ihwtexture.h @@ -21,7 +21,7 @@ public: virtual void AllocateBuffer(int w, int h, int texelsize) = 0; virtual uint8_t *MapBuffer() = 0; - virtual unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) = 0; + virtual unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, const char *name) = 0; void Resize(int swidth, int sheight, int width, int height, unsigned char *src_data, unsigned char *dst_data); diff --git a/src/rendering/hwrenderer/textures/hw_precache.cpp b/src/rendering/hwrenderer/textures/hw_precache.cpp index ed024e77e..2e24e5110 100644 --- a/src/rendering/hwrenderer/textures/hw_precache.cpp +++ b/src/rendering/hwrenderer/textures/hw_precache.cpp @@ -110,8 +110,8 @@ void hw_PrecacheTexture(uint8_t *texhitlist, TMap &actorhitl while (it.NextPair(pair)) { PClassActor *cls = pair->Key; - auto remap = TranslationToTable(GetDefaultByType(cls)->Translation); - int gltrans = remap == nullptr ? 0 : remap->GetUniqueIndex(); + auto remap = palMgr.TranslationToTable(GetDefaultByType(cls)->Translation); + int gltrans = remap == nullptr ? 0 : remap->Index; for (unsigned i = 0; i < cls->GetStateCount(); i++) { diff --git a/src/rendering/hwrenderer/textures/hw_texcontainer.h b/src/rendering/hwrenderer/textures/hw_texcontainer.h index 87abb95ae..11cc48172 100644 --- a/src/rendering/hwrenderer/textures/hw_texcontainer.h +++ b/src/rendering/hwrenderer/textures/hw_texcontainer.h @@ -42,9 +42,11 @@ private: TranslatedTexture hwDefTex[2]; TArray hwTex_Translated; - TranslatedTexture * GetTexID(int translation, bool expanded) + TranslatedTexture * GetTexID(int translation, bool expanded) { - translation = TranslationToIndex(translation); + auto remap = palMgr.TranslationToTable(translation); + translation = remap == nullptr ? 0 : remap->Index; + if (translation == 0) { return &hwDefTex[expanded]; @@ -122,12 +124,6 @@ public: } } - static int TranslationToIndex(int translation) - { - auto remap = TranslationToTable(translation); - return remap == nullptr ? 0 : remap->GetUniqueIndex(); - } - template void Iterate(T callback) { diff --git a/src/rendering/polyrenderer/backend/poly_hwtexture.cpp b/src/rendering/polyrenderer/backend/poly_hwtexture.cpp index ffac7f547..17d162405 100644 --- a/src/rendering/polyrenderer/backend/poly_hwtexture.cpp +++ b/src/rendering/polyrenderer/backend/poly_hwtexture.cpp @@ -130,7 +130,7 @@ uint8_t *PolyHardwareTexture::MapBuffer() return mCanvas->GetPixels(); } -unsigned int PolyHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) +unsigned int PolyHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, const char *name) { return 0; } @@ -166,9 +166,6 @@ void PolyHardwareTexture::CreateImage(FTexture *tex, int translation, int flags) if (!tex->isHardwareCanvas()) { - auto remap = TranslationToTable(translation); - translation = remap == nullptr ? 0 : remap->GetUniqueIndex(); - FTextureBuffer texbuffer = tex->CreateTexBuffer(translation, flags | CTF_ProcessData); mCanvas->Resize(texbuffer.mWidth, texbuffer.mHeight, false); memcpy(mCanvas->GetPixels(), texbuffer.mBuffer, texbuffer.mWidth * texbuffer.mHeight * 4); diff --git a/src/rendering/polyrenderer/backend/poly_hwtexture.h b/src/rendering/polyrenderer/backend/poly_hwtexture.h index d88604c66..2aeba3b55 100644 --- a/src/rendering/polyrenderer/backend/poly_hwtexture.h +++ b/src/rendering/polyrenderer/backend/poly_hwtexture.h @@ -32,7 +32,7 @@ public: // Software renderer stuff void AllocateBuffer(int w, int h, int texelsize) override; uint8_t *MapBuffer() override; - unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) override; + unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, const char *name) override; // Wipe screen void CreateWipeTexture(int w, int h, const char *name); diff --git a/src/rendering/swrenderer/r_swscene.cpp b/src/rendering/swrenderer/r_swscene.cpp index 7e432fb52..1c78c6146 100644 --- a/src/rendering/swrenderer/r_swscene.cpp +++ b/src/rendering/swrenderer/r_swscene.cpp @@ -112,7 +112,7 @@ sector_t *SWSceneDrawer::RenderView(player_t *player) auto buf = systemTexture->MapBuffer(); if (!buf) I_FatalError("Unable to map buffer for software rendering"); SWRenderer->RenderView(player, Canvas.get(), buf, systemTexture->GetBufferPitch()); - systemTexture->CreateTexture(nullptr, screen->GetWidth(), screen->GetHeight(), 0, false, 0, "swbuffer"); + systemTexture->CreateTexture(nullptr, screen->GetWidth(), screen->GetHeight(), 0, false, "swbuffer"); auto map = swrenderer::CameraLight::Instance()->ShaderColormap(); screen->DrawTexture(fbtex.get(), 0, 0, DTA_SpecialColormap, map, TAG_DONE); diff --git a/src/rendering/swrenderer/viewport/r_spritedrawer.cpp b/src/rendering/swrenderer/viewport/r_spritedrawer.cpp index 7d3af54ec..efa445df9 100644 --- a/src/rendering/swrenderer/viewport/r_spritedrawer.cpp +++ b/src/rendering/swrenderer/viewport/r_spritedrawer.cpp @@ -474,7 +474,7 @@ namespace swrenderer SetTranslationMap(nullptr); if (translation != 0) { - FRemapTable *table = TranslationToTable(translation); + FRemapTable *table = palMgr.TranslationToTable(translation); if (table != NULL && !table->Inactive) { if (viewport->RenderTarget->IsBgra()) diff --git a/src/rendering/v_framebuffer.cpp b/src/rendering/v_framebuffer.cpp index 39b86251d..ec693b3af 100644 --- a/src/rendering/v_framebuffer.cpp +++ b/src/rendering/v_framebuffer.cpp @@ -132,7 +132,7 @@ void V_DrawPaletteTester(int paletteno) PalEntry pe; if (t > 1) { - auto palette = GetTranslation(TRANSLATION_Standard, t - 2)->Palette; + auto palette = palMgr.GetTranslation(TRANSLATION_Standard, t - 2)->Palette; pe = palette[k]; } else GPalette.BaseColors[k]; diff --git a/src/rendering/v_video.h b/src/rendering/v_video.h index 580f711e3..01745c8d4 100644 --- a/src/rendering/v_video.h +++ b/src/rendering/v_video.h @@ -350,7 +350,6 @@ protected: bool Bgra; }; -class FUniquePalette; class IHardwareTexture; class FTexture; diff --git a/src/rendering/vulkan/textures/vk_hwtexture.cpp b/src/rendering/vulkan/textures/vk_hwtexture.cpp index 90180776b..49771cdba 100644 --- a/src/rendering/vulkan/textures/vk_hwtexture.cpp +++ b/src/rendering/vulkan/textures/vk_hwtexture.cpp @@ -207,9 +207,6 @@ void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags) { if (!tex->isHardwareCanvas()) { - auto remap = TranslationToTable(translation); - translation = remap == nullptr ? 0 : remap->GetUniqueIndex(); - FTextureBuffer texbuffer = tex->CreateTexBuffer(translation, flags | CTF_ProcessData); CreateTexture(texbuffer.mWidth, texbuffer.mHeight, 4, VK_FORMAT_B8G8R8A8_UNORM, texbuffer.mBuffer); } @@ -348,7 +345,7 @@ uint8_t *VkHardwareTexture::MapBuffer() return mappedSWFB; } -unsigned int VkHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) +unsigned int VkHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, const char *name) { return 0; } diff --git a/src/rendering/vulkan/textures/vk_hwtexture.h b/src/rendering/vulkan/textures/vk_hwtexture.h index 9770cb1c0..160f9060a 100644 --- a/src/rendering/vulkan/textures/vk_hwtexture.h +++ b/src/rendering/vulkan/textures/vk_hwtexture.h @@ -34,7 +34,7 @@ public: // Software renderer stuff void AllocateBuffer(int w, int h, int texelsize) override; uint8_t *MapBuffer() override; - unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) override; + unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, const char *name) override; // Wipe screen void CreateWipeTexture(int w, int h, const char *name); diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index ca1679ea5..caae2b9d8 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -756,7 +756,7 @@ DEFINE_PROPERTY(translation, L, Actor) } } } - defaults->Translation = CurrentTranslation.StoreTranslation (TRANSLATION_Decorate); + defaults->Translation = palMgr.StoreTranslation (TRANSLATION_Decorate, &CurrentTranslation); } } diff --git a/src/utility/palutil.h b/src/utility/palutil.h index b06712777..13cd8b711 100644 --- a/src/utility/palutil.h +++ b/src/utility/palutil.h @@ -1,7 +1,8 @@ #pragma once #include -struct PalEntry; +#include "memarena.h" +#include "palentry.h" int BestColor(const uint32_t* pal, int r, int g, int b, int first = 1, int num = 255); int PTM_BestColor(const uint32_t* pal_in, int r, int g, int b, bool reverselookup, float powtable, int first = 1, int num = 255); @@ -9,3 +10,124 @@ void DoBlending(const PalEntry* from, PalEntry* to, int count, int r, int g, int // Colorspace conversion RGB <-> HSV void RGBtoHSV (float r, float g, float b, float *h, float *s, float *v); void HSVtoRGB (float *r, float *g, float *b, float h, float s, float v); + +struct FRemapTable +{ + FRemapTable(int count = 256) { NumEntries = count; } + FRemapTable(const FRemapTable& o) = default; + + bool operator==(const FRemapTable& o); + void MakeIdentity(); + bool IsIdentity() const; + bool AddIndexRange(int start, int end, int pal1, int pal2); + bool AddColorRange(int start, int end, int r1, int g1, int b1, int r2, int g2, int b2); + bool AddDesaturation(int start, int end, double r1, double g1, double b1, double r2, double g2, double b2); + bool AddColourisation(int start, int end, int r, int g, int b); + bool AddTint(int start, int end, int r, int g, int b, int amount); + bool AddToTranslation(const char* range); + bool AddColors(int start, int count, const uint8_t*); + + uint8_t Remap[256]; // For the software renderer + PalEntry Palette[256]; // The ideal palette this maps to + int crc32; + int Index; + int NumEntries; // # of elements in this table (usually 256) + bool Inactive = false; // This table is inactive and should be treated as if it was passed as NULL + +private: +}; + +// A class that initializes unusued pointers to NULL. This is used so that when +// the TAutoGrowArray below is expanded, the new elements will be NULLed. +class FRemapTablePtr +{ +public: + FRemapTablePtr() throw() : Ptr(0) {} + FRemapTablePtr(FRemapTable* p) throw() : Ptr(p) {} + FRemapTablePtr(const FRemapTablePtr& p) throw() : Ptr(p.Ptr) {} + operator FRemapTable* () const throw() { return Ptr; } + FRemapTablePtr& operator= (FRemapTable* p) throw() { Ptr = p; return *this; } + FRemapTablePtr& operator= (FRemapTablePtr& p) throw() { Ptr = p.Ptr; return *this; } + FRemapTable& operator*() const throw() { return *Ptr; } + FRemapTable* operator->() const throw() { return Ptr; } +private: + FRemapTable* Ptr = nullptr; +}; + + +#define TRANSLATION_SHIFT 16 +#define TRANSLATION_MASK ((1<> TRANSLATION_SHIFT; +} +inline int GetTranslationIndex(uint32_t trans) +{ + return (trans & TRANSLATION_MASK); +} + +// Fixme: This should avoid hard game content dependencies! +enum +{ + TRANSLATION_Invalid, + TRANSLATION_Players, + TRANSLATION_PlayersExtra, + TRANSLATION_Standard, + TRANSLATION_LevelScripted, + TRANSLATION_Decals, + TRANSLATION_PlayerCorpses, + TRANSLATION_Decorate, + TRANSLATION_Blood, + TRANSLATION_RainPillar, + TRANSLATION_Custom, + TRANSLATION_Font, + + NUM_TRANSLATION_TABLES +}; + + +class PaletteContainer +{ + FMemArena remapArena; + TArray uniqueRemaps; + TAutoGrowArray TranslationTables[NUM_TRANSLATION_TABLES]; +public: + void Init(); // This cannot be a constructor!!! + void Clear(); + FRemapTable* AddRemap(FRemapTable* remap); + void UpdateTranslation(int trans, FRemapTable* remap); + int AddTranslation(int slot, FRemapTable* remap, int count = 1); + void CopyTranslation(int dest, int src); + int StoreTranslation(int slot, FRemapTable* remap); + FRemapTable* TranslationToTable(int translation); + + void PushIdentityTable(int slot) + { + AddTranslation(slot, nullptr); + } + + FRemapTable* GetTranslation(int slot, int index) + { + return TranslationTables[slot].GetVal(index); + } + + void ClearTranslationSlot(int slot) + { + TranslationTables[slot].Clear(); + } + + unsigned NumTranslations(int slot) const + { + return TranslationTables[slot].Size(); + } + +}; + +extern PaletteContainer palMgr; +