diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 8adf718f7..d4c0ebe68 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,6 @@ April 15, 2008 (Changes by Graf Zahl) +- Added translation support to multipatch textures. Not tested yet! +- Added Martin Howe's morph weapon update. - Changed true color texture creation to use a newly defined Bitmap class instead of having the copy functions in the frame buffer class. - Fixed: The WolfSS didn't have its obituary defined. diff --git a/src/g_doom/doom_sbar.cpp b/src/g_doom/doom_sbar.cpp index 5f5b8a051..899de629f 100644 --- a/src/g_doom/doom_sbar.cpp +++ b/src/g_doom/doom_sbar.cpp @@ -224,7 +224,7 @@ private: FTexture *BaseTexture; BYTE *Pixels; - FRemapTable *STBFremap; + FRemapTable *STFBRemap; } StatusBarTex; @@ -1044,7 +1044,7 @@ DDoomStatusBar::FDoomStatusBarTexture::FDoomStatusBarTexture () // now copy all the properties from the base texture CopySize(BaseTexture); Pixels = NULL; - STBFremap = NULL; + STFBRemap = NULL; } const BYTE *DDoomStatusBar::FDoomStatusBarTexture::GetColumn (unsigned int column, const Span **spans_out) @@ -1090,7 +1090,7 @@ void DDoomStatusBar::FDoomStatusBarTexture::MakeTexture () if (!deathmatch) DrawToBar("STARMS", 104, 0, NULL); DrawToBar("STTPRCNT", 90, 3, NULL); DrawToBar("STTPRCNT", 221, 3, NULL); - if (multiplayer) DrawToBar("STFBANY", 143, 1, STBFremap? STBFremap->Remap : NULL); + if (multiplayer) DrawToBar("STFBANY", 143, 1, STFBRemap? STFBRemap->Remap : NULL); } int DDoomStatusBar::FDoomStatusBarTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate) @@ -1119,7 +1119,7 @@ int DDoomStatusBar::FDoomStatusBarTexture::CopyTrueColorPixels(FBitmap *bmp, int tex = TexMan["STFBANY"]; if (tex != NULL) { - tex->CopyTrueColorTranslated(bmp, x+143, y+1, STBFremap); + tex->CopyTrueColorTranslated(bmp, x+143, y+1, 0, STFBRemap); } } return -1; @@ -1141,7 +1141,7 @@ void DDoomStatusBar::FDoomStatusBarTexture::SetPlayerRemap(FRemapTable *remap) { Unload(); KillNative(); - STBFremap = remap; + STFBRemap = remap; } DBaseStatusBar *CreateDoomStatusBar () diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 348aafc9d..d46c2e13e 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -206,6 +206,7 @@ bool P_UndoPlayerMorph (player_t *player, bool force) mo->flags3 = (mo->flags3 & ~MF3_GHOST) | (pmo->flags3 & MF3_GHOST); const PClass *exit_flash = player->MorphExitFlash; + bool correctweapon = ((player->MorphStyle & MORPH_LOSEACTUALWEAPON) == 0); player->morphTics = 0; player->MorphedPlayerClass = 0; @@ -267,13 +268,32 @@ bool P_UndoPlayerMorph (player_t *player, bool force) { player->ReadyWeapon = player->PendingWeapon = NULL; } - if (beastweap != NULL) - { // You don't get to keep your morphed weapon. - if (beastweap->SisterWeapon != NULL) + if (correctweapon) + { // Better "lose morphed weapon" semantics + const PClass *morphweapon = PClass::FindClass (mo->MorphWeapon); + if (morphweapon != NULL && morphweapon->IsDescendantOf (RUNTIME_CLASS(AWeapon))) { - beastweap->SisterWeapon->Destroy (); + AWeapon *OriginalMorphWeapon = static_cast(mo->FindInventory (morphweapon)); + if ((OriginalMorphWeapon != NULL) && (OriginalMorphWeapon->GivenAsMorphWeapon)) + { // You don't get to keep your morphed weapon. + if (OriginalMorphWeapon->SisterWeapon != NULL) + { + OriginalMorphWeapon->SisterWeapon->Destroy (); + } + OriginalMorphWeapon->Destroy (); + } + } + } + else // old behaviour (not really useful now) + { // Assumptions made here are no longer valid + if (beastweap != NULL) + { // You don't get to keep your morphed weapon. + if (beastweap->SisterWeapon != NULL) + { + beastweap->SisterWeapon->Destroy (); + } + beastweap->Destroy (); } - beastweap->Destroy (); } pmo->tracer = NULL; pmo->Destroy (); diff --git a/src/g_shared/a_morph.h b/src/g_shared/a_morph.h index 1beb78790..18cb19848 100644 --- a/src/g_shared/a_morph.h +++ b/src/g_shared/a_morph.h @@ -17,7 +17,8 @@ enum MORPH_UNDOBYCHAOSDEVICE = 0x00000008, // Player unmorphs upon activating a Chaos Device MORPH_FAILNOTELEFRAG = 0x00000010, // Player stays morphed if unmorph by Tome of Power fails MORPH_FAILNOLAUGH = 0x00000020, // Player doesn't laugh if unmorph by Chaos Device fails - MORPH_WHENINVULNERABLE = 0x00000040 // Player can morph when invulnerable but ONLY if doing it to themselves + MORPH_WHENINVULNERABLE = 0x00000040, // Player can morph when invulnerable but ONLY if doing it to themselves + MORPH_LOSEACTUALWEAPON = 0X00000080 // Player loses specified morph weapon only (not "whichever they have when unmorphing") }; struct PClass; diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 50ecc569f..03bb0a7a2 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -221,6 +221,7 @@ public: // In-inventory instance variables TObjPtr Ammo1, Ammo2; TObjPtr SisterWeapon; + bool GivenAsMorphWeapon; bool bAltFire; // Set when this weapon's alternate fire is used. diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 8f35819f7..3f3929573 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -52,7 +52,7 @@ void AWeapon::Serialize (FArchive &arc) << ProjectileType << AltProjectileType << SelectionOrder << MoveCombatDist - << Ammo1 << Ammo2 << SisterWeapon + << Ammo1 << Ammo2 << SisterWeapon << GivenAsMorphWeapon << bAltFire; } @@ -230,6 +230,7 @@ void AWeapon::AttachToOwner (AActor *other) StatusBar->ReceivedWeapon (this); } } + GivenAsMorphWeapon = false; // will be set explicitly by morphing code } //=========================================================================== diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 36e43e530..14633e798 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5342,21 +5342,18 @@ int DLevelScript::RunScript () case PCD_CHECKPLAYERCAMERA: { - AActor *actor = SingleActorFromTID(STACK(1), activator); - - if(actor != NULL && actor->player != NULL) - { - if(actor->player->camera != actor->player->mo) - { - STACK(1) = actor->player->camera->tid; - } - else - { - STACK(1) = 0; - } + int playernum = STACK(1); + + if (playernum < 0 || playernum >= MAXPLAYERS || !playeringame[playernum] || players[playernum].camera == NULL) + { + STACK(1) = -1; } - else STACK(1) = 0; - } + else + { + STACK(1) = players[playernum].camera->tid; + } + } + break; } } diff --git a/src/p_user.cpp b/src/p_user.cpp index 88ef6b5d9..280d7f79a 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1050,6 +1050,10 @@ void APlayerPawn::ActivateMorphWeapon () if (player->ReadyWeapon == NULL) { player->ReadyWeapon = static_cast(player->mo->GiveInventoryType (morphweapon)); + if (player->ReadyWeapon != NULL) + { + player->ReadyWeapon->GivenAsMorphWeapon = true; // flag is used only by new beastweap semantics in P_UndoPlayerMorph + } } if (player->ReadyWeapon != NULL) { diff --git a/src/r_data.h b/src/r_data.h index 39223abb5..6771fae4e 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -107,6 +107,8 @@ protected: SWORD OriginX, OriginY; BYTE Rotate; bool textureOwned; + FRemapTable *Translation; + PalEntry Blend; FTexture *Texture; TexPart(); diff --git a/src/r_defs.h b/src/r_defs.h index a9df07b35..4da1ff2a1 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -796,7 +796,7 @@ public: virtual const BYTE *GetPixels () = 0; virtual int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate=0); - int CopyTrueColorTranslated(FBitmap *bmp, int x, int y, FRemapTable *remap); + int CopyTrueColorTranslated(FBitmap *bmp, int x, int y, int rotate, FRemapTable *remap); virtual bool UseBasePalette(); virtual int GetSourceLump() { return -1; } diff --git a/src/r_translate.cpp b/src/r_translate.cpp index 4c6f9771e..153f0e819 100644 --- a/src/r_translate.cpp +++ b/src/r_translate.cpp @@ -46,6 +46,26 @@ TAutoGrowArray translationtables[NUM_TRANSLATION_TABLES]; +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 } +}; + /****************************************************/ /****************************************************/ @@ -428,25 +448,6 @@ void R_InitTranslationTables () // 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) { diff --git a/src/r_translate.h b/src/r_translate.h index 3b25db75b..84e481b03 100644 --- a/src/r_translate.h +++ b/src/r_translate.h @@ -97,6 +97,8 @@ void R_DeinitTranslationTables(); // [RH] Actually create a player's translation table. void R_BuildPlayerTranslation (int player); +extern const BYTE IcePalette[16][3]; + #endif // __R_TRANSLATE_H diff --git a/src/textures/bitmap.cpp b/src/textures/bitmap.cpp index eea69ed23..fb3657bf1 100644 --- a/src/textures/bitmap.cpp +++ b/src/textures/bitmap.cpp @@ -34,41 +34,217 @@ #include "bitmap.h" #include "templates.h" +#include "r_translate.h" //=========================================================================== // // multi-format pixel copy with colormap application -// requires one of the previously defined conversion classes to work +// requires the previously defined conversion classes to work // //=========================================================================== -template -void iCopyColors(BYTE *pout, const BYTE *pin, int count, int step) +template +void iCopyColors(BYTE *pout, const BYTE *pin, int count, int step, FCopyInfo *inf) { - for(int i=0;iblend : BLEND_NONE) { - pout[0]=T::B(pin); - pout[1]=T::G(pin); - pout[2]=T::R(pin); - pout[3]=T::A(pin); - pout+=4; - pin+=step; + case BLEND_NONE: + for(i=0;i(255 - TSrc::Gray(pin),0,255); + + TBlend::OpC(pout[TDest::RED], gray, a, inf); + TBlend::OpC(pout[TDest::GREEN], gray, a, inf); + TBlend::OpC(pout[TDest::BLUE], gray, a, inf); + TBlend::OpA(pout[TDest::ALPHA], a, inf); + } + pout+=4; + pin+=step; + } + break; + + case BLEND_GOLDMAP: + // Heretic's golden invulnerability map + for(i=0;i(gray+(gray>>1),0,255); + g=clamp(gray-(gray>>2),0,255); + + TBlend::OpC(pout[TDest::RED], r, a, inf); + TBlend::OpC(pout[TDest::GREEN], g, a, inf); + TBlend::OpC(pout[TDest::BLUE], 0, a, inf); + TBlend::OpA(pout[TDest::ALPHA], a, inf); + } + pout+=4; + pin+=step; + } + break; + + case BLEND_REDMAP: + // Skulltag's red Doomsphere map + for(i=0;i(gray+(gray>>1),0,255); + + TBlend::OpC(pout[TDest::RED], r, a, inf); + TBlend::OpC(pout[TDest::GREEN], 0, a, inf); + TBlend::OpC(pout[TDest::BLUE], 0, a, inf); + TBlend::OpA(pout[TDest::ALPHA], a, inf); + } + pout+=4; + pin+=step; + } + break; + + case BLEND_GREENMAP: + // Skulltags's Guardsphere map + for(i=0;i(gray+(gray>>1),0,255); + + TBlend::OpC(pout[TDest::RED], r, a, inf); + TBlend::OpC(pout[TDest::GREEN], r, a, inf); + TBlend::OpC(pout[TDest::BLUE], gray, a, inf); + TBlend::OpA(pout[TDest::ALPHA], a, inf); + } + pout+=4; + pin+=step; + } + break; + + case BLEND_ICEMAP: + // Create the ice translation table, based on Hexen's. + // Since this is done in True Color the purplish tint is fully preserved - even in Doom! + for(i=0;i>4; + + TBlend::OpC(pout[TDest::RED], IcePalette[gray][0], a, inf); + TBlend::OpC(pout[TDest::GREEN], IcePalette[gray][1], a, inf); + TBlend::OpC(pout[TDest::BLUE], IcePalette[gray][2], a, inf); + TBlend::OpA(pout[TDest::ALPHA], a, inf); + } + pout+=4; + pin+=step; + } + break; + + default: + if (inf->blend >= BLEND_DESATURATE1 && inf->blend<=BLEND_DESATURATE31) + { + // Desaturated light settings. + fac=inf->blend-BLEND_DESATURATE1+1; + for(i=0;iblendcolor[0])>>FRACBITS; + g = (TSrc::G(pin)*inf->blendcolor[1])>>FRACBITS; + b = (TSrc::B(pin)*inf->blendcolor[2])>>FRACBITS; + + TBlend::OpC(pout[TDest::RED], r, a, inf); + TBlend::OpC(pout[TDest::GREEN], g, a, inf); + TBlend::OpC(pout[TDest::BLUE], b, a, inf); + TBlend::OpA(pout[TDest::ALPHA], a, inf); + } + pout+=4; + pin+=step; + } + break; + + case BLEND_OVERLAY: + for(i=0;iblendcolor[3] + inf->blendcolor[0]) >> FRACBITS; + g = (TSrc::G(pin)*inf->blendcolor[3] + inf->blendcolor[1]) >> FRACBITS; + b = (TSrc::B(pin)*inf->blendcolor[3] + inf->blendcolor[2]) >> FRACBITS; + + TBlend::OpC(pout[TDest::RED], r, a, inf); + TBlend::OpC(pout[TDest::GREEN], g, a, inf); + TBlend::OpC(pout[TDest::BLUE], b, a, inf); + TBlend::OpA(pout[TDest::ALPHA], a, inf); + } + pout+=4; + pin+=step; + } + break; + } } -typedef void (*CopyFunc)(BYTE *pout, const BYTE *pin, int count, int step); +typedef void (*CopyFunc)(BYTE *pout, const BYTE *pin, int count, int step, FCopyInfo *inf); -static CopyFunc copyfuncs[]={ - iCopyColors, - iCopyColors, - iCopyColors, - iCopyColors, - iCopyColors, - iCopyColors, - iCopyColors, - iCopyColors, - iCopyColors -}; +static CopyFunc copyfuncs[9]= + { + iCopyColors, + iCopyColors, + iCopyColors, + iCopyColors, + iCopyColors, + iCopyColors, + iCopyColors, + iCopyColors, + iCopyColors + }; //=========================================================================== // @@ -199,7 +375,7 @@ void FBitmap::CopyPixelDataRGB(int originx, int originy, const BYTE *patch, int BYTE *buffer = data + 4 * originx + Pitch * originy; for (int y=0;y>8; } + static __forceinline unsigned char R(const unsigned char * p) { return p[0]; } + static __forceinline unsigned char G(const unsigned char * p) { return p[1]; } + static __forceinline unsigned char B(const unsigned char * p) { return p[2]; } + static __forceinline unsigned char A(const unsigned char * p) { return 255; } + static __forceinline int Gray(const unsigned char * p) { return (p[0]*77 + p[1]*143 + p[2]*36)>>8; } }; struct cRGBA { - static unsigned char R(const unsigned char * p) { return p[0]; } - static unsigned char G(const unsigned char * p) { return p[1]; } - static unsigned char B(const unsigned char * p) { return p[2]; } - static unsigned char A(const unsigned char * p) { return p[3]; } - static int Gray(const unsigned char * p) { return (p[0]*77 + p[1]*143 + p[2]*36)>>8; } + enum + { + RED = 0, + GREEN = 1, + BLUE = 1, + ALPHA = 3 + }; + static __forceinline unsigned char R(const unsigned char * p) { return p[0]; } + static __forceinline unsigned char G(const unsigned char * p) { return p[1]; } + static __forceinline unsigned char B(const unsigned char * p) { return p[2]; } + static __forceinline unsigned char A(const unsigned char * p) { return p[3]; } + static __forceinline int Gray(const unsigned char * p) { return (p[0]*77 + p[1]*143 + p[2]*36)>>8; } }; struct cIA { - static unsigned char R(const unsigned char * p) { return p[0]; } - static unsigned char G(const unsigned char * p) { return p[0]; } - static unsigned char B(const unsigned char * p) { return p[0]; } - static unsigned char A(const unsigned char * p) { return p[1]; } - static int Gray(const unsigned char * p) { return p[0]; } + static __forceinline unsigned char R(const unsigned char * p) { return p[0]; } + static __forceinline unsigned char G(const unsigned char * p) { return p[0]; } + static __forceinline unsigned char B(const unsigned char * p) { return p[0]; } + static __forceinline unsigned char A(const unsigned char * p) { return p[1]; } + static __forceinline int Gray(const unsigned char * p) { return p[0]; } }; struct cCMYK { - static unsigned char R(const unsigned char * p) { return p[3] - (((256-p[0])*p[3]) >> 8); } - static unsigned char G(const unsigned char * p) { return p[3] - (((256-p[1])*p[3]) >> 8); } - static unsigned char B(const unsigned char * p) { return p[3] - (((256-p[2])*p[3]) >> 8); } - static unsigned char A(const unsigned char * p) { return 255; } - static int Gray(const unsigned char * p) { return (R(p)*77 + G(p)*143 + B(p)*36)>>8; } + static __forceinline unsigned char R(const unsigned char * p) { return p[3] - (((256-p[0])*p[3]) >> 8); } + static __forceinline unsigned char G(const unsigned char * p) { return p[3] - (((256-p[1])*p[3]) >> 8); } + static __forceinline unsigned char B(const unsigned char * p) { return p[3] - (((256-p[2])*p[3]) >> 8); } + static __forceinline unsigned char A(const unsigned char * p) { return 255; } + static __forceinline int Gray(const unsigned char * p) { return (R(p)*77 + G(p)*143 + B(p)*36)>>8; } }; struct cBGR { - static unsigned char R(const unsigned char * p) { return p[2]; } - static unsigned char G(const unsigned char * p) { return p[1]; } - static unsigned char B(const unsigned char * p) { return p[0]; } - static unsigned char A(const unsigned char * p) { return 255; } - static int Gray(const unsigned char * p) { return (p[2]*77 + p[1]*143 + p[0]*36)>>8; } + static __forceinline unsigned char R(const unsigned char * p) { return p[2]; } + static __forceinline unsigned char G(const unsigned char * p) { return p[1]; } + static __forceinline unsigned char B(const unsigned char * p) { return p[0]; } + static __forceinline unsigned char A(const unsigned char * p) { return 255; } + static __forceinline int Gray(const unsigned char * p) { return (p[2]*77 + p[1]*143 + p[0]*36)>>8; } }; struct cBGRA { - static unsigned char R(const unsigned char * p) { return p[2]; } - static unsigned char G(const unsigned char * p) { return p[1]; } - static unsigned char B(const unsigned char * p) { return p[0]; } - static unsigned char A(const unsigned char * p) { return p[3]; } - static int Gray(const unsigned char * p) { return (p[2]*77 + p[1]*143 + p[0]*36)>>8; } + enum + { + RED = 2, + GREEN = 1, + BLUE = 0, + ALPHA = 3 + }; + static __forceinline unsigned char R(const unsigned char * p) { return p[2]; } + static __forceinline unsigned char G(const unsigned char * p) { return p[1]; } + static __forceinline unsigned char B(const unsigned char * p) { return p[0]; } + static __forceinline unsigned char A(const unsigned char * p) { return p[3]; } + static __forceinline int Gray(const unsigned char * p) { return (p[2]*77 + p[1]*143 + p[0]*36)>>8; } +}; + +struct cARGB +{ + enum + { + RED = 1, + GREEN = 2, + BLUE = 3, + ALPHA = 0 + }; + static __forceinline unsigned char R(const unsigned char * p) { return p[1]; } + static __forceinline unsigned char G(const unsigned char * p) { return p[2]; } + static __forceinline unsigned char B(const unsigned char * p) { return p[3]; } + static __forceinline unsigned char A(const unsigned char * p) { return p[0]; } + static __forceinline int Gray(const unsigned char * p) { return (p[1]*77 + p[2]*143 + p[3]*36)>>8; } }; struct cI16 { - static unsigned char R(const unsigned char * p) { return p[1]; } - static unsigned char G(const unsigned char * p) { return p[1]; } - static unsigned char B(const unsigned char * p) { return p[1]; } - static unsigned char A(const unsigned char * p) { return 255; } - static int Gray(const unsigned char * p) { return p[1]; } + static __forceinline unsigned char R(const unsigned char * p) { return p[1]; } + static __forceinline unsigned char G(const unsigned char * p) { return p[1]; } + static __forceinline unsigned char B(const unsigned char * p) { return p[1]; } + static __forceinline unsigned char A(const unsigned char * p) { return 255; } + static __forceinline int Gray(const unsigned char * p) { return p[1]; } }; struct cRGB555 { - static unsigned char R(const unsigned char * p) { return (((*(WORD*)p)&0x1f)<<3); } - static unsigned char G(const unsigned char * p) { return (((*(WORD*)p)&0x3e0)>>2); } - static unsigned char B(const unsigned char * p) { return (((*(WORD*)p)&0x7c00)>>7); } - static unsigned char A(const unsigned char * p) { return p[1]; } - static int Gray(const unsigned char * p) { return (R(p)*77 + G(p)*143 + B(p)*36)>>8; } + static __forceinline unsigned char R(const unsigned char * p) { return (((*(WORD*)p)&0x1f)<<3); } + static __forceinline unsigned char G(const unsigned char * p) { return (((*(WORD*)p)&0x3e0)>>2); } + static __forceinline unsigned char B(const unsigned char * p) { return (((*(WORD*)p)&0x7c00)>>7); } + static __forceinline unsigned char A(const unsigned char * p) { return 255; } + static __forceinline int Gray(const unsigned char * p) { return (R(p)*77 + G(p)*143 + B(p)*36)>>8; } }; struct cPalEntry { - static unsigned char R(const unsigned char * p) { return ((PalEntry*)p)->r; } - static unsigned char G(const unsigned char * p) { return ((PalEntry*)p)->g; } - static unsigned char B(const unsigned char * p) { return ((PalEntry*)p)->b; } - static unsigned char A(const unsigned char * p) { return ((PalEntry*)p)->a; } - static int Gray(const unsigned char * p) { return (R(p)*77 + G(p)*143 + B(p)*36)>>8; } + static __forceinline unsigned char R(const unsigned char * p) { return ((PalEntry*)p)->r; } + static __forceinline unsigned char G(const unsigned char * p) { return ((PalEntry*)p)->g; } + static __forceinline unsigned char B(const unsigned char * p) { return ((PalEntry*)p)->b; } + static __forceinline unsigned char A(const unsigned char * p) { return ((PalEntry*)p)->a; } + static __forceinline int Gray(const unsigned char * p) { return (R(p)*77 + G(p)*143 + B(p)*36)>>8; } }; enum ColorType @@ -200,5 +230,37 @@ enum ColorType CF_PalEntry }; +enum EBlend +{ + BLEND_NONE = 0, + BLEND_INVERSEMAP = 1, + BLEND_GOLDMAP = 2, + BLEND_REDMAP = 3, + BLEND_GREENMAP = 4, + BLEND_ICEMAP = 5, + BLEND_DESATURATE1 = 6, + BLEND_DESATURATE31 = 36, + BLEND_MODULATE = -1, + BLEND_OVERLAY = -2, +}; + +struct FCopyInfo +{ + //ECopyOp op; + EBlend blend; + fixed_t blendcolor[4]; +// fixed_t alpha; +// fixed_t invalpha; + +}; + +struct bCopy +{ + static __forceinline void OpC(BYTE &d, BYTE s, BYTE a, FCopyInfo *i) { d = s; } + static __forceinline void OpA(BYTE &d, BYTE s, FCopyInfo *i) { d = s; } +}; + + + #endif \ No newline at end of file diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index 9d2225ba6..c9ef4edf8 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -44,6 +44,8 @@ #include "sc_man.h" #include "templates.h" #include "vectors.h" +#include "r_translate.h" +#include "bitmap.h" // On the Alpha, accessing the shorts directly if they aren't aligned on a // 4-byte boundary causes unaligned access warnings. Why it does this at @@ -274,6 +276,70 @@ const BYTE *FMultiPatchTexture::GetColumn (unsigned int column, const Span **spa return Pixels + column*Height; } + +//========================================================================== +// +// FMultiPatchTexture :: GetColumn +// +//========================================================================== + +BYTE * GetBlendMap(PalEntry blend, BYTE *blendwork) +{ + + switch (blend) + { + case BLEND_INVERSEMAP: + return InverseColormap; + + case BLEND_GOLDMAP: + return GoldColormap; + + case BLEND_REDMAP: + return RedColormap; + + case BLEND_GREENMAP: + return GreenColormap; + + case BLEND_ICEMAP: + return TranslationToTable(TRANSLATION(TRANSLATION_Standard, 7))->Remap; + + default: + if (blend >= BLEND_DESATURATE1 && blend <= BLEND_DESATURATE31) + { + return DesaturateColormap[blend - BLEND_DESATURATE1]; + } + else + { + blendwork[0]=0; + if (blend.a == 255) + { + for(int i=1;i<256;i++) + { + int rr = (blend.r * GPalette.BaseColors[i].r) / 255; + int gg = (blend.g * GPalette.BaseColors[i].g) / 255; + int bb = (blend.b * GPalette.BaseColors[i].b) / 255; + + blendwork[i] = ColorMatcher.Pick(rr, gg, bb); + } + return blendwork; + } + else if (blend.a != 0) + { + for(int i=1;i<256;i++) + { + int rr = (blend.r * blend.a + GPalette.BaseColors[i].r * (255-blend.a)) / 255; + int gg = (blend.g * blend.a + GPalette.BaseColors[i].g * (255-blend.a)) / 255; + int bb = (blend.b * blend.a + GPalette.BaseColors[i].b * (255-blend.a)) / 255; + + blendwork[i] = ColorMatcher.Pick(rr, gg, bb); + } + return blendwork; + } + } + } + return NULL; +} + //========================================================================== // // FMultiPatchTexture :: MakeTexture @@ -285,14 +351,20 @@ void FMultiPatchTexture::MakeTexture () // Add a little extra space at the end if the texture's height is not // a power of 2, in case somebody accidentally makes it repeat vertically. int numpix = Width * Height + (1 << HeightBits) - Height; + BYTE blendwork[256]; Pixels = new BYTE[numpix]; memset (Pixels, 0, numpix); for (int i = 0; i < NumParts; ++i) { + BYTE *trans = Parts[i].Translation? Parts[i].Translation->Remap : NULL; + if (Parts[i].Blend != BLEND_NONE) + { + trans = GetBlendMap(Parts[i].Blend, blendwork); + } Parts[i].Texture->CopyToBlock (Pixels, Width, Height, - Parts[i].OriginX, Parts[i].OriginY, Parts[i].Rotate); + Parts[i].OriginX, Parts[i].OriginY, Parts[i].Rotate, trans); } } @@ -310,7 +382,29 @@ int FMultiPatchTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rota for(int i=0;iCopyTrueColorPixels(bmp, x+Parts[i].OriginX, y+Parts[i].OriginY, Parts[i].Rotate); + int ret; + + if (!Parts[i].Texture->bComplex) + { + if (Parts[i].Translation != NULL) + { + // Using a translation forces downconversion to the base palette + ret = Parts[i].Texture->CopyTrueColorTranslated(bmp, x+Parts[i].OriginX, y+Parts[i].OriginY, Parts[i].Rotate, Parts[i].Translation); + } + else + { + if (Parts[i].Blend != BLEND_NONE) + { + } + ret = Parts[i].Texture->CopyTrueColorPixels(bmp, x+Parts[i].OriginX, y+Parts[i].OriginY, Parts[i].Rotate); + } + } + else + { + // If the patch is a texture with some kind of processing involved + // the copying must be done in 2 steps: First create a complete image of the patch + // including all processing and then copy from that intermediate image to the destination + } if (ret > retv) retv = ret; } @@ -327,6 +421,7 @@ int FMultiPatchTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rota FTextureFormat FMultiPatchTexture::GetFormat() { + if (bComplex) return TEX_RGB; if (NumParts == 1) return Parts[0].Texture->GetFormat(); return UseBasePalette() ? TEX_Pal : TEX_RGB; } @@ -343,6 +438,7 @@ FTextureFormat FMultiPatchTexture::GetFormat() bool FMultiPatchTexture::UseBasePalette() { + if (bComplex) return false; for(int i=0;iUseBasePalette()) return false; @@ -489,6 +585,8 @@ FMultiPatchTexture::TexPart::TexPart() Rotate = 0; textureOwned = false; Texture = NULL; + Translation = NULL; + Blend = 0; } //========================================================================== @@ -501,6 +599,7 @@ FMultiPatchTexture::TexPart::~TexPart() { if (textureOwned && Texture != NULL) delete Texture; Texture = NULL; + if (Translation != NULL) delete Translation; } //========================================================================== @@ -673,6 +772,17 @@ void FTextureManager::AddTexturesLumps (int lump1, int lump2, int patcheslump) } +static bool Check(char *& range, char c) +{ + while (isspace(*range)) range++; + if (*range==c) + { + range++; + return true; + } + return false; +} + void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part) { FString patchname; @@ -727,6 +837,110 @@ void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part) } part.Rotate = (sc.Number / 90) & 3; } + else if (sc.Compare("Translation")) + { + bComplex = true; + if (part.Translation != NULL) delete part.Translation; + part.Translation = NULL; + part.Blend = 0; + static const char *maps[] = { "inverse", "gold", "red", "green", "ice", "desaturate", NULL }; + int match = sc.MatchString(maps); + if (match >= 0) + { + part.Blend.r = 1 + match; + if (part.Blend.r == BLEND_DESATURATE1) + { + sc.MustGetStringName(","); + sc.MustGetNumber(); + part.Blend.r += clamp(sc.Number-1, 0, 30); + } + } + else + { + part.Translation = new FRemapTable; + part.Translation->MakeIdentity(); + do + { + sc.MustGetString(); + + char *range = sc.String; + int start,end; + + start=strtol(range, &range, 10); + if (!Check(range, ':')) return; + end=strtol(range, &range, 10); + if (!Check(range, '=')) return; + if (!Check(range, '[')) + { + int pal1,pal2; + + pal1=strtol(range, &range, 10); + if (!Check(range, ':')) return; + pal2=strtol(range, &range, 10); + + part.Translation->AddIndexRange(start, end, pal1, pal2); + } + else + { + // translation using RGB values + int r1,g1,b1,r2,g2,b2; + + r1=strtol(range, &range, 10); + if (!Check(range, ',')) return; + g1=strtol(range, &range, 10); + if (!Check(range, ',')) return; + b1=strtol(range, &range, 10); + if (!Check(range, ']')) return; + if (!Check(range, ':')) return; + if (!Check(range, '[')) return; + r2=strtol(range, &range, 10); + if (!Check(range, ',')) return; + g2=strtol(range, &range, 10); + if (!Check(range, ',')) return; + b2=strtol(range, &range, 10); + if (!Check(range, ']')) return; + + part.Translation->AddColorRange(start, end, r1, g1, b1, r2, g2, b2); + } + } + while (sc.CheckString(",")); + } + + } + else if (sc.Compare("Blend")) + { + bComplex = true; + if (part.Translation != NULL) delete part.Translation; + part.Translation = NULL; + part.Blend = 0; + + if (!sc.CheckNumber()) + { + part.Blend = V_GetColor(NULL, sc.String); + } + else + { + int r,g,b; + + sc.MustGetNumber(); + sc.MustGetStringName(","); + r = sc.Number; + sc.MustGetNumber(); + sc.MustGetStringName(","); + g = sc.Number; + sc.MustGetNumber(); + sc.MustGetStringName(","); + b = sc.Number; + part.Blend = MAKERGB(r, g, b); + } + if (sc.CheckString(",")) + { + sc.MustGetFloat(); + part.Blend.a = clamp(int(sc.Float*255), 1, 254); + } + else part.Blend.a = 255; + bComplex = true; + } } } if (Mirror & 2) diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp index c2248d2f3..3f02f568f 100644 --- a/src/textures/texture.cpp +++ b/src/textures/texture.cpp @@ -490,11 +490,11 @@ int FTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate) return 0; } -int FTexture::CopyTrueColorTranslated(FBitmap *bmp, int x, int y, FRemapTable *remap) +int FTexture::CopyTrueColorTranslated(FBitmap *bmp, int x, int y, int rotate, FRemapTable *remap) { PalEntry *palette = remap->Palette; palette[0].a=255; // temporarily modify the first color's alpha - bmp->CopyPixelData(x, y, GetPixels(), Width, Height, Height, 1, 0, palette); + bmp->CopyPixelData(x, y, GetPixels(), Width, Height, Height, 1, rotate, palette); palette[0].a=0; return 0; diff --git a/src/v_palette.cpp b/src/v_palette.cpp index 00e3ddc59..e6f13f067 100644 --- a/src/v_palette.cpp +++ b/src/v_palette.cpp @@ -64,6 +64,7 @@ BYTE GoldColormap[256]; // [BC] New Skulltag colormaps. BYTE RedColormap[256]; BYTE GreenColormap[256]; +BYTE DesaturateColormap[31][256]; static void FreeSpecialLights();; @@ -433,6 +434,24 @@ void InitPalette () MIN( 255, ( intensity + ( intensity / 2 )) >> 8 ), intensity>>8 ); } + + // desaturated colormaps + for(int m = 0; m < 31; m++) + { + shade = DesaturateColormap[m]; + for (c = 0; c < 256; c++) + { + intensity = GPalette.BaseColors[c].r * 77 + + GPalette.BaseColors[c].g * 143 + + GPalette.BaseColors[c].b * 37; + + int r = (GPalette.BaseColors[c].r * (31-m) + intensity *m) / 31; + int g = (GPalette.BaseColors[c].g * (31-m) + intensity *m) / 31; + int b = (GPalette.BaseColors[c].b * (31-m) + intensity *m) / 31; + shade[c] = ColorMatcher.Pick (r, g, b); + } + } + } extern "C" diff --git a/src/v_palette.h b/src/v_palette.h index 2fbe992c6..c8236a385 100644 --- a/src/v_palette.h +++ b/src/v_palette.h @@ -85,6 +85,7 @@ extern BYTE GoldColormap[256]; // [BC] New Skulltag colormaps. extern BYTE RedColormap[256]; extern BYTE GreenColormap[256]; +extern BYTE DesaturateColormap[31][256]; extern FPalette GPalette; extern "C" { extern FDynamicColormap NormalLight; diff --git a/tools/updaterevision/updaterevision.vcproj b/tools/updaterevision/updaterevision.vcproj index 202c9d042..f39914dca 100644 --- a/tools/updaterevision/updaterevision.vcproj +++ b/tools/updaterevision/updaterevision.vcproj @@ -1,7 +1,7 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + +