diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 706b9df55..589123f11 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,12 @@ +December 26, 2007 (Changes by Graf Zahl) +- Split off the entire translation code from r_draw.cpp into r_translate.cpp. +- Moved the common code of ACS and DECORATE translation generation into the + FRemapTable class. +- Fixed: The DECORATE translation code was not changed for the new data structures. +- Expanded range of ACS and DECORATE translations to 65535. +- Fixed: R_CopyTranslation was not altered for the new functionality. + I removed the function and replaced the one use with a simple assignment. + December 25, 2007 - Fixed: The fullscreen console crashed when opened before starting a game. - Discovered that Shader Model 1.4 clamps my constants, so I can't use diff --git a/src/actor.h b/src/actor.h index 21cc84001..3320d026d 100644 --- a/src/actor.h +++ b/src/actor.h @@ -714,7 +714,7 @@ public: BYTE FloatBobPhase; BYTE FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc) - WORD Translation; + DWORD Translation; // [RH] Stuff that used to be part of an Actor Info WORD SeeSound; diff --git a/src/am_map.cpp b/src/am_map.cpp index 66fc2435c..c4e9f9336 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -33,6 +33,7 @@ #include "w_wad.h" #include "a_sharedglobal.h" #include "statnums.h" +#include "r_translate.h" #include "m_cheat.h" #include "i_system.h" diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 9489ce8d3..fdde1cc5e 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -66,6 +66,7 @@ #include "thingdef/thingdef.h" #include "vectors.h" #include "dobject.h" +#include "r_translate.h" // [SO] Just the way Randy said to do it :) // [RH] Made this CVAR_SERVERINFO diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 663639ca5..1948056b9 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -53,6 +53,7 @@ #include "gi.h" #include "m_random.h" #include "teaminfo.h" +#include "r_translate.h" static FRandom pr_pickteam ("PickRandomTeam"); diff --git a/src/decallib.cpp b/src/decallib.cpp index e7163820f..ce356779b 100644 --- a/src/decallib.cpp +++ b/src/decallib.cpp @@ -44,6 +44,7 @@ #include "templates.h" #include "r_draw.h" #include "a_sharedglobal.h" +#include "r_translate.h" FDecalLib DecalLibrary; diff --git a/src/decallib.h b/src/decallib.h index e1cc4bf1d..c77b3abdb 100644 --- a/src/decallib.h +++ b/src/decallib.h @@ -76,7 +76,7 @@ public: fixed_t ScaleX, ScaleY; DWORD ShadeColor; - WORD Translation; + DWORD Translation; BYTE RenderStyle; WORD PicNum; WORD RenderFlags; diff --git a/src/f_finale.cpp b/src/f_finale.cpp index 77873af68..e2d2b4e93 100644 --- a/src/f_finale.cpp +++ b/src/f_finale.cpp @@ -45,6 +45,7 @@ #include "a_strifeglobal.h" #include "templates.h" #include "c_bind.h" +#include "r_translate.h" static void FadePic (); static void GetFinaleText (const char *msgLumpName); diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp index 11939681e..83aa31312 100644 --- a/src/g_doom/a_scriptedmarine.cpp +++ b/src/g_doom/a_scriptedmarine.cpp @@ -6,6 +6,7 @@ #include "p_local.h" #include "a_doomglobal.h" #include "s_sound.h" +#include "r_translate.h" #define MARINE_PAIN_CHANCE 160 diff --git a/src/g_doom/doom_sbar.cpp b/src/g_doom/doom_sbar.cpp index 64b417489..1f5139c0a 100644 --- a/src/g_doom/doom_sbar.cpp +++ b/src/g_doom/doom_sbar.cpp @@ -13,6 +13,7 @@ #include "a_keys.h" #include "templates.h" #include "i_system.h" +#include "r_translate.h" #define ST_EVILGRINCOUNT (2*TICRATE) diff --git a/src/g_game.cpp b/src/g_game.cpp index 29d2e408b..4eb7b1d0a 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -72,6 +72,7 @@ #include "gi.h" #include "a_keys.h" #include "a_artifacts.h" +#include "r_translate.h" #include @@ -1399,7 +1400,7 @@ static void G_QueueBody (AActor *body) if (GetTranslationType(body->Translation) == TRANSLATION_Players || GetTranslationType(body->Translation) == TRANSLATION_PlayersExtra) { - R_CopyTranslation (TRANSLATION(TRANSLATION_PlayerCorpses,modslot), body->Translation); + translationtables[TRANSLATION_PlayerCorpses][modslot] = TranslationToTable(body->Translation); body->Translation = TRANSLATION(TRANSLATION_PlayerCorpses,modslot); } diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index 638c5d570..ec4abd3f6 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -13,6 +13,7 @@ #include "gstrings.h" #include "p_enemy.h" #include "gi.h" +#include "r_translate.h" static FRandom pr_sap ("StaffAtkPL1"); static FRandom pr_sap2 ("StaffAtkPL2"); diff --git a/src/g_heretic/heretic_sbar.cpp b/src/g_heretic/heretic_sbar.cpp index 05a93004e..3065ee474 100644 --- a/src/g_heretic/heretic_sbar.cpp +++ b/src/g_heretic/heretic_sbar.cpp @@ -13,6 +13,7 @@ #include "r_draw.h" #include "templates.h" #include "a_keys.h" +#include "r_translate.h" static FRandom pr_chainwiggle; diff --git a/src/g_hexen/hexen_sbar.cpp b/src/g_hexen/hexen_sbar.cpp index c0e6fea9f..3f1b24a85 100644 --- a/src/g_hexen/hexen_sbar.cpp +++ b/src/g_hexen/hexen_sbar.cpp @@ -14,6 +14,7 @@ #include "templates.h" #include "a_hexenglobal.h" #include "a_keys.h" +#include "r_translate.h" class FManaBar : public FTexture diff --git a/src/g_level.cpp b/src/g_level.cpp index 70762ebe4..5585d1601 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -73,6 +73,7 @@ #include "statnums.h" #include "vectors.h" #include "sbarinfo.h" +#include "r_translate.h" #include "gi.h" @@ -2688,58 +2689,37 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad) // Does this level have custom translations? FRemapTable *trans; + WORD w; if (arc.IsStoring ()) { for (unsigned int i = 0; i < translationtables[TRANSLATION_LevelScripted].Size(); ++i) { trans = translationtables[TRANSLATION_LevelScripted][i]; - int j; - for (j = 0; j < 256; ++j) + if (trans != NULL && !trans->IsIdentity()) { - if (trans->Remap[j] != j) - { - break; - } - } - if (j < 256) - { - t = i; - arc << t; - arc.Write (trans->Remap, 256); - for (j = 0; j < 256; ++j) - { - arc << trans->Palette[j].r - << trans->Palette[j].g - << trans->Palette[j].b; - } + w = WORD(i); + arc << w; + trans->Serialize(arc); } } - t = 255; - arc << t; + w = 0xffff; + arc << w; } else { - arc << t; - while (t != 255) + while (arc << w, w != 0xffff) { - if (t >= MAX_ACS_TRANSLATIONS) + if (w >= MAX_ACS_TRANSLATIONS) { // hack hack to avoid crashing - t = 0; + w = 0; } - trans = translationtables[TRANSLATION_LevelScripted].GetVal(t); + trans = translationtables[TRANSLATION_LevelScripted].GetVal(w); if (trans == NULL) { trans = new FRemapTable; translationtables[TRANSLATION_LevelScripted].SetVal(t, trans); } - arc.Read (trans->Remap, 256); - for (int j = 0; j < 256; ++j) - { - arc << trans->Palette[j].r - << trans->Palette[j].g - << trans->Palette[j].b; - } - arc << t; + trans->Serialize(arc); } } diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index eff8549ce..d47558fcb 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -16,6 +16,7 @@ #include "sbarinfo.h" #include "sc_man.h" #include "gi.h" +#include "r_translate.h" static FRandom pr_chainwiggle; //use the same method of chain wiggling as heretic. diff --git a/src/g_strife/a_acolyte.cpp b/src/g_strife/a_acolyte.cpp index c9ab8ca8a..0d7fa4e4e 100644 --- a/src/g_strife/a_acolyte.cpp +++ b/src/g_strife/a_acolyte.cpp @@ -6,6 +6,7 @@ #include "s_sound.h" #include "a_strifeglobal.h" #include "doomdata.h" +#include "r_translate.h" void A_BeShadowyFoe (AActor *); void A_AcolyteBits (AActor *); diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 5ccc45a21..25c013069 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -42,6 +42,7 @@ #include "templates.h" #include "p_lnspec.h" #include "c_console.h" +#include "r_translate.h" // [RH] Actually handle the cheat. The cheat code in st_stuff.c now just // writes some bytes to the network data stream, and the network code diff --git a/src/m_menu.cpp b/src/m_menu.cpp index dffa64b9e..15ce9cf85 100644 --- a/src/m_menu.cpp +++ b/src/m_menu.cpp @@ -66,6 +66,7 @@ #include "p_tick.h" #include "st_start.h" #include "teaminfo.h" +#include "r_translate.h" // MACROS ------------------------------------------------------------------ diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 73ae1e90f..40ed4629a 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -66,6 +66,7 @@ #include "sc_man.h" #include "c_bind.h" #include "info.h" +#include "r_translate.h" extern FILE *Logfile; @@ -4691,31 +4692,10 @@ int DLevelScript::RunScript () int end = STACK(3); int pal1 = STACK(2); int pal2 = STACK(1); - fixed_t palcol, palstep; sp -= 4; - if (translation == NULL) - { - break; - } - if (start > end) - { - swap (start, end); - swap (pal1, pal2); - } - else if (start == end) - { - translation->Remap[start] = pal1; - translation->Palette[start] = GPalette.BaseColors[pal1]; - break; - } - palcol = pal1 << FRACBITS; - palstep = ((pal2 << FRACBITS) - palcol) / (end - start); - for (int i = start; i <= end; palcol += palstep, ++i) - { - translation->Remap[i] = palcol >> FRACBITS; - translation->Palette[i] = GPalette.BaseColors[palcol >> FRACBITS]; - } + if (translation != NULL) + translation->AddIndexRange(start, end, pal1, pal2); } break; @@ -4724,58 +4704,16 @@ int DLevelScript::RunScript () // (would HSV be a good idea too?) int start = STACK(8); int end = STACK(7); - fixed_t r1 = STACK(6) << FRACBITS; - fixed_t g1 = STACK(5) << FRACBITS; - fixed_t b1 = STACK(4) << FRACBITS; - fixed_t r2 = STACK(3) << FRACBITS; - fixed_t g2 = STACK(2) << FRACBITS; - fixed_t b2 = STACK(1) << FRACBITS; - fixed_t r, g, b; - fixed_t rs, gs, bs; + int r1 = STACK(6); + int g1 = STACK(5); + int b1 = STACK(4); + int r2 = STACK(3); + int g2 = STACK(2); + int b2 = STACK(1); sp -= 8; - if (translation == NULL) - { - break; - } - if (start > end) - { - swap (start, end); - r = r2; - g = g2; - b = b2; - rs = r1 - r2; - gs = g1 - g2; - bs = b1 - b2; - } - else - { - r = r1; - g = g1; - b = b1; - rs = r2 - r1; - gs = g2 - g1; - bs = b2 - b1; - } - if (start == end) - { - translation->Remap[start] = ColorMatcher.Pick - (r >> FRACBITS, g >> FRACBITS, b >> FRACBITS); - translation->Palette[start] = PalEntry(r >> FRACBITS, g >> FRACBITS, b >> FRACBITS); - break; - } - rs /= (end - start); - gs /= (end - start); - bs /= (end - start); - for (int i = start; i <= end; ++i) - { - translation->Remap[i] = ColorMatcher.Pick - (r >> FRACBITS, g >> FRACBITS, b >> FRACBITS); - translation->Palette[i] = PalEntry(r >> FRACBITS, g >> FRACBITS, b >> FRACBITS); - r += rs; - g += gs; - b += bs; - } + if (translation != NULL) + translation->AddColorRange(start, end, r1, g1, b1, r2, g2, b2); } break; diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index e16dfdd3f..fb22c9361 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -52,6 +52,7 @@ #include "m_random.h" #include "p_conversation.h" #include "a_strifeglobal.h" +#include "r_translate.h" #define FUNC(a) static int a (line_t *ln, AActor *it, bool backSide, \ int arg0, int arg1, int arg2, int arg3, int arg4) @@ -1505,7 +1506,7 @@ FUNC(LS_Thing_SetTranslation) } else if (arg1 >= 1 && arg1 < MAX_ACS_TRANSLATIONS) { - range = (TRANSLATION_LevelScripted<<8)|(arg1-1); + range = TRANSLATION(TRANSLATION_LevelScripted, (arg1-1)); } else { diff --git a/src/p_map.cpp b/src/p_map.cpp index c6e7441f6..054e0ca84 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -52,6 +52,7 @@ #include "a_sharedglobal.h" #include "a_doomglobal.h" #include "p_conversation.h" +#include "r_translate.h" #define WATER_SINK_FACTOR 3 #define WATER_SINK_SMALL_FACTOR 4 diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 03e9ea268..43bd8f980 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -55,6 +55,7 @@ #include "thingdef/thingdef.h" #include "g_game.h" #include "teaminfo.h" +#include "r_translate.h" // MACROS ------------------------------------------------------------------ diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 2dd774b57..4cde527b9 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -58,6 +58,7 @@ #include "s_sndseq.h" #include "sbar.h" #include "p_setup.h" +#include "r_translate.h" extern void P_SpawnMapThing (mapthing2_t *mthing, int position); extern bool P_LoadBuildMap (BYTE *mapdata, size_t len, mapthing2_t **things, int *numthings); diff --git a/src/r_defs.h b/src/r_defs.h index e5a4b6151..e68e4366c 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -862,7 +862,7 @@ struct vissprite_t fixed_t floorclip; FTexture *pic; short renderflags; - WORD Translation; // [RH] for color translation + DWORD Translation; // [RH] for color translation BYTE RenderStyle; BYTE FakeFlatStat; // [RH] which side of fake/floor ceiling sprite is on BYTE bSplitSprite; // [RH] Sprite was split by a drawseg diff --git a/src/r_draw.cpp b/src/r_draw.cpp index 3c24e0e75..5db315d4b 100644 --- a/src/r_draw.cpp +++ b/src/r_draw.cpp @@ -37,6 +37,7 @@ #include "a_hexenglobal.h" #include "g_game.h" #include "g_level.h" +#include "r_translate.h" #include "gi.h" #include "stats.h" @@ -132,7 +133,6 @@ cycle_t DetailDoubleCycles; int dc_fillcolor; BYTE *dc_translation; -TAutoGrowArray translationtables[NUM_TRANSLATION_TABLES]; BYTE shadetables[NUMCOLORMAPS*16*256]; /************************************/ @@ -1406,502 +1406,7 @@ void tmvline4_addclamp () } while (--count); } -/****************************************************/ -/****************************************************/ -FRemapTable::FRemapTable(int count) -{ - assert(count <= 256); - - Alloc(count); - - // Note that the tables are left uninitialized. It is assumed that - // the caller will do that next, if only by calling MakeIdentity(). -} - -FRemapTable::~FRemapTable() -{ - Free(); -} - -void FRemapTable::Alloc(int count) -{ - Remap = (BYTE *)M_Malloc(count*sizeof(*Remap) + count*sizeof(*Palette)); - assert (Remap != NULL); - Palette = (PalEntry *)(Remap + count*(sizeof(*Remap))); - Native = NULL; - NumEntries = count; -} - -void FRemapTable::Free() -{ - KillNative(); - if (Remap != NULL) - { - free(Remap); - Remap = NULL; - Palette = NULL; - NumEntries = 0; - } -} - -FRemapTable::FRemapTable(const FRemapTable &o) -{ - Remap = NULL; - Native = NULL; - NumEntries = 0; - operator= (o); -} - -FRemapTable &FRemapTable::operator=(const FRemapTable &o) -{ - if (&o == this) - { - return *this; - } - if (o.NumEntries != NumEntries) - { - Free(); - } - if (Remap == NULL) - { - Alloc(o.NumEntries); - } - memcpy(Remap, o.Remap, NumEntries*sizeof(*Remap) + NumEntries*sizeof(*Palette)); - return *this; -} - -void FRemapTable::MakeIdentity() -{ - int i; - - for (i = 0; i < NumEntries; ++i) - { - Remap[i] = i; - } - for (i = 0; i < NumEntries; ++i) - { - Palette[i] = GPalette.BaseColors[i]; - } -} - -void FRemapTable::KillNative() -{ - if (Native != NULL) - { - delete Native; - Native = NULL; - } -} - -void FRemapTable::UpdateNative() -{ - if (Native != NULL) - { - Native->Update(); - } -} - -FNativeTexture *FRemapTable::GetNative() -{ - if (Native == NULL) - { - Native = screen->CreatePalette(this); - } - return Native; -} - -FRemapTable *TranslationToTable(int translation) -{ - unsigned int type = (translation & 0xFF00) >> 8; - unsigned int index = (translation & 0x00FF); - TAutoGrowArray *slots; - - if (type <= 0 || type >= NUM_TRANSLATION_TABLES) - { - return NULL; - } - slots = &translationtables[type]; - if (index >= slots->Size()) - { - return NULL; - } - return slots->operator[](index); -} - -static void PushIdentityTable(int slot) -{ - FRemapTable *table = new FRemapTable; - table->MakeIdentity(); - translationtables[slot].Push(table); -} - -// -// R_InitTranslationTables -// Creates the translation tables to map the green color ramp to gray, -// brown, red. Assumes a given structure of the PLAYPAL. -// -void R_InitTranslationTables () -{ - int i, j; - - // Each player gets two translations. Doom and Strife don't use the - // extra ones, but Heretic and Hexen do. These are set up during - // netgame arbitration and as-needed, so they just get to be identity - // maps until then so they won't be invalid. - for (i = 0; i < MAXPLAYERS; ++i) - { - PushIdentityTable(TRANSLATION_Players); - PushIdentityTable(TRANSLATION_PlayersExtra); - } - // The menu player also gets a separate translation table - PushIdentityTable(TRANSLATION_Players); - - // The three standard translations from Doom or Heretic (seven for Strife), - // plus the generic ice translation. - for (i = 0; i < 8; ++i) - { - PushIdentityTable(TRANSLATION_Standard); - } - - // Each player corpse has its own translation so they won't change - // color if the player who created them changes theirs. - for (i = 0; i < BODYQUESIZE; ++i) - { - PushIdentityTable(TRANSLATION_PlayerCorpses); - } - - // Create the standard translation tables - if (gameinfo.gametype == GAME_Doom) - { - for (i = 0x70; i < 0x80; i++) - { // map green ramp to gray, brown, red - translationtables[TRANSLATION_Standard][0]->Remap[i] = 0x60 + (i&0xf); - translationtables[TRANSLATION_Standard][1]->Remap[i] = 0x40 + (i&0xf); - translationtables[TRANSLATION_Standard][2]->Remap[i] = 0x20 + (i&0xf); - - translationtables[TRANSLATION_Standard][0]->Palette[i] = GPalette.BaseColors[0x60 + (i&0xf)]; - translationtables[TRANSLATION_Standard][1]->Palette[i] = GPalette.BaseColors[0x40 + (i&0xf)]; - translationtables[TRANSLATION_Standard][2]->Palette[i] = GPalette.BaseColors[0x20 + (i&0xf)]; - } - } - else if (gameinfo.gametype == GAME_Heretic) - { - for (i = 225; i <= 240; i++) - { - translationtables[TRANSLATION_Standard][0]->Remap[i] = 114+(i-225); // yellow - translationtables[TRANSLATION_Standard][1]->Remap[i] = 145+(i-225); // red - translationtables[TRANSLATION_Standard][2]->Remap[i] = 190+(i-225); // blue - - translationtables[TRANSLATION_Standard][0]->Palette[i] = GPalette.BaseColors[114+(i-225)]; - translationtables[TRANSLATION_Standard][1]->Palette[i] = GPalette.BaseColors[145+(i-225)]; - translationtables[TRANSLATION_Standard][2]->Palette[i] = GPalette.BaseColors[190+(i-225)]; - } - } - else if (gameinfo.gametype == GAME_Strife) - { - for (i = 0x20; i <= 0x3F; ++i) - { - translationtables[TRANSLATION_Standard][0]->Remap[i] = i - 0x20; - translationtables[TRANSLATION_Standard][1]->Remap[i] = i - 0x20; - translationtables[TRANSLATION_Standard][2]->Remap[i] = 0xD0 + (i&0xf); - translationtables[TRANSLATION_Standard][3]->Remap[i] = 0xD0 + (i&0xf); - translationtables[TRANSLATION_Standard][4]->Remap[i] = i - 0x20; - translationtables[TRANSLATION_Standard][5]->Remap[i] = i - 0x20; - translationtables[TRANSLATION_Standard][6]->Remap[i] = i - 0x20; - } - for (i = 0x50; i <= 0x5F; ++i) - { - // Merchant hair - translationtables[TRANSLATION_Standard][4]->Remap[i] = 0x80 + (i&0xf); - translationtables[TRANSLATION_Standard][5]->Remap[i] = 0x10 + (i&0xf); - translationtables[TRANSLATION_Standard][6]->Remap[i] = 0x40 + (i&0xf); - } - for (i = 0x80; i <= 0x8F; ++i) - { - translationtables[TRANSLATION_Standard][0]->Remap[i] = 0x40 + (i&0xf); // red - translationtables[TRANSLATION_Standard][1]->Remap[i] = 0xB0 + (i&0xf); // rust - translationtables[TRANSLATION_Standard][2]->Remap[i] = 0x10 + (i&0xf); // gray - translationtables[TRANSLATION_Standard][3]->Remap[i] = 0x30 + (i&0xf); // dark green - translationtables[TRANSLATION_Standard][4]->Remap[i] = 0x50 + (i&0xf); // gold - translationtables[TRANSLATION_Standard][5]->Remap[i] = 0x60 + (i&0xf); // bright green - translationtables[TRANSLATION_Standard][6]->Remap[i] = 0x90 + (i&0xf); // blue - } - for (i = 0xC0; i <= 0xCF; ++i) - { - translationtables[TRANSLATION_Standard][4]->Remap[i] = 0xA0 + (i&0xf); - translationtables[TRANSLATION_Standard][5]->Remap[i] = 0x20 + (i&0xf); - translationtables[TRANSLATION_Standard][6]->Remap[i] = (i&0xf); - } - translationtables[TRANSLATION_Standard][6]->Remap[0xC0] = 1; - for (i = 0xD0; i <= 0xDF; ++i) - { - translationtables[TRANSLATION_Standard][4]->Remap[i] = 0xB0 + (i&0xf); - translationtables[TRANSLATION_Standard][5]->Remap[i] = 0x30 + (i&0xf); - translationtables[TRANSLATION_Standard][6]->Remap[i] = 0x10 + (i&0xf); - } - for (i = 0xF1; i <= 0xF6; ++i) - { - translationtables[TRANSLATION_Standard][0]->Remap[i] = 0xDF + (i&0xf); - } - for (i = 0xF7; i <= 0xFB; ++i) - { - translationtables[TRANSLATION_Standard][0]->Remap[i] = i - 6; - } - for (i = 0; i < 7; ++i) - { - for (int j = 0x20; j <= 0xFB; ++j) - { - translationtables[TRANSLATION_Standard][i]->Palette[j] = - GPalette.BaseColors[translationtables[TRANSLATION_Standard][i]->Remap[j]]; - } - } - } - - // Create the ice translation table, based on Hexen's. Alas, the standard - // Doom palette has no good substitutes for these bluish-tinted grays, so - // they will just look gray unless you use a different PLAYPAL with Doom. - - static const BYTE IcePalette[16][3] = - { - { 10, 8, 18 }, - { 15, 15, 26 }, - { 20, 16, 36 }, - { 30, 26, 46 }, - { 40, 36, 57 }, - { 50, 46, 67 }, - { 59, 57, 78 }, - { 69, 67, 88 }, - { 79, 77, 99 }, - { 89, 87,109 }, - { 99, 97,120 }, - { 109,107,130 }, - { 118,118,141 }, - { 128,128,151 }, - { 138,138,162 }, - { 148,148,172 } - }; - BYTE IcePaletteRemap[16]; - for (i = 0; i < 16; ++i) - { - IcePaletteRemap[i] = ColorMatcher.Pick (IcePalette[i][0], IcePalette[i][1], IcePalette[i][2]); - } - FRemapTable *remap = translationtables[TRANSLATION_Standard][7]; - for (i = 0; i < 256; ++i) - { - int r = GPalette.BaseColors[i].r; - int g = GPalette.BaseColors[i].g; - int b = GPalette.BaseColors[i].b; - int v = (r*77 + g*143 + b*37) >> 12; - remap->Remap[i] = IcePaletteRemap[v]; - remap->Palette[i] = PalEntry(IcePalette[v][0], IcePalette[v][1], IcePalette[v][2]); - } - - // set up shading tables for shaded columns - // 16 colormap sets, progressing from full alpha to minimum visible alpha - - BYTE *table = shadetables; - - // Full alpha - for (i = 0; i < 16; ++i) - { - for (j = 0; j < NUMCOLORMAPS; ++j) - { - int a = (NUMCOLORMAPS - j) * 256 / NUMCOLORMAPS * (16-i); - for (int k = 0; k < 256; ++k) - { - BYTE v = (((k+2) * a) + 256) >> 14; - table[k] = MIN (v, 64); - } - table += 256; - } - } -} - -void R_DeinitTranslationTables() -{ - for (int i = 0; i < NUM_TRANSLATION_TABLES; ++i) - { - for (unsigned int j = 0; j < translationtables[i].Size(); ++j) - { - if (translationtables[i][j] != NULL) - { - delete translationtables[i][j]; - translationtables[i][j] = NULL; - } - } - } -} - -// [RH] Create a player's translation table based on a given mid-range color. -// [GRB] Split to 2 functions (because of player setup menu) -static void SetRemap(FRemapTable *table, int i, float r, float g, float b) -{ - int ir = clamp (int(r * 255.f), 0, 255); - int ig = clamp (int(g * 255.f), 0, 255); - int ib = clamp (int(b * 255.f), 0, 255); - table->Remap[i] = ColorMatcher.Pick (ir, ig, ib); - table->Palette[i] = PalEntry(ir, ig, ib); -} - -static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *skin, FRemapTable *table, FRemapTable *alttable) -{ - int i; - BYTE start = skin->range0start; - BYTE end = skin->range0end; - float r, g, b; - float bases, basev; - float sdelta, vdelta; - float range; - - // Set up the base translation for this skin. If the skin was created - // for the current game, then this is just an identity translation. - // Otherwise, it remaps the colors from the skin's original palette to - // the current one. - if (skin->othergame) - { - memcpy (table->Remap, OtherGameSkinRemap, 256); - memcpy (table->Palette, OtherGameSkinPalette, sizeof(table->Palette)); - } - else - { - for (i = 0; i < 256; ++i) - { - table->Remap[i] = i; - } - memcpy(table->Palette, GPalette.BaseColors, sizeof(table->Palette)); - } - - // [GRB] Don't translate skins with color range 0-0 (APlayerPawn default) - if (start == 0 && end == 0) - { - table->UpdateNative(); - return; - } - - range = (float)(end-start+1); - - bases = s; - basev = v; - - if (gameinfo.gametype == GAME_Doom || gameinfo.gametype == GAME_Strife) - { - // Build player sprite translation - s -= 0.23f; - v += 0.1f; - sdelta = 0.23f / range; - vdelta = -0.94112f / range; - - for (i = start; i <= end; i++) - { - float uses, usev; - uses = clamp (s, 0.f, 1.f); - usev = clamp (v, 0.f, 1.f); - HSVtoRGB (&r, &g, &b, h, uses, usev); - SetRemap(table, i, r, g, b); - s += sdelta; - v += vdelta; - } - } - else if (gameinfo.gametype == GAME_Heretic) - { - float vdelta = 0.418916f / range; - - // Build player sprite translation - for (i = start; i <= end; i++) - { - v = vdelta * (float)(i - start) + basev - 0.2352937f; - v = clamp (v, 0.f, 1.f); - HSVtoRGB (&r, &g, &b, h, s, v); - SetRemap(table, i, r, g, b); - } - - // Build rain/lifegem translation - if (alttable) - { - bases = MIN (bases*1.3f, 1.f); - basev = MIN (basev*1.3f, 1.f); - for (i = 145; i <= 168; i++) - { - s = MIN (bases, 0.8965f - 0.0962f*(float)(i - 161)); - v = MIN (1.f, (0.2102f + 0.0489f*(float)(i - 144)) * basev); - HSVtoRGB (&r, &g, &b, h, s, v); - SetRemap(alttable, i, r, g, b); - } - alttable->UpdateNative(); - } - } - else if (gameinfo.gametype == GAME_Hexen) - { - if (memcmp (sprites[skin->sprite].name, "PLAY", 4) == 0) - { // The fighter is different! He gets a brown hairy loincloth, but the other - // two have blue capes. - float vs[9] = { .28f, .32f, .38f, .42f, .47f, .5f, .58f, .71f, .83f }; - - // Build player sprite translation - //h = 45.f; - v = MAX (0.1f, v); - - for (i = start; i <= end; i++) - { - HSVtoRGB (&r, &g, &b, h, s, vs[(i-start)*9/(int)range]*basev); - SetRemap(table, i, r, g, b); - } - } - else - { - float ms[18] = { .95f, .96f, .89f, .97f, .97f, 1.f, 1.f, 1.f, .97f, .99f, .87f, .77f, .69f, .62f, .57f, .47f, .43f }; - float mv[18] = { .16f, .19f, .22f, .25f, .31f, .35f, .38f, .41f, .47f, .54f, .60f, .65f, .71f, .77f, .83f, .89f, .94f, 1.f }; - - // Build player sprite translation - v = MAX (0.1f, v); - - for (i = start; i <= end; i++) - { - HSVtoRGB (&r, &g, &b, h, ms[(i-start)*18/(int)range]*bases, mv[(i-start)*18/(int)range]*basev); - SetRemap(table, i, r, g, b); - } - } - - // Build lifegem translation - if (alttable) - { - for (i = 164; i <= 185; ++i) - { - const PalEntry *base = &GPalette.BaseColors[i]; - float dummy; - - RGBtoHSV (base->r/255.f, base->g/255.f, base->b/255.f, &dummy, &s, &v); - HSVtoRGB (&r, &g, &b, h, s*bases, v*basev); - SetRemap(alttable, i, r, g, b); - } - alttable->UpdateNative(); - } - } - table->UpdateNative(); -} - -void R_BuildPlayerTranslation (int player) -{ - float h, s, v; - - D_GetPlayerColor (player, &h, &s, &v); - - R_CreatePlayerTranslation (h, s, v, - &skins[players[player].userinfo.skin], - translationtables[TRANSLATION_Players][player], - translationtables[TRANSLATION_PlayersExtra][player]); -} - -void R_GetPlayerTranslation (int color, FPlayerSkin *skin, FRemapTable *table) -{ - float h, s, v; - - RGBtoHSV (RPART(color)/255.f, GPART(color)/255.f, BPART(color)/255.f, - &h, &s, &v); - - R_CreatePlayerTranslation (h, s, v, skin, table, NULL); -} void R_DrawBorder (int x1, int y1, int x2, int y2) { @@ -1926,7 +1431,6 @@ void R_DrawBorder (int x1, int y1, int x2, int y2) } } - /* ================== = diff --git a/src/r_draw.h b/src/r_draw.h index 41a636040..f26acc9a3 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -201,82 +201,13 @@ extern "C" const BYTE* ds_source; extern "C" int ds_color; // [RH] For flat color (no texturing) -enum -{ - TRANSLATION_Invalid, - TRANSLATION_Players, - TRANSLATION_PlayersExtra, - TRANSLATION_Standard, - TRANSLATION_LevelScripted, - TRANSLATION_Decals, - TRANSLATION_PlayerCorpses, - TRANSLATION_Decorate, - TRANSLATION_Blood, - TRANSLATION_Dim, - - NUM_TRANSLATION_TABLES -}; - -struct FRemapTable -{ - FRemapTable(int count=256); - FRemapTable(const FRemapTable &o); - ~FRemapTable(); - - FRemapTable &operator= (const FRemapTable &o); - void MakeIdentity(); - void KillNative(); - void UpdateNative(); - FNativeTexture *GetNative(); - - BYTE *Remap; // For the software renderer - PalEntry *Palette; // The ideal palette this maps to - FNativeTexture *Native; // The Palette stored in a HW texture - int NumEntries; // # of elements in this table (usually 256) - -private: - void Free(); - void Alloc(int count); -}; - -extern TAutoGrowArray translationtables[NUM_TRANSLATION_TABLES]; extern BYTE shadetables[NUMCOLORMAPS*16*256]; extern BYTE *dc_translation; -inline WORD TRANSLATION(BYTE a, BYTE b) -{ - return (a<<8) | b; -} -inline int GetTranslationType(WORD trans) -{ - return trans >> 8; -} -// Retrieve the FRemapTable that an actor's translation value maps to. -FRemapTable *TranslationToTable(int translation); - -#define DIM_MAP TRANSLATION(TRANSLATION_Dim, 0) - -const int MAX_ACS_TRANSLATIONS = 255; -const int MAX_DECORATE_TRANSLATIONS = 255; - -inline void R_CopyTranslation (WORD to, WORD from) -{ - memcpy (&translationtables[to>>8][(to&255)*256], - &translationtables[from>>8][(from&255)*256], 256); -} - - // [RH] Double view pixels by detail mode void R_DetailDouble (void); -// Initialize color translation tables, for player rendering etc. -void R_InitTranslationTables (void); -void R_DeinitTranslationTables(); - -// [RH] Actually create a player's translation table. -void R_BuildPlayerTranslation (int player); - // If the view size is not full screen, draws a border around it. void R_DrawViewBorder (void); diff --git a/src/r_main.cpp b/src/r_main.cpp index cdf21c181..7bfffb53f 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -46,6 +46,7 @@ #include "i_system.h" #include "vectors.h" #include "a_sharedglobal.h" +#include "r_translate.h" // MACROS ------------------------------------------------------------------ diff --git a/src/r_translate.cpp b/src/r_translate.cpp new file mode 100644 index 000000000..e3db07721 --- /dev/null +++ b/src/r_translate.cpp @@ -0,0 +1,670 @@ +/* +** r_translate.cpp +** Translatioo table handling +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include + +#include "templates.h" +#include "m_alloc.h" +#include "r_draw.h" +#include "r_translate.h" +#include "v_video.h" +#include "g_game.h" + +#include "gi.h" +#include "stats.h" + +TAutoGrowArray translationtables[NUM_TRANSLATION_TABLES]; + +/****************************************************/ +/****************************************************/ + +FRemapTable::FRemapTable(int count) +{ + assert(count <= 256); + + Alloc(count); + + // Note that the tables are left uninitialized. It is assumed that + // the caller will do that next, if only by calling MakeIdentity(). +} + +FRemapTable::~FRemapTable() +{ + Free(); +} + +void FRemapTable::Alloc(int count) +{ + Remap = (BYTE *)M_Malloc(count*sizeof(*Remap) + count*sizeof(*Palette)); + assert (Remap != NULL); + Palette = (PalEntry *)(Remap + count*(sizeof(*Remap))); + Native = NULL; + NumEntries = count; +} + +void FRemapTable::Free() +{ + KillNative(); + if (Remap != NULL) + { + free(Remap); + Remap = NULL; + Palette = NULL; + NumEntries = 0; + } +} + +FRemapTable::FRemapTable(const FRemapTable &o) +{ + Remap = NULL; + Native = NULL; + NumEntries = 0; + operator= (o); +} + +FRemapTable &FRemapTable::operator=(const FRemapTable &o) +{ + if (&o == this) + { + return *this; + } + if (o.NumEntries != NumEntries) + { + Free(); + } + if (Remap == NULL) + { + Alloc(o.NumEntries); + } + memcpy(Remap, o.Remap, NumEntries*sizeof(*Remap) + NumEntries*sizeof(*Palette)); + return *this; +} + +bool FRemapTable::operator==(const FRemapTable &o) +{ + // Two translations are identical when they have the same amount of colors + // and the palette values for both are identical. + if (&o == this) return true; + if (o.NumEntries != NumEntries) return false; + return !memcmp(o.Palette, Palette, NumEntries * sizeof(*Palette)); +} + +void FRemapTable::Serialize(FArchive &arc) +{ + int n = NumEntries; + + arc << NumEntries; + if (arc.IsStoring()) + { + arc.Write (Remap, NumEntries); + } + else + { + if (n != NumEntries) + { + Free(); + Alloc(NumEntries); + } + arc.Read (Remap, NumEntries); + } + for (int j = 0; j < NumEntries; ++j) + { + arc << Palette[j].r + << Palette[j].g + << Palette[j].b; + } +} + + +void FRemapTable::MakeIdentity() +{ + int i; + + for (i = 0; i < NumEntries; ++i) + { + Remap[i] = i; + } + for (i = 0; i < NumEntries; ++i) + { + Palette[i] = GPalette.BaseColors[i]; + } +} + +bool FRemapTable::IsIdentity() const +{ + for (int j = 0; j < 256; ++j) + { + if (Remap[j] != j) + { + return false; + } + } + return true; +} + +void FRemapTable::KillNative() +{ + if (Native != NULL) + { + delete Native; + Native = NULL; + } +} + +void FRemapTable::UpdateNative() +{ + if (Native != NULL) + { + Native->Update(); + } +} + +FNativeTexture *FRemapTable::GetNative() +{ + if (Native == NULL) + { + Native = screen->CreatePalette(this); + } + return Native; +} + +void FRemapTable::AddIndexRange(int start, int end, int pal1, int pal2) +{ + fixed_t palcol, palstep; + + if (start > end) + { + swap (start, end); + swap (pal1, pal2); + } + else if (start == end) + { + Remap[start] = pal1; + Palette[start] = GPalette.BaseColors[pal1]; + return; + } + palcol = pal1 << FRACBITS; + palstep = ((pal2 << FRACBITS) - palcol) / (end - start); + for (int i = start; i <= end; palcol += palstep, ++i) + { + Remap[i] = palcol >> FRACBITS; + Palette[i] = GPalette.BaseColors[palcol >> FRACBITS]; + } +} + +void FRemapTable::AddColorRange(int start, int end, int _r1,int _g1, int _b1, int _r2, int _g2, int _b2) +{ + fixed_t r1 = _r1 << FRACBITS; + fixed_t g1 = _g1 << FRACBITS; + fixed_t b1 = _b1 << FRACBITS; + fixed_t r2 = _r2 << FRACBITS; + fixed_t g2 = _g2 << FRACBITS; + fixed_t b2 = _b2 << FRACBITS; + fixed_t r, g, b; + fixed_t rs, gs, bs; + + if (start > end) + { + swap (start, end); + r = r2; + g = g2; + b = b2; + rs = r1 - r2; + gs = g1 - g2; + bs = b1 - b2; + } + else + { + r = r1; + g = g1; + b = b1; + rs = r2 - r1; + gs = g2 - g1; + bs = b2 - b1; + } + if (start == end) + { + Remap[start] = ColorMatcher.Pick + (r >> FRACBITS, g >> FRACBITS, b >> FRACBITS); + Palette[start] = PalEntry(r >> FRACBITS, g >> FRACBITS, b >> FRACBITS); + } + else + { + rs /= (end - start); + gs /= (end - start); + bs /= (end - start); + for (int i = start; i <= end; ++i) + { + Remap[i] = ColorMatcher.Pick + (r >> FRACBITS, g >> FRACBITS, b >> FRACBITS); + Palette[i] = PalEntry(r >> FRACBITS, g >> FRACBITS, b >> FRACBITS); + r += rs; + g += gs; + b += bs; + } + } +} + + +FRemapTable *TranslationToTable(int translation) +{ + unsigned int type = GetTranslationType(translation); + unsigned int index = GetTranslationIndex(translation); + TAutoGrowArray *slots; + + if (type <= 0 || type >= NUM_TRANSLATION_TABLES) + { + return NULL; + } + slots = &translationtables[type]; + if (index >= slots->Size()) + { + return NULL; + } + return slots->operator[](index); +} + +static void PushIdentityTable(int slot) +{ + FRemapTable *table = new FRemapTable; + table->MakeIdentity(); + translationtables[slot].Push(table); +} + +// +// R_InitTranslationTables +// Creates the translation tables to map the green color ramp to gray, +// brown, red. Assumes a given structure of the PLAYPAL. +// +void R_InitTranslationTables () +{ + int i, j; + + // Each player gets two translations. Doom and Strife don't use the + // extra ones, but Heretic and Hexen do. These are set up during + // netgame arbitration and as-needed, so they just get to be identity + // maps until then so they won't be invalid. + for (i = 0; i < MAXPLAYERS; ++i) + { + PushIdentityTable(TRANSLATION_Players); + PushIdentityTable(TRANSLATION_PlayersExtra); + } + // The menu player also gets a separate translation table + PushIdentityTable(TRANSLATION_Players); + + // The three standard translations from Doom or Heretic (seven for Strife), + // plus the generic ice translation. + for (i = 0; i < 8; ++i) + { + PushIdentityTable(TRANSLATION_Standard); + } + + // Each player corpse has its own translation so they won't change + // color if the player who created them changes theirs. + for (i = 0; i < BODYQUESIZE; ++i) + { + PushIdentityTable(TRANSLATION_PlayerCorpses); + } + + // Create the standard translation tables + if (gameinfo.gametype == GAME_Doom) + { + for (i = 0x70; i < 0x80; i++) + { // map green ramp to gray, brown, red + translationtables[TRANSLATION_Standard][0]->Remap[i] = 0x60 + (i&0xf); + translationtables[TRANSLATION_Standard][1]->Remap[i] = 0x40 + (i&0xf); + translationtables[TRANSLATION_Standard][2]->Remap[i] = 0x20 + (i&0xf); + + translationtables[TRANSLATION_Standard][0]->Palette[i] = GPalette.BaseColors[0x60 + (i&0xf)]; + translationtables[TRANSLATION_Standard][1]->Palette[i] = GPalette.BaseColors[0x40 + (i&0xf)]; + translationtables[TRANSLATION_Standard][2]->Palette[i] = GPalette.BaseColors[0x20 + (i&0xf)]; + } + } + else if (gameinfo.gametype == GAME_Heretic) + { + for (i = 225; i <= 240; i++) + { + translationtables[TRANSLATION_Standard][0]->Remap[i] = 114+(i-225); // yellow + translationtables[TRANSLATION_Standard][1]->Remap[i] = 145+(i-225); // red + translationtables[TRANSLATION_Standard][2]->Remap[i] = 190+(i-225); // blue + + translationtables[TRANSLATION_Standard][0]->Palette[i] = GPalette.BaseColors[114+(i-225)]; + translationtables[TRANSLATION_Standard][1]->Palette[i] = GPalette.BaseColors[145+(i-225)]; + translationtables[TRANSLATION_Standard][2]->Palette[i] = GPalette.BaseColors[190+(i-225)]; + } + } + else if (gameinfo.gametype == GAME_Strife) + { + for (i = 0x20; i <= 0x3F; ++i) + { + translationtables[TRANSLATION_Standard][0]->Remap[i] = i - 0x20; + translationtables[TRANSLATION_Standard][1]->Remap[i] = i - 0x20; + translationtables[TRANSLATION_Standard][2]->Remap[i] = 0xD0 + (i&0xf); + translationtables[TRANSLATION_Standard][3]->Remap[i] = 0xD0 + (i&0xf); + translationtables[TRANSLATION_Standard][4]->Remap[i] = i - 0x20; + translationtables[TRANSLATION_Standard][5]->Remap[i] = i - 0x20; + translationtables[TRANSLATION_Standard][6]->Remap[i] = i - 0x20; + } + for (i = 0x50; i <= 0x5F; ++i) + { + // Merchant hair + translationtables[TRANSLATION_Standard][4]->Remap[i] = 0x80 + (i&0xf); + translationtables[TRANSLATION_Standard][5]->Remap[i] = 0x10 + (i&0xf); + translationtables[TRANSLATION_Standard][6]->Remap[i] = 0x40 + (i&0xf); + } + for (i = 0x80; i <= 0x8F; ++i) + { + translationtables[TRANSLATION_Standard][0]->Remap[i] = 0x40 + (i&0xf); // red + translationtables[TRANSLATION_Standard][1]->Remap[i] = 0xB0 + (i&0xf); // rust + translationtables[TRANSLATION_Standard][2]->Remap[i] = 0x10 + (i&0xf); // gray + translationtables[TRANSLATION_Standard][3]->Remap[i] = 0x30 + (i&0xf); // dark green + translationtables[TRANSLATION_Standard][4]->Remap[i] = 0x50 + (i&0xf); // gold + translationtables[TRANSLATION_Standard][5]->Remap[i] = 0x60 + (i&0xf); // bright green + translationtables[TRANSLATION_Standard][6]->Remap[i] = 0x90 + (i&0xf); // blue + } + for (i = 0xC0; i <= 0xCF; ++i) + { + translationtables[TRANSLATION_Standard][4]->Remap[i] = 0xA0 + (i&0xf); + translationtables[TRANSLATION_Standard][5]->Remap[i] = 0x20 + (i&0xf); + translationtables[TRANSLATION_Standard][6]->Remap[i] = (i&0xf); + } + translationtables[TRANSLATION_Standard][6]->Remap[0xC0] = 1; + for (i = 0xD0; i <= 0xDF; ++i) + { + translationtables[TRANSLATION_Standard][4]->Remap[i] = 0xB0 + (i&0xf); + translationtables[TRANSLATION_Standard][5]->Remap[i] = 0x30 + (i&0xf); + translationtables[TRANSLATION_Standard][6]->Remap[i] = 0x10 + (i&0xf); + } + for (i = 0xF1; i <= 0xF6; ++i) + { + translationtables[TRANSLATION_Standard][0]->Remap[i] = 0xDF + (i&0xf); + } + for (i = 0xF7; i <= 0xFB; ++i) + { + translationtables[TRANSLATION_Standard][0]->Remap[i] = i - 6; + } + for (i = 0; i < 7; ++i) + { + for (int j = 0x20; j <= 0xFB; ++j) + { + translationtables[TRANSLATION_Standard][i]->Palette[j] = + GPalette.BaseColors[translationtables[TRANSLATION_Standard][i]->Remap[j]]; + } + } + } + + // Create the ice translation table, based on Hexen's. Alas, the standard + // Doom palette has no good substitutes for these bluish-tinted grays, so + // they will just look gray unless you use a different PLAYPAL with Doom. + + static const BYTE IcePalette[16][3] = + { + { 10, 8, 18 }, + { 15, 15, 26 }, + { 20, 16, 36 }, + { 30, 26, 46 }, + { 40, 36, 57 }, + { 50, 46, 67 }, + { 59, 57, 78 }, + { 69, 67, 88 }, + { 79, 77, 99 }, + { 89, 87,109 }, + { 99, 97,120 }, + { 109,107,130 }, + { 118,118,141 }, + { 128,128,151 }, + { 138,138,162 }, + { 148,148,172 } + }; + BYTE IcePaletteRemap[16]; + for (i = 0; i < 16; ++i) + { + IcePaletteRemap[i] = ColorMatcher.Pick (IcePalette[i][0], IcePalette[i][1], IcePalette[i][2]); + } + FRemapTable *remap = translationtables[TRANSLATION_Standard][7]; + for (i = 0; i < 256; ++i) + { + int r = GPalette.BaseColors[i].r; + int g = GPalette.BaseColors[i].g; + int b = GPalette.BaseColors[i].b; + int v = (r*77 + g*143 + b*37) >> 12; + remap->Remap[i] = IcePaletteRemap[v]; + remap->Palette[i] = PalEntry(IcePalette[v][0], IcePalette[v][1], IcePalette[v][2]); + } + + // set up shading tables for shaded columns + // 16 colormap sets, progressing from full alpha to minimum visible alpha + + BYTE *table = shadetables; + + // Full alpha + for (i = 0; i < 16; ++i) + { + for (j = 0; j < NUMCOLORMAPS; ++j) + { + int a = (NUMCOLORMAPS - j) * 256 / NUMCOLORMAPS * (16-i); + for (int k = 0; k < 256; ++k) + { + BYTE v = (((k+2) * a) + 256) >> 14; + table[k] = MIN (v, 64); + } + table += 256; + } + } +} + +void R_DeinitTranslationTables() +{ + for (int i = 0; i < NUM_TRANSLATION_TABLES; ++i) + { + for (unsigned int j = 0; j < translationtables[i].Size(); ++j) + { + if (translationtables[i][j] != NULL) + { + delete translationtables[i][j]; + translationtables[i][j] = NULL; + } + } + } +} + +// [RH] Create a player's translation table based on a given mid-range color. +// [GRB] Split to 2 functions (because of player setup menu) +static void SetRemap(FRemapTable *table, int i, float r, float g, float b) +{ + int ir = clamp (int(r * 255.f), 0, 255); + int ig = clamp (int(g * 255.f), 0, 255); + int ib = clamp (int(b * 255.f), 0, 255); + table->Remap[i] = ColorMatcher.Pick (ir, ig, ib); + table->Palette[i] = PalEntry(ir, ig, ib); +} + +static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *skin, FRemapTable *table, FRemapTable *alttable) +{ + int i; + BYTE start = skin->range0start; + BYTE end = skin->range0end; + float r, g, b; + float bases, basev; + float sdelta, vdelta; + float range; + + // Set up the base translation for this skin. If the skin was created + // for the current game, then this is just an identity translation. + // Otherwise, it remaps the colors from the skin's original palette to + // the current one. + if (skin->othergame) + { + memcpy (table->Remap, OtherGameSkinRemap, 256); + memcpy (table->Palette, OtherGameSkinPalette, sizeof(table->Palette)); + } + else + { + for (i = 0; i < 256; ++i) + { + table->Remap[i] = i; + } + memcpy(table->Palette, GPalette.BaseColors, sizeof(table->Palette)); + } + + // [GRB] Don't translate skins with color range 0-0 (APlayerPawn default) + if (start == 0 && end == 0) + { + table->UpdateNative(); + return; + } + + range = (float)(end-start+1); + + bases = s; + basev = v; + + if (gameinfo.gametype == GAME_Doom || gameinfo.gametype == GAME_Strife) + { + // Build player sprite translation + s -= 0.23f; + v += 0.1f; + sdelta = 0.23f / range; + vdelta = -0.94112f / range; + + for (i = start; i <= end; i++) + { + float uses, usev; + uses = clamp (s, 0.f, 1.f); + usev = clamp (v, 0.f, 1.f); + HSVtoRGB (&r, &g, &b, h, uses, usev); + SetRemap(table, i, r, g, b); + s += sdelta; + v += vdelta; + } + } + else if (gameinfo.gametype == GAME_Heretic) + { + float vdelta = 0.418916f / range; + + // Build player sprite translation + for (i = start; i <= end; i++) + { + v = vdelta * (float)(i - start) + basev - 0.2352937f; + v = clamp (v, 0.f, 1.f); + HSVtoRGB (&r, &g, &b, h, s, v); + SetRemap(table, i, r, g, b); + } + + // Build rain/lifegem translation + if (alttable) + { + bases = MIN (bases*1.3f, 1.f); + basev = MIN (basev*1.3f, 1.f); + for (i = 145; i <= 168; i++) + { + s = MIN (bases, 0.8965f - 0.0962f*(float)(i - 161)); + v = MIN (1.f, (0.2102f + 0.0489f*(float)(i - 144)) * basev); + HSVtoRGB (&r, &g, &b, h, s, v); + SetRemap(alttable, i, r, g, b); + } + alttable->UpdateNative(); + } + } + else if (gameinfo.gametype == GAME_Hexen) + { + if (memcmp (sprites[skin->sprite].name, "PLAY", 4) == 0) + { // The fighter is different! He gets a brown hairy loincloth, but the other + // two have blue capes. + float vs[9] = { .28f, .32f, .38f, .42f, .47f, .5f, .58f, .71f, .83f }; + + // Build player sprite translation + //h = 45.f; + v = MAX (0.1f, v); + + for (i = start; i <= end; i++) + { + HSVtoRGB (&r, &g, &b, h, s, vs[(i-start)*9/(int)range]*basev); + SetRemap(table, i, r, g, b); + } + } + else + { + float ms[18] = { .95f, .96f, .89f, .97f, .97f, 1.f, 1.f, 1.f, .97f, .99f, .87f, .77f, .69f, .62f, .57f, .47f, .43f }; + float mv[18] = { .16f, .19f, .22f, .25f, .31f, .35f, .38f, .41f, .47f, .54f, .60f, .65f, .71f, .77f, .83f, .89f, .94f, 1.f }; + + // Build player sprite translation + v = MAX (0.1f, v); + + for (i = start; i <= end; i++) + { + HSVtoRGB (&r, &g, &b, h, ms[(i-start)*18/(int)range]*bases, mv[(i-start)*18/(int)range]*basev); + SetRemap(table, i, r, g, b); + } + } + + // Build lifegem translation + if (alttable) + { + for (i = 164; i <= 185; ++i) + { + const PalEntry *base = &GPalette.BaseColors[i]; + float dummy; + + RGBtoHSV (base->r/255.f, base->g/255.f, base->b/255.f, &dummy, &s, &v); + HSVtoRGB (&r, &g, &b, h, s*bases, v*basev); + SetRemap(alttable, i, r, g, b); + } + alttable->UpdateNative(); + } + } + table->UpdateNative(); +} + +void R_BuildPlayerTranslation (int player) +{ + float h, s, v; + + D_GetPlayerColor (player, &h, &s, &v); + + R_CreatePlayerTranslation (h, s, v, + &skins[players[player].userinfo.skin], + translationtables[TRANSLATION_Players][player], + translationtables[TRANSLATION_PlayersExtra][player]); +} + +void R_GetPlayerTranslation (int color, FPlayerSkin *skin, FRemapTable *table) +{ + float h, s, v; + + RGBtoHSV (RPART(color)/255.f, GPART(color)/255.f, BPART(color)/255.f, + &h, &s, &v); + + R_CreatePlayerTranslation (h, s, v, skin, table, NULL); +} diff --git a/src/r_translate.h b/src/r_translate.h new file mode 100644 index 000000000..1368aec50 --- /dev/null +++ b/src/r_translate.h @@ -0,0 +1,85 @@ +#ifndef __R_TRANSLATE_H +#define __R_TRANSLATE_H + +#include "doomtype.h" +#include "tarray.h" + +class FNativeTexture; +class FArchive; + +enum +{ + TRANSLATION_Invalid, + TRANSLATION_Players, + TRANSLATION_PlayersExtra, + TRANSLATION_Standard, + TRANSLATION_LevelScripted, + TRANSLATION_Decals, + TRANSLATION_PlayerCorpses, + TRANSLATION_Decorate, + TRANSLATION_Blood, + + NUM_TRANSLATION_TABLES +}; + +struct FRemapTable +{ + FRemapTable(int count=256); + FRemapTable(const FRemapTable &o); + ~FRemapTable(); + + FRemapTable &operator= (const FRemapTable &o); + bool operator==(const FRemapTable &o); + void MakeIdentity(); + void KillNative(); + void UpdateNative(); + FNativeTexture *GetNative(); + bool IsIdentity() const; + void Serialize(FArchive &ar); + void AddIndexRange(int start, int end, int pal1, int pal2); + void AddColorRange(int start, int end, int r1,int g1, int b1, int r2, int g2, int b2); + + BYTE *Remap; // For the software renderer + PalEntry *Palette; // The ideal palette this maps to + FNativeTexture *Native; // The Palette stored in a HW texture + int NumEntries; // # of elements in this table (usually 256) + +private: + void Free(); + void Alloc(int count); +}; + +extern TAutoGrowArray translationtables[NUM_TRANSLATION_TABLES]; + +#define TRANSLATION_SHIFT 16 +#define TRANSLATION_MASK ((1<> TRANSLATION_SHIFT; +} +inline int GetTranslationIndex(DWORD trans) +{ + return (trans&TRANSLATION_MASK); +} +// Retrieve the FRemapTable that an actor's translation value maps to. +FRemapTable *TranslationToTable(int translation); + +const int MAX_ACS_TRANSLATIONS = 65535; +const int MAX_DECORATE_TRANSLATIONS = 65535; + +// Initialize color translation tables, for player rendering etc. +void R_InitTranslationTables (void); +void R_DeinitTranslationTables(); + +// [RH] Actually create a player's translation table. +void R_BuildPlayerTranslation (int player); + + + +#endif // __R_TRANSLATE_H diff --git a/src/thingdef/olddecorations.cpp b/src/thingdef/olddecorations.cpp index 54c38928d..220d627a0 100644 --- a/src/thingdef/olddecorations.cpp +++ b/src/thingdef/olddecorations.cpp @@ -51,6 +51,7 @@ #include "i_system.h" #include "thingdef.h" #include "vectors.h" +#include "r_translate.h" // TYPES ------------------------------------------------------------------- diff --git a/src/thingdef/thingdef_main.cpp b/src/thingdef/thingdef_main.cpp index e9f6cc01a..391efe7d2 100644 --- a/src/thingdef/thingdef_main.cpp +++ b/src/thingdef/thingdef_main.cpp @@ -52,7 +52,6 @@ void ParseClass(); void ParseGlobalConst(); void ParseGlobalEnum(); void FinishThingdef(); -void InitDecorateTranslations(); void ParseOldDecoration(EDefinitionType def); // STATIC FUNCTION PROTOTYPES -------------------------------------------- @@ -164,7 +163,6 @@ void LoadDecorations () { int lastlump, lump; - InitDecorateTranslations(); lastlump = 0; while ((lump = Wads.FindLump ("DECORATE", &lastlump)) != -1) { diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 8bc4224b4..e4808d94c 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -68,6 +68,7 @@ #include "v_text.h" #include "thingdef.h" #include "a_sharedglobal.h" +#include "r_translate.h" //========================================================================== // @@ -506,17 +507,10 @@ void ParseActorFlag (Baggage &bag, int mod) // //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- -static int NumUsedTranslations; -static int NumUsedBloodTranslations; -BYTE decorate_translations[256*256*2]; -PalEntry BloodTranslations[256]; +FRemapTable CurrentTranslation; +TArray BloodTranslationColors; -void InitDecorateTranslations() -{ - // The translation tables haven't been allocated yet so we may as easily use a static buffer instead! - NumUsedBloodTranslations = NumUsedTranslations = 0; - for(int i=0;i<256*256*2;i++) decorate_translations[i]=i&255; -} +PalEntry BloodTranslations[256]; static bool Check(char *& range, char c, bool error=true) { @@ -534,7 +528,7 @@ static bool Check(char *& range, char c, bool error=true) } -static void AddToTranslation(unsigned char * translation, char * range) +static void AddToTranslation(char * range) { int start,end; @@ -545,40 +539,17 @@ static void AddToTranslation(unsigned char * translation, char * range) if (!Check(range, '[', false)) { int pal1,pal2; - fixed_t palcol, palstep; pal1=strtol(range, &range, 10); if (!Check(range, ':')) return; pal2=strtol(range, &range, 10); - if (start > end) - { - swap (start, end); - swap (pal1, pal2); - } - else if (start == end) - { - translation[start] = pal1; - return; - } - palcol = pal1 << FRACBITS; - palstep = ((pal2 << FRACBITS) - palcol) / (end - start); - for (int i = start; i <= end; palcol += palstep, ++i) - { - translation[i] = palcol >> FRACBITS; - } + CurrentTranslation.AddIndexRange(start, end, pal1, pal2); } else { // translation using RGB values - int r1; - int g1; - int b1; - int r2; - int g2; - int b2; - int r,g,b; - int rs,gs,bs; + int r1,g1,b1,r2,g2,b2; r1=strtol(range, &range, 10); if (!Check(range, ',')) return; @@ -595,98 +566,62 @@ static void AddToTranslation(unsigned char * translation, char * range) b2=strtol(range, &range, 10); if (!Check(range, ']')) return; - if (start > end) - { - swap (start, end); - r = r2; - g = g2; - b = b2; - rs = r1 - r2; - gs = g1 - g2; - bs = b1 - b2; - } - else - { - r = r1; - g = g1; - b = b1; - rs = r2 - r1; - gs = g2 - g1; - bs = b2 - b1; - } - r <<= FRACBITS; - g <<= FRACBITS; - b <<= FRACBITS; - rs <<= FRACBITS; - gs <<= FRACBITS; - bs <<= FRACBITS; - if (start == end) - { - translation[start] = ColorMatcher.Pick - (r >> FRACBITS, g >> FRACBITS, b >> FRACBITS); - return; - } - rs /= (end - start); - gs /= (end - start); - bs /= (end - start); - for (int i = start; i <= end; ++i) - { - translation[i] = ColorMatcher.Pick - (r >> FRACBITS, g >> FRACBITS, b >> FRACBITS); - r += rs; - g += gs; - b += bs; - } - + CurrentTranslation.AddColorRange(start, end, r1, g1, b1, r2, g2, b2); } } -static int StoreTranslation(const unsigned char * translation) +static int StoreTranslation() { - for (int i = 0; i < NumUsedTranslations; i++) + unsigned int i; + + for (i = 0; i < translationtables[TRANSLATION_Decorate].Size(); i++) { - if (!memcmp(translation, decorate_translations + i*256, 256)) + if (CurrentTranslation == *translationtables[TRANSLATION_Decorate][i]) { // A duplicate of this translation already exists return TRANSLATION(TRANSLATION_Decorate, i); } } - if (NumUsedTranslations>=MAX_DECORATE_TRANSLATIONS) + if (translationtables[TRANSLATION_Decorate].Size() >= MAX_DECORATE_TRANSLATIONS) { SC_ScriptError("Too many translations in DECORATE"); } - memcpy(decorate_translations + NumUsedTranslations*256, translation, 256); - NumUsedTranslations++; - return TRANSLATION(TRANSLATION_Decorate, NumUsedTranslations-1); + FRemapTable *newtrans = new FRemapTable; + *newtrans = CurrentTranslation; + i = translationtables[TRANSLATION_Decorate].Push(newtrans); + return TRANSLATION(TRANSLATION_Decorate, i); } static int CreateBloodTranslation(PalEntry color) { - int i; + unsigned int i; - for (i = 0; i < NumUsedBloodTranslations; i++) + for (i = 0; i < BloodTranslationColors.Size(); i++) { - if (color.r == BloodTranslations[i].r && - color.g == BloodTranslations[i].g && - color.b == BloodTranslations[i].b) + if (color.r == BloodTranslationColors[i].r && + color.g == BloodTranslationColors[i].g && + color.b == BloodTranslationColors[i].b) { // A duplicate of this translation already exists return i; } } - if (NumUsedBloodTranslations>=MAX_DECORATE_TRANSLATIONS) + if (BloodTranslationColors.Size() >= MAX_DECORATE_TRANSLATIONS) { SC_ScriptError("Too many blood colors in DECORATE"); } + FRemapTable *trans = new FRemapTable; for (i = 0; i < 256; i++) { int bright = MAX(MAX(GPalette.BaseColors[i].r, GPalette.BaseColors[i].g), GPalette.BaseColors[i].b); - int entry = ColorMatcher.Pick(color.r*bright/255, color.g*bright/255, color.b*bright/255); + PalEntry pe = PalEntry(color.r*bright/255, color.g*bright/255, color.b*bright/255); + int entry = ColorMatcher.Pick(pe.r, pe.g, pe.b); - *(decorate_translations + MAX_DECORATE_TRANSLATIONS*256 + NumUsedBloodTranslations*256 + i)=entry; + trans->Palette[i] = pe; + trans->Remap[i] = entry; } - BloodTranslations[NumUsedBloodTranslations]=color; - return NumUsedBloodTranslations++; + translationtables[TRANSLATION_Blood].Push(trans); + return BloodTranslationColors.Push(color); } //---------------------------------------------------------------------------- @@ -1447,15 +1382,14 @@ static void ActorTranslation (AActor *defaults, Baggage &bag) } else { - unsigned char translation[256]; - for(int i=0;i<256;i++) translation[i]=i; + CurrentTranslation.MakeIdentity(); do { SC_GetString(); - AddToTranslation(translation,sc_String); + AddToTranslation(sc_String); } while (SC_CheckString(",")); - defaults->Translation = StoreTranslation (translation); + defaults->Translation = StoreTranslation (); } } diff --git a/src/v_draw.cpp b/src/v_draw.cpp index b836174fb..ef36fd4d6 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -41,6 +41,7 @@ #include "r_defs.h" #include "r_draw.h" #include "r_things.h" +#include "r_translate.h" #include "i_system.h" #include "i_video.h" diff --git a/src/v_font.cpp b/src/v_font.cpp index 3dd4add18..8c97c232c 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -53,6 +53,7 @@ #include "sc_man.h" #include "hu_stuff.h" #include "r_draw.h" +#include "r_translate.h" // MACROS ------------------------------------------------------------------ diff --git a/src/v_video.cpp b/src/v_video.cpp index 7a7b9297b..0d4609bb7 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -59,6 +59,7 @@ #include "templates.h" #include "sbar.h" #include "hardware.h" +#include "r_translate.h" IMPLEMENT_ABSTRACT_CLASS (DCanvas) IMPLEMENT_ABSTRACT_CLASS (DFrameBuffer) diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 09f301b92..fe8ba3fdf 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -45,6 +45,7 @@ #include "sc_man.h" #include "v_text.h" #include "gi.h" +#include "r_translate.h" // States for the intermission typedef enum diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 12320c3d6..b565af462 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -61,6 +61,7 @@ #include "stats.h" #include "doomerrors.h" #include "r_draw.h" +#include "r_translate.h" #include "win32iface.h" diff --git a/zdoom.vcproj b/zdoom.vcproj index 34dec87e7..2b76f0bf0 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -8962,6 +8962,10 @@ /> + + + +