diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3a3efad30..9af325791 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1190,6 +1190,7 @@ set (PCH_SOURCES textures/rawpagetexture.cpp textures/emptytexture.cpp textures/backdroptexture.cpp + textures/shadertexture.cpp textures/texture.cpp textures/texturemanager.cpp textures/tgatexture.cpp diff --git a/src/am_map.cpp b/src/am_map.cpp index 1922b967c..f4382f0fd 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -734,6 +734,8 @@ static int grid = 0; bool automapactive = false; +DEFINE_GLOBAL(automapactive); + // location of window on screen static int f_x; static int f_y; diff --git a/src/d_main.cpp b/src/d_main.cpp index 7216881d4..22ba39cfe 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2568,14 +2568,8 @@ void D_DoomMain (void) P_SetupWeapons_ntohton(); - //SBarInfo support. - // This needs special checking because there are two distinct methods of defining status bars. - // SBARINFO should only be picked if it is the most recently defined one, so that both - // methods can override each other if loaded in sequence. - if (gameinfo.statusbarfile > gameinfo.statusbarclassfile) - { - SBarInfo::Load(); - } + //SBarInfo support. Note that the first SBARINFO lump contains the mugshot definition so it even needs to be read when a regular status bar is being used. + SBarInfo::Load(); HUD_InitHud(); if (!batchrun) diff --git a/src/d_player.h b/src/d_player.h index 4a718778b..dc5f6cd54 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -532,6 +532,8 @@ public: // [Nash] set player FOV void SetFOV(float fov); + bool HasWeaponsInSlot(int slot) const; + bool Resurrect(); }; // Bookkeeping on players - state. diff --git a/src/g_game.cpp b/src/g_game.cpp index 447fb82db..e70935cf4 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -234,8 +234,6 @@ FString shotfile; AActor* bodyque[BODYQUESIZE]; int bodyqueslot; -void R_ExecuteSetViewSize (FViewWindow &viewwindow); - FString savename; FString BackupSaveName; diff --git a/src/g_inventory/a_keys.cpp b/src/g_inventory/a_keys.cpp index 75d98c2c7..701b98b00 100644 --- a/src/g_inventory/a_keys.cpp +++ b/src/g_inventory/a_keys.cpp @@ -464,7 +464,7 @@ void P_DeinitKeyMessages() // //=========================================================================== -bool P_CheckKeys (AActor *owner, int keynum, bool remote) +bool P_CheckKeys (AActor *owner, int keynum, bool remote, bool quiet) { const char *failtext = NULL; FSoundID *failsound; @@ -479,6 +479,7 @@ bool P_CheckKeys (AActor *owner, int keynum, bool remote) if (!locks[keynum]) { + if (quiet) return false; if (keynum == 103 && (gameinfo.flags & GI_SHAREWARE)) failtext = "$TXT_RETAIL_ONLY"; else @@ -490,6 +491,7 @@ bool P_CheckKeys (AActor *owner, int keynum, bool remote) else { if (locks[keynum]->check(owner)) return true; + if (quiet) return false; failtext = remote? locks[keynum]->RemoteMsg : locks[keynum]->Message; failsound = &locks[keynum]->locksound[0]; numfailsounds = locks[keynum]->locksound.Size(); @@ -519,6 +521,15 @@ bool P_CheckKeys (AActor *owner, int keynum, bool remote) return false; } +DEFINE_ACTION_FUNCTION(AActor, CheckKeys) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(locknum); + PARAM_BOOL(remote); + PARAM_BOOL_DEF(quiet); + ACTION_RETURN_BOOL(P_CheckKeys(self, locknum, remote, quiet)); +} + //========================================================================== // // These functions can be used to get color information for diff --git a/src/g_inventory/a_keys.h b/src/g_inventory/a_keys.h index 328ff04a6..05eff1189 100644 --- a/src/g_inventory/a_keys.h +++ b/src/g_inventory/a_keys.h @@ -4,7 +4,7 @@ class AActor; class AInventory; -bool P_CheckKeys (AActor *owner, int keynum, bool remote); +bool P_CheckKeys (AActor *owner, int keynum, bool remote, bool quiet = false); void P_InitKeyMessages (); void P_DeinitKeyMessages (); int P_GetMapColorForLock (int lock); diff --git a/src/g_level.cpp b/src/g_level.cpp index 1a3d1d073..ecde760f3 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1028,7 +1028,10 @@ void G_DoLoadLevel (int position, bool autosave) { players[ii].camera = players[ii].mo; } - E_PlayerEntered(ii, finishstate == FINISH_SameHub); + if (!savegamerestore) + { + E_PlayerEntered(ii, finishstate == FINISH_SameHub); + } // ENTER scripts are being handled when the player gets spawned, this cannot be changed due to its effect on voodoo dolls. if (level.FromSnapshot && !savegamerestore) FBehavior::StaticStartTypedScripts(SCRIPT_Return, players[ii].mo, true); } diff --git a/src/g_shared/a_dynlight.h b/src/g_shared/a_dynlight.h index 1a1862957..893bbfbee 100644 --- a/src/g_shared/a_dynlight.h +++ b/src/g_shared/a_dynlight.h @@ -27,6 +27,7 @@ enum #define MF4_DONTLIGHTSELF MF4_SEESDAGGERS #define MF4_ATTENUATE MF4_INCOMBAT #define MF4_NOSHADOWMAP MF4_STANDSTILL +#define MF4_DONTLIGHTACTORS MF4_EXTREMEDEATH enum ELightType { diff --git a/src/g_shared/a_dynlightdata.cpp b/src/g_shared/a_dynlightdata.cpp index 160ddea5f..7db1f8f7c 100644 --- a/src/g_shared/a_dynlightdata.cpp +++ b/src/g_shared/a_dynlightdata.cpp @@ -127,6 +127,7 @@ public: void SetDontLightSelf(bool add) { m_dontlightself = add; } void SetAttenuate(bool on) { m_attenuate = on; } void SetHalo(bool halo) { m_halo = halo; } + void SetDontLightActors(bool on) { m_dontlightactors = on; } void OrderIntensities() { @@ -144,7 +145,7 @@ protected: DVector3 m_Pos; ELightType m_type; int8_t m_attenuate; - bool m_subtractive, m_additive, m_halo, m_dontlightself; + bool m_subtractive, m_additive, m_halo, m_dontlightself, m_dontlightactors; bool m_swapped = false; }; @@ -187,6 +188,7 @@ void FLightDefaults::ApplyProperties(ADynamicLight * light) const if (m_subtractive) light->flags4 |= MF4_SUBTRACTIVE; if (m_additive) light->flags4 |= MF4_ADDITIVE; if (m_dontlightself) light->flags4 |= MF4_DONTLIGHTSELF; + if (m_dontlightactors) light->flags4 |= MF4_DONTLIGHTACTORS; light->m_tickCount = 0; if (m_type == PulseLight) { @@ -236,6 +238,7 @@ static const char *LightTags[]= "halo", "dontlightself", "attenuate", + "dontlightactors", NULL }; @@ -256,7 +259,8 @@ enum { LIGHTTAG_ADDITIVE, LIGHTTAG_HALO, LIGHTTAG_DONTLIGHTSELF, - LIGHTTAG_ATTENUATE + LIGHTTAG_ATTENUATE, + LIGHTTAG_DONTLIGHTACTORS, }; @@ -394,6 +398,9 @@ static void ParsePointLight(FScanner &sc) case LIGHTTAG_ATTENUATE: defaults->SetAttenuate(ParseInt(sc) != 0); break; + case LIGHTTAG_DONTLIGHTACTORS: + defaults->SetDontLightActors(ParseInt(sc) != 0); + break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); } @@ -476,6 +483,9 @@ static void ParsePulseLight(FScanner &sc) case LIGHTTAG_ATTENUATE: defaults->SetAttenuate(ParseInt(sc) != 0); break; + case LIGHTTAG_DONTLIGHTACTORS: + defaults->SetDontLightActors(ParseInt(sc) != 0); + break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); } @@ -560,6 +570,9 @@ void ParseFlickerLight(FScanner &sc) case LIGHTTAG_ATTENUATE: defaults->SetAttenuate(ParseInt(sc) != 0); break; + case LIGHTTAG_DONTLIGHTACTORS: + defaults->SetDontLightActors(ParseInt(sc) != 0); + break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); } @@ -643,6 +656,9 @@ void ParseFlickerLight2(FScanner &sc) case LIGHTTAG_ATTENUATE: defaults->SetAttenuate(ParseInt(sc) != 0); break; + case LIGHTTAG_DONTLIGHTACTORS: + defaults->SetDontLightActors(ParseInt(sc) != 0); + break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); } @@ -723,6 +739,9 @@ static void ParseSectorLight(FScanner &sc) case LIGHTTAG_ATTENUATE: defaults->SetAttenuate(ParseInt(sc) != 0); break; + case LIGHTTAG_DONTLIGHTACTORS: + defaults->SetDontLightActors(ParseInt(sc) != 0); + break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); } diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index fa5b8a030..ce8a4965e 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -115,7 +115,7 @@ static FFont * IndexFont; // The font for the inventory indices static FTexture * healthpic; // Health icon static FTexture * berserkpic; // Berserk icon (Doom only) static FTexture * fragpic; // Frags icon -static FTexture * invgems[4]; // Inventory arrows +static FTexture * invgems[2]; // Inventory arrows static int hudwidth, hudheight; // current width/height for HUD display static int statspace; @@ -816,7 +816,7 @@ static void DrawInventory(player_t * CPlayer, int x,int y) { if(rover->PrevInv()) { - screen->DrawTexture(invgems[!!(level.time&4)], x-10, y, + screen->DrawTexture(invgems[0], x-10, y, DTA_KeepRatio, true, DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, 0.4, TAG_DONE); } @@ -852,7 +852,7 @@ static void DrawInventory(player_t * CPlayer, int x,int y) } if(rover) { - screen->DrawTexture(invgems[2 + !!(level.time&4)], x-10, y, + screen->DrawTexture(invgems[1], x-10, y, DTA_KeepRatio, true, DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, 0.4, TAG_DONE); } @@ -1279,9 +1279,7 @@ void HUD_InitHud() if (IndexFont == NULL) IndexFont = ConFont; // Emergency fallback invgems[0] = TexMan.FindTexture("INVGEML1"); - invgems[1] = TexMan.FindTexture("INVGEML2"); - invgems[2] = TexMan.FindTexture("INVGEMR1"); - invgems[3] = TexMan.FindTexture("INVGEMR2"); + invgems[1] = TexMan.FindTexture("INVGEMR1"); fragpic = TexMan.FindTexture("HU_FRAGS"); // Sadly, I don't have anything usable for this. :( diff --git a/src/g_statusbar/sbar.h b/src/g_statusbar/sbar.h index 1f8fb62e4..d7c771767 100644 --- a/src/g_statusbar/sbar.h +++ b/src/g_statusbar/sbar.h @@ -356,13 +356,6 @@ public: CENTER_BOTTOM = BOTTOM | HCENTER }; - enum ETextAlign - { - ALIGN_LEFT = 0, - ALIGN_CENTER = 1, - ALIGN_RIGHT = 2 - }; - DBaseStatusBar (); void SetSize(int reltop = 32, int hres = 320, int vres = 200); void OnDestroy() override; @@ -402,10 +395,9 @@ public: void DrawLog(); uint32_t GetTranslation() const; - void DrawGraphic(FTextureID texture, bool animate, double x, double y, double Alpha = 1., bool translatable = false, bool dim = false, - int imgAlign = TOP | LEFT, int screenalign = TOP | LEFT, bool alphamap = false, double width = -1, double height = -1); - - void DrawString(FFont *font, const FString &cstring, double x, double y, double Alpha, int translation, int align, int screenalign, int spacing = 0, bool monospaced = false, int shadowX = 0, int shadowY = 0); + void DrawGraphic(FTextureID texture, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY); + void DrawString(FFont *font, const FString &cstring, double x, double y, int flags, double Alpha, int translation, int spacing, bool monospaced, int shadowX, int shadowY); + void Fill(PalEntry color, double x, double y, double w, double h, int flags = 0); void BeginStatusBar(int resW, int resH, int relTop, bool completeborder = false, bool forceScaled = false); void BeginHUD(int resW, int resH, double Alpha, bool forceScaled = false); @@ -435,8 +427,8 @@ public: double CrosshairSize; double Displacement; bool ShowLog; - - FImageCollection Images; + int artiflashTick = 0; + double itemflashFade = 0.75; player_t *CPlayer; @@ -471,6 +463,7 @@ extern FTexture *CrosshairImage; FTextureID GetInventoryIcon(AInventory *item, uint32_t flags, bool *applyscale); + enum DI_Flags { DI_SKIPICON = 0x1, @@ -478,11 +471,74 @@ enum DI_Flags DI_SKIPSPAWN = 0x4, DI_SKIPREADY = 0x8, DI_ALTICONFIRST = 0x10, - - DI_DRAWINBOX = 0x20, // Set when either width or height is not zero - + DI_TRANSLATABLE = 0x20, DI_FORCESCALE = 0x40, - DI_ALTERNATEONFAIL = 0x80 + DI_DIM = 0x80, + DI_DRAWCURSORFIRST = 0x100, // only for DrawInventoryBar. + DI_ALWAYSSHOWCOUNT = 0x200, // only for DrawInventoryBar. + DI_DIMDEPLETED = 0x400, + DI_DONTANIMATE = 0x800, // do not animate the texture + + DI_SCREEN_AUTO = 0, // decide based on given offsets. + DI_SCREEN_MANUAL_ALIGN = 0x4000, // If this is on, the following flags will have an effect + + DI_SCREEN_TOP = DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_VCENTER = 0x8000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_BOTTOM = 0x10000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_VOFFSET = 0x18000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_VMASK = 0x18000 | DI_SCREEN_MANUAL_ALIGN, + + DI_SCREEN_LEFT = DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_HCENTER = 0x20000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_RIGHT = 0x40000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_HOFFSET = 0x60000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_HMASK = 0x60000 | DI_SCREEN_MANUAL_ALIGN, + + DI_SCREEN_LEFT_TOP = DI_SCREEN_TOP|DI_SCREEN_LEFT, + DI_SCREEN_RIGHT_TOP = DI_SCREEN_TOP|DI_SCREEN_RIGHT, + DI_SCREEN_LEFT_BOTTOM = DI_SCREEN_BOTTOM|DI_SCREEN_LEFT, + DI_SCREEN_RIGHT_BOTTOM = DI_SCREEN_BOTTOM|DI_SCREEN_RIGHT, + DI_SCREEN_CENTER = DI_SCREEN_VCENTER|DI_SCREEN_HCENTER, + DI_SCREEN_CENTER_BOTTOM = DI_SCREEN_BOTTOM|DI_SCREEN_HCENTER, + DI_SCREEN_OFFSETS = DI_SCREEN_HOFFSET|DI_SCREEN_VOFFSET, + + DI_ITEM_AUTO = 0, // equivalent with bottom center, which is the default alignment. + + DI_ITEM_TOP = 0x80000, + DI_ITEM_VCENTER = 0x100000, + DI_ITEM_BOTTOM = 0, // this is the default vertical alignment + DI_ITEM_VOFFSET = 0x180000, + DI_ITEM_VMASK = 0x180000, + + DI_ITEM_LEFT = 0x200000, + DI_ITEM_HCENTER = 0, // this is the deafault horizontal alignment + DI_ITEM_RIGHT = 0x400000, + DI_ITEM_HOFFSET = 0x600000, + DI_ITEM_HMASK = 0x600000, + + DI_ITEM_LEFT_TOP = DI_ITEM_TOP|DI_ITEM_LEFT, + DI_ITEM_RIGHT_TOP = DI_ITEM_TOP|DI_ITEM_RIGHT, + DI_ITEM_LEFT_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_LEFT, + DI_ITEM_RIGHT_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_RIGHT, + DI_ITEM_CENTER = DI_ITEM_VCENTER|DI_ITEM_HCENTER, + DI_ITEM_CENTER_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_HCENTER, + DI_ITEM_OFFSETS = DI_ITEM_HOFFSET|DI_ITEM_VOFFSET, + + DI_TEXT_ALIGN_LEFT = 0, + DI_TEXT_ALIGN_RIGHT = 0x800000, + DI_TEXT_ALIGN_CENTER = 0x1000000, + DI_TEXT_ALIGN = 0x1800000, + + DI_ALPHAMAPPED = 0x2000000, + DI_NOSHADOW = 0x4000000, + DI_ALWAYSSHOWCOUNTERS = 0x8000000, + DI_ARTIFLASH = 0x10000000, + DI_FORCEFILL = 0x20000000, + + // These 2 flags are only used by SBARINFO so these duplicate other flags not used by SBARINFO + DI_DRAWINBOX = DI_TEXT_ALIGN_RIGHT, + DI_ALTERNATEONFAIL = DI_TEXT_ALIGN_CENTER, + }; #endif /* __SBAR_H__ */ diff --git a/src/g_statusbar/sbarinfo.cpp b/src/g_statusbar/sbarinfo.cpp index 438c3e3d2..c64dbef65 100644 --- a/src/g_statusbar/sbarinfo.cpp +++ b/src/g_statusbar/sbarinfo.cpp @@ -65,9 +65,7 @@ enum imgSELECTBOX, imgCURSOR, imgINVLFGEM1, - imgINVLFGEM2, imgINVRTGEM1, - imgINVRTGEM2, }; EXTERN_CVAR(Int, fraglimit) @@ -448,6 +446,7 @@ void SBarInfo::Load() { FreeSBarInfoScript(); MugShotStates.Clear(); + if(gameinfo.statusbar.IsNotEmpty()) { int lump = Wads.CheckNumForFullName(gameinfo.statusbar, true); @@ -981,18 +980,17 @@ public: static const char *InventoryBarLumps[] = { - "ARTIBOX", "SELECTBO", "INVCURS", "INVGEML1", - "INVGEML2", "INVGEMR1", "INVGEMR2", + "ARTIBOX", "SELECTBO", "INVCURS", "INVGEML1", "INVGEMR1", "USEARTIA", "USEARTIB", "USEARTIC", "USEARTID", }; TArray patchnames; - patchnames.Resize(script->Images.Size()+10); + patchnames.Resize(script->Images.Size()+9); unsigned int i = 0; for(i = 0;i < script->Images.Size();i++) { patchnames[i] = script->Images[i]; } - for(i = 0;i < 10;i++) + for(i = 0;i < 9;i++) { patchnames[i+script->Images.Size()] = InventoryBarLumps[i]; } @@ -1163,9 +1161,6 @@ public: lastInventoryBar->Tick(NULL, this, false); } - // void DSBarInfo::FlashItem(const PClass *itemtype) - Is defined with CommandDrawSelectedInventory - void _FlashItem(const PClass *itemtype); - void _ShowPop(int popnum) { if(popnum != currentPopup) @@ -1606,14 +1601,6 @@ DEFINE_ACTION_FUNCTION(DSBarInfo, Tick) return 0; } -DEFINE_ACTION_FUNCTION(DSBarInfo, FlashItem) -{ - PARAM_SELF_STRUCT_PROLOGUE(DSBarInfo); - PARAM_CLASS(w, AInventory); - self->_FlashItem(w); - return 0; -} - DEFINE_ACTION_FUNCTION(DSBarInfo, ShowPop) { PARAM_SELF_STRUCT_PROLOGUE(DSBarInfo); diff --git a/src/g_statusbar/sbarinfo_commands.cpp b/src/g_statusbar/sbarinfo_commands.cpp index f9b772581..458208b96 100644 --- a/src/g_statusbar/sbarinfo_commands.cpp +++ b/src/g_statusbar/sbarinfo_commands.cpp @@ -1691,16 +1691,16 @@ class CommandDrawSelectedInventory : public CommandDrawImage, private CommandDra if(statusBar->CPlayer->mo->InvSel != NULL && !(level.flags & LEVEL_NOINVENTORYBAR)) { - if(artiflash && artiflashTick) + if(artiflash && statusBar->wrapper->artiflashTick) { - statusBar->DrawGraphic(statusBar->Images[ARTIFLASH_OFFSET+(4-artiflashTick)], imgx, imgy, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), + statusBar->DrawGraphic(statusBar->Images[ARTIFLASH_OFFSET+(4- statusBar->wrapper->artiflashTick)], imgx, imgy, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), translatable, false, offset); } else { - if(itemflash && itemflashFade != 0) + if(itemflash && statusBar->wrapper->itemflashFade != 0) { - double flashAlpha = block->Alpha() * itemflashFade; + double flashAlpha = block->Alpha() * statusBar->wrapper->itemflashFade; statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgCURSOR], imgx-4, imgy+2, block->XOffset(), block->YOffset(), flashAlpha, block->FullScreenOffsets(), translatable, false, offset); } @@ -1789,38 +1789,18 @@ class CommandDrawSelectedInventory : public CommandDrawImage, private CommandDra { SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged); - if(artiflashTick > 0) - artiflashTick--; - if(itemflashFade > 0) - { - itemflashFade -= 1./14; - if(itemflashFade < 0) - itemflashFade = 0; - } - SetTruth(statusBar->CPlayer->mo->InvSel == NULL || (level.flags & LEVEL_NOINVENTORYBAR), block, statusBar); CommandDrawImage::Tick(block, statusBar, hudChanged); CommandDrawNumber::Tick(block, statusBar, hudChanged); } - static void Flash() { artiflashTick = 4; itemflashFade = 0.75; } protected: bool alternateOnEmpty; bool artiflash; bool alwaysShowCounter; bool itemflash; - - static int artiflashTick; - static double itemflashFade; }; -int CommandDrawSelectedInventory::artiflashTick = 0; -double CommandDrawSelectedInventory::itemflashFade = 0.75; - -void DSBarInfo::_FlashItem(const PClass *itemtype) -{ - CommandDrawSelectedInventory::Flash(); -} //////////////////////////////////////////////////////////////////////////////// @@ -2032,7 +2012,7 @@ class CommandDrawShader : public SBarInfoCommand void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) { - statusBar->DrawGraphic(&shaders[(vertical<<1) + reverse], x, y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, false, 0, true, width, height); + statusBar->DrawGraphic(shaders[(vertical<<1) + reverse], x, y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, false, 0, true, width, height); } void Parse(FScanner &sc, bool fullScreenOffsets) { @@ -2063,6 +2043,10 @@ class CommandDrawShader : public SBarInfoCommand } GetCoordinates(sc, fullScreenOffsets, x, y); sc.MustGetToken(';'); + shaders[0] = TexMan.FindTexture("BarShaderHF"); + shaders[1] = TexMan.FindTexture("BarShaderHR"); + shaders[2] = TexMan.FindTexture("BarShaderVF"); + shaders[3] = TexMan.FindTexture("BarShaderVR"); } protected: bool vertical; @@ -2072,87 +2056,8 @@ class CommandDrawShader : public SBarInfoCommand SBarInfoCoordinate x; SBarInfoCoordinate y; private: - class FBarShader : public FTexture - { - public: - FBarShader(bool vertical, bool reverse) - { - int i; - Width = vertical ? 2 : 256; - Height = vertical ? 256 : 2; - CalcBitSize(); - - // Fill the column/row with shading values. - // Vertical shaders have have minimum alpha at the top - // and maximum alpha at the bottom, unless flipped by - // setting reverse to true. Horizontal shaders are just - // the opposite. - if (vertical) - { - if (!reverse) - { - for (i = 0; i < 256; ++i) - { - Pixels[i] = i; - Pixels[256+i] = i; - } - } - else - { - for (i = 0; i < 256; ++i) - { - Pixels[i] = 255 - i; - Pixels[256+i] = 255 -i; - } - } - } - else - { - if (!reverse) - { - for (i = 0; i < 256; ++i) - { - Pixels[i*2] = 255 - i; - Pixels[i*2+1] = 255 - i; - } - } - else - { - for (i = 0; i < 256; ++i) - { - Pixels[i*2] = i; - Pixels[i*2+1] = i; - } - } - } - DummySpan[0].TopOffset = 0; - DummySpan[0].Length = vertical ? 256 : 2; - DummySpan[1].TopOffset = 0; - DummySpan[1].Length = 0; - } - const uint8_t *GetColumn(unsigned int column, const Span **spans_out) - { - if (spans_out != NULL) - { - *spans_out = DummySpan; - } - return Pixels + ((column & WidthMask) << HeightBits); - } - const uint8_t *GetPixels() { return Pixels; } - void Unload() {} - private: - uint8_t Pixels[512]; - Span DummySpan[2]; - }; - - static FBarShader shaders[4]; -}; - -CommandDrawShader::FBarShader CommandDrawShader::shaders[4] = -{ - FBarShader(false, false), FBarShader(false, true), - FBarShader(true, false), FBarShader(true, true) + FTexture *shaders[4]; }; //////////////////////////////////////////////////////////////////////////////// @@ -2230,16 +2135,14 @@ class CommandDrawInventoryBar : public SBarInfoCommand { int offset = (style != STYLE_Strife ? (style != STYLE_HexenStrict ? -12 : -10) : 14); int yOffset = style != STYLE_HexenStrict ? 0 : -1; - statusBar->DrawGraphic(statusBar->Images[!(gametic & 4) ? - statusBar->invBarOffset + imgINVLFGEM1 : statusBar->invBarOffset + imgINVLFGEM2], x + (!vertical ? offset : yOffset), y + (vertical ? offset : yOffset), block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgINVLFGEM1], x + (!vertical ? offset : yOffset), y + (vertical ? offset : yOffset), block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); } // Is there something to the right? if (!noArrows && item != NULL) { int offset = (style != STYLE_Strife ? (style != STYLE_HexenStrict ? size*31+2 : size*31) : size*35-4); int yOffset = style != STYLE_HexenStrict ? 0 : -1; - statusBar->DrawGraphic(statusBar->Images[!(gametic & 4) ? - statusBar->invBarOffset + imgINVRTGEM1 : statusBar->invBarOffset + imgINVRTGEM2], x + (!vertical ? offset : yOffset), y + (vertical ? offset : yOffset), block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgINVRTGEM1], x + (!vertical ? offset : yOffset), y + (vertical ? offset : yOffset), block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); } } } diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index d8c46a1dd..240c30fac 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -243,16 +243,24 @@ void ST_CreateStatusBar(bool bTitleLevel) StatusBar = new DBaseStatusBar(); StatusBar->SetSize(0); } - else if (gameinfo.statusbarclassfile >= gameinfo.statusbarfile) + else { - auto cls = PClass::FindClass(gameinfo.statusbarclass); - if (cls != nullptr) + // The old rule of 'what came last wins' goes here, as well. + // If the most recent SBARINFO definition comes before a status bar class definition it will be picked, + // if the class is defined later, this will be picked. If both come from the same file, the class definition will win. + int sbarinfolump = Wads.CheckNumForName("SBARINFO"); + int sbarinfofile = Wads.GetLumpFile(sbarinfolump); + if (gameinfo.statusbarclassfile >= gameinfo.statusbarfile && gameinfo.statusbarclassfile >= sbarinfofile) { - StatusBar = (DBaseStatusBar *)cls->CreateNew(); - IFVIRTUALPTR(StatusBar, DBaseStatusBar, Init) + auto cls = PClass::FindClass(gameinfo.statusbarclass); + if (cls != nullptr) { - VMValue params[] = { StatusBar }; - GlobalVMStack.Call(func, params, 1, nullptr, 0); + StatusBar = (DBaseStatusBar *)cls->CreateNew(); + IFVIRTUALPTR(StatusBar, DBaseStatusBar, Init) + { + VMValue params[] = { StatusBar }; + GlobalVMStack.Call(func, params, 1, nullptr, 0); + } } } } @@ -283,7 +291,6 @@ void ST_CreateStatusBar(bool bTitleLevel) auto cls = PClass::FindClass(defname); if (cls != nullptr) { - StatusBar = (DBaseStatusBar *)cls->CreateNew(); IFVIRTUALPTR(StatusBar, DBaseStatusBar, Init) { @@ -327,6 +334,9 @@ void DBaseStatusBar::SetSize(int reltop, int hres, int vres) RelTop = reltop; HorizontalResolution = hres; VerticalResolution = vres; + int x, y; + V_CalcCleanFacs(hres, vres, SCREENWIDTH, SCREENHEIGHT, &x, &y); + defaultScale = { (double)x, (double)y }; CallSetScaled(st_scale); } @@ -500,7 +510,7 @@ DEFINE_ACTION_FUNCTION(DBaseStatusBar, BeginStatusBar) void DBaseStatusBar::BeginHUD(int resW, int resH, double Alpha, bool forcescaled) { - SetSize(0, resW, resH); // this intentionally resets the relative top to force the caller to go through BeginStatusBar and not just reset some variables. + SetSize(RelTop, resW, resH); this->Alpha = Alpha; ForcedScale = forcescaled; CompleteBorder = false; @@ -583,6 +593,19 @@ void DBaseStatusBar::Tick () } } } + + if (artiflashTick > 0) + artiflashTick--; + + if (itemflashFade > 0) + { + itemflashFade -= 1 / 14.; + if (itemflashFade < 0) + { + itemflashFade = 0; + } + } + } DEFINE_ACTION_FUNCTION(DBaseStatusBar, Tick) @@ -1112,6 +1135,7 @@ void DBaseStatusBar::CallDraw(EHudState state) GlobalVMStack.Call(func, params, countof(params), nullptr, 0); } else Draw(state); + screen->ClearClipRect(); // make sure the scripts don't leave a valid clipping rect behind. } @@ -1397,11 +1421,8 @@ void DBaseStatusBar::SerializeMessages(FSerializer &arc) void DBaseStatusBar::ScreenSizeChanged () { - st_scale.Callback (); - - int x, y; - V_CalcCleanFacs(HorizontalResolution, VerticalResolution, SCREENWIDTH, SCREENHEIGHT, &x, &y); - defaultScale = { (double)x, (double)y }; + // We need to recalculate the sizing info + SetSize(RelTop, HorizontalResolution, VerticalResolution); for (size_t i = 0; i < countof(Messages); ++i) { @@ -1543,124 +1564,221 @@ uint32_t DBaseStatusBar::GetTranslation() const // //============================================================================ -void DBaseStatusBar::DrawGraphic(FTextureID texture, bool animate, double x, double y, double Alpha, bool translatable, bool dim, - int imgAlign, int screenalign, bool alphamap, double width, double height) +void DBaseStatusBar::DrawGraphic(FTextureID texture, double x, double y, int flags, double Alpha, double boxwidth, double boxheight, double scaleX, double scaleY) { if (!texture.isValid()) return; + FTexture *tex = (flags & DI_DONTANIMATE)? TexMan[texture] : TexMan(texture); + + double texwidth = tex->GetScaledWidthDouble() * scaleX; + double texheight = tex->GetScaledHeightDouble() * scaleY; + + if (boxwidth > 0 || boxheight > 0) + { + if (!(flags & DI_FORCEFILL)) + { + double scale1 = 1., scale2 = 1.; + + if (boxwidth > 0 && (boxwidth < texwidth || (flags & DI_FORCESCALE))) + { + scale1 = boxwidth / texwidth; + } + if (boxheight != -1 && (boxheight < texheight || (flags & DI_FORCESCALE))) + { + scale2 = boxheight / texheight; + } + + if (flags & DI_FORCESCALE) + { + if (boxwidth <= 0 || (boxheight > 0 && scale2 < scale1)) + scale1 = scale2; + } + else scale1 = MIN(scale1, scale2); + + boxwidth = texwidth * scale1; + boxheight = texheight * scale1; + } + } + else + { + boxwidth = texwidth; + boxheight = texheight; + } + + // resolve auto-alignment before making any adjustments to the position values. + if (!(flags & DI_SCREEN_MANUAL_ALIGN)) + { + if (x < 0) flags |= DI_SCREEN_RIGHT; + else flags |= DI_SCREEN_LEFT; + if (y < 0) flags |= DI_SCREEN_BOTTOM; + else flags |= DI_SCREEN_TOP; + } + Alpha *= this->Alpha; if (Alpha <= 0) return; x += drawOffset.X; y += drawOffset.Y; - FTexture *tex = animate ? TexMan(texture) : TexMan[texture]; - - switch (imgAlign & HMASK) + switch (flags & DI_ITEM_HMASK) { - case HCENTER: x -= width / 2; break; - case RIGHT: x -= width; break; - case HOFFSET: x -= tex->GetScaledLeftOffsetDouble() * width / tex->GetScaledWidthDouble(); break; + case DI_ITEM_HCENTER: x -= boxwidth / 2; break; + case DI_ITEM_RIGHT: x -= boxwidth; break; + case DI_ITEM_HOFFSET: x -= tex->GetScaledLeftOffsetDouble() * boxwidth / texwidth; break; } - switch (imgAlign & VMASK) + switch (flags & DI_ITEM_VMASK) { - case VCENTER: y -= height / 2; break; - case BOTTOM: y -= height; break; - case VOFFSET: y -= tex->GetScaledTopOffsetDouble() * height / tex->GetScaledHeightDouble(); break; + case DI_ITEM_VCENTER: y -= boxheight / 2; break; + case DI_ITEM_BOTTOM: y -= boxheight; break; + case DI_ITEM_VOFFSET: y -= tex->GetScaledTopOffsetDouble() * boxheight / texheight; break; } if (!fullscreenOffsets) { x += ST_X; - y += ST_Y; + //y += ST_Y; // Todo: Allow other scaling values, too. if (Scaled) { - screen->VirtualToRealCoords(x, y, width, height, HorizontalResolution, VerticalResolution, true, true); + screen->VirtualToRealCoords(x, y, boxwidth, boxheight, HorizontalResolution, VerticalResolution, true, true); } } else { double orgx, orgy; - switch (screenalign & HMASK) + switch (flags & DI_SCREEN_HMASK) { default: orgx = 0; break; - case HCENTER: orgx = screen->GetWidth() / 2; break; - case RIGHT: orgx = screen->GetWidth(); break; + case DI_SCREEN_HCENTER: orgx = screen->GetWidth() / 2; break; + case DI_SCREEN_RIGHT: orgx = screen->GetWidth(); break; } - switch (screenalign & VMASK) + switch (flags & DI_SCREEN_VMASK) { default: orgy = 0; break; - case VCENTER: orgy = screen->GetHeight() / 2; break; - case BOTTOM: orgy = screen->GetHeight(); break; + case DI_SCREEN_VCENTER: orgy = screen->GetHeight() / 2; break; + case DI_SCREEN_BOTTOM: orgy = screen->GetHeight(); break; } - if (screenalign == (RIGHT | TOP) && vid_fps) y += 10; + // move stuff in the top right corner a bit down if the fps counter is on. + if ((flags & (DI_SCREEN_HMASK|DI_SCREEN_VMASK)) == DI_SCREEN_RIGHT_TOP && vid_fps) y += 10; DVector2 Scale = GetHUDScale(); x *= Scale.X; y *= Scale.Y; - width *= Scale.X; - height *= Scale.Y; + boxwidth *= Scale.X; + boxheight *= Scale.Y; x += orgx; y += orgy; } screen->DrawTexture(tex, x, y, DTA_TopOffset, 0, DTA_LeftOffset, 0, - DTA_DestWidthF, width, - DTA_DestHeightF, height, - DTA_TranslationIndex, translatable ? GetTranslation() : 0, - DTA_ColorOverlay, dim ? MAKEARGB(170, 0, 0, 0) : 0, + DTA_DestWidthF, boxwidth, + DTA_DestHeightF, boxheight, + DTA_TranslationIndex, (flags & DI_TRANSLATABLE) ? GetTranslation() : 0, + DTA_ColorOverlay, (flags & DI_DIM) ? MAKEARGB(170, 0, 0, 0) : 0, DTA_Alpha, Alpha, - DTA_AlphaChannel, alphamap, - DTA_FillColor, alphamap ? 0 : -1); + DTA_AlphaChannel, !!(flags & DI_ALPHAMAPPED), + DTA_FillColor, (flags & DI_ALPHAMAPPED) ? 0 : -1); } -DEFINE_ACTION_FUNCTION(DBaseStatusBar, DrawGraphic) +DEFINE_ACTION_FUNCTION(DBaseStatusBar, DrawTexture) { PARAM_SELF_PROLOGUE(DBaseStatusBar); PARAM_INT(texid); - PARAM_BOOL(animate); PARAM_FLOAT(x); PARAM_FLOAT(y); - PARAM_FLOAT(alpha); - PARAM_BOOL(translatable); - PARAM_BOOL(dim); - PARAM_INT(ialign); - PARAM_INT(salign); - PARAM_BOOL(alphamap); - PARAM_FLOAT(w); - PARAM_FLOAT(h); - self->DrawGraphic(FSetTextureID(texid), animate, x, y, alpha, translatable, dim, ialign, salign, alphamap, w, h); + PARAM_INT_DEF(flags); + PARAM_FLOAT_DEF(alpha); + PARAM_FLOAT_DEF(w); + PARAM_FLOAT_DEF(h); + PARAM_FLOAT_DEF(scaleX); + PARAM_FLOAT_DEF(scaleY); + if (!screen->IsLocked()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + self->DrawGraphic(FSetTextureID(texid), x, y, flags, alpha, w, h, scaleX, scaleY); + return 0; +} + +DEFINE_ACTION_FUNCTION(DBaseStatusBar, DrawImage) +{ + PARAM_SELF_PROLOGUE(DBaseStatusBar); + PARAM_STRING(texid); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_INT_DEF(flags); + PARAM_FLOAT_DEF(alpha); + PARAM_FLOAT_DEF(w); + PARAM_FLOAT_DEF(h); + PARAM_FLOAT_DEF(scaleX); + PARAM_FLOAT_DEF(scaleY); + if (!screen->IsLocked()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + self->DrawGraphic(TexMan.CheckForTexture(texid, FTexture::TEX_Any), x, y, flags, alpha, w, h, scaleX, scaleY); return 0; } //============================================================================ // -// draw stuff +// encapsulates all settings a HUD font may need // //============================================================================ -void DBaseStatusBar::DrawString(FFont *font, const FString &cstring, double x, double y, double Alpha, int translation, int align, int screenalign, int spacing, bool monospaced, int shadowX, int shadowY) +class DHUDFont : public DObject { - switch (align) + // this blocks CreateNew on this class which is the intent here. + DECLARE_ABSTRACT_CLASS(DHUDFont, DObject); + +public: + FFont *mFont; + int mSpacing; + bool mMonospaced; + int mShadowX; + int mShadowY; + + DHUDFont(FFont *f, int sp, bool ms, int sx, int sy) + : mFont(f), mSpacing(sp), mMonospaced(ms), mShadowX(sx), mShadowY(sy) + {} +}; + +IMPLEMENT_CLASS(DHUDFont, true, false); + +DEFINE_ACTION_FUNCTION(DHUDFont, Create) +{ + PARAM_PROLOGUE; + PARAM_POINTER(fnt, FFont); + PARAM_INT_DEF(spac); + PARAM_BOOL_DEF(mono); + PARAM_INT_DEF(sx); + PARAM_INT_DEF(sy); + ACTION_RETURN_POINTER(new DHUDFont(fnt, spac, mono, sy, sy)); +} + +DEFINE_FIELD(DHUDFont, mFont); + +//============================================================================ +// +// draw a string +// +//============================================================================ + +void DBaseStatusBar::DrawString(FFont *font, const FString &cstring, double x, double y, int flags, double Alpha, int translation, int spacing, bool monospaced, int shadowX, int shadowY) +{ + switch (flags & DI_TEXT_ALIGN) { default: break; - case ALIGN_RIGHT: + case DI_TEXT_ALIGN_RIGHT: if (!monospaced) x -= static_cast (font->StringWidth(cstring) + (spacing * cstring.Len())); else //monospaced, so just multiply the character size x -= static_cast ((spacing) * cstring.Len()); break; - case ALIGN_CENTER: + case DI_TEXT_ALIGN_CENTER: if (!monospaced) x -= static_cast (font->StringWidth(cstring) + (spacing * cstring.Len())) / 2; else //monospaced, so just multiply the character size @@ -1680,21 +1798,22 @@ void DBaseStatusBar::DrawString(FFont *font, const FString &cstring, double x, d shadowX *= (int)Scale.X; shadowY *= (int)Scale.Y; - switch (screenalign & HMASK) + switch (flags & DI_SCREEN_HMASK) { default: orgx = 0; break; - case HCENTER: orgx = screen->GetWidth() / 2; break; - case RIGHT: orgx = screen->GetWidth(); break; + case DI_SCREEN_HCENTER: orgx = screen->GetWidth() / 2; break; + case DI_SCREEN_RIGHT: orgx = screen->GetWidth(); break; } - switch (screenalign & VMASK) + switch (flags & DI_SCREEN_VMASK) { default: orgy = 0; break; - case VCENTER: orgy = screen->GetHeight() / 2; break; - case BOTTOM: orgy = screen->GetHeight(); break; + case DI_SCREEN_VCENTER: orgy = screen->GetHeight() / 2; break; + case DI_SCREEN_BOTTOM: orgy = screen->GetHeight(); break; } - if (screenalign == (RIGHT | TOP) && vid_fps) orgy += 10; + // move stuff in the top right corner a bit down if the fps counter is on. + if ((flags & (DI_SCREEN_HMASK | DI_SCREEN_VMASK)) == DI_SCREEN_RIGHT_TOP && vid_fps) y += 10; } else { @@ -1732,27 +1851,10 @@ void DBaseStatusBar::DrawString(FFont *font, const FString &cstring, double x, d rw = c->GetScaledWidthDouble(); rh = c->GetScaledHeightDouble(); - if (monospaced) - { - // align the character in the monospaced cell according to the general alignment to ensure that it gets positioned properly - // (i.e. right aligned text aligns to the right edge of the character and not the empty part of the cell.) - switch (align) - { - default: - break; - case ALIGN_CENTER: - rx -= (spacing) / 2; - break; - case ALIGN_RIGHT: - rx -= spacing; - break; - } - } - if (!fullscreenOffsets) { rx += ST_X; - ry += ST_Y; + //ry += ST_Y; // Todo: Allow other scaling values, too. if (Scaled) @@ -1772,7 +1874,7 @@ void DBaseStatusBar::DrawString(FFont *font, const FString &cstring, double x, d } // This is not really such a great way to draw shadows because they can overlap with previously drawn characters. // This may have to be changed to draw the shadow text up front separately. - if (shadowX != 0 || shadowY != 0) + if ((shadowX != 0 || shadowY != 0) && !(flags & DI_NOSHADOW)) { screen->DrawChar(font, CR_UNTRANSLATED, rx + shadowX, ry + shadowY, ch, DTA_DestWidthF, rw, @@ -1795,44 +1897,129 @@ void DBaseStatusBar::DrawString(FFont *font, const FString &cstring, double x, d } - - DEFINE_ACTION_FUNCTION(DBaseStatusBar, DrawString) { PARAM_SELF_PROLOGUE(DBaseStatusBar); - PARAM_POINTER(font, FFont); + PARAM_POINTER(font, DHUDFont); PARAM_STRING(string); PARAM_FLOAT(x); PARAM_FLOAT(y); - PARAM_FLOAT(alpha); - PARAM_INT(trans); - PARAM_INT(ialign); - PARAM_INT(salign); - PARAM_INT_DEF(spacing); - PARAM_BOOL_DEF(monospaced); - PARAM_INT_DEF(shadowX); - PARAM_INT_DEF(shadowY); + PARAM_INT_DEF(flags); + PARAM_INT_DEF(trans); + PARAM_FLOAT_DEF(alpha); PARAM_INT_DEF(wrapwidth); PARAM_INT_DEF(linespacing); + if (!screen->IsLocked()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + + // resolve auto-alignment before making any adjustments to the position values. + if (!(flags & DI_SCREEN_MANUAL_ALIGN)) + { + if (x < 0) flags |= DI_SCREEN_RIGHT; + else flags |= DI_SCREEN_LEFT; + if (y < 0) flags |= DI_SCREEN_BOTTOM; + else flags |= DI_SCREEN_TOP; + } + if (wrapwidth > 0) { - FBrokenLines *brk = V_BreakLines(font, wrapwidth, string, true); + FBrokenLines *brk = V_BreakLines(font->mFont, wrapwidth, string, true); for (int i = 0; brk[i].Width >= 0; i++) { - self->DrawString(font, brk[i].Text, x, y, alpha, trans, ialign, salign, spacing, monospaced, shadowX, shadowY); - y += font->GetHeight() + linespacing; + self->DrawString(font->mFont, brk[i].Text, x, y, flags, alpha, trans, font->mSpacing, font->mMonospaced, font->mShadowX, font->mShadowY); + y += font->mFont->GetHeight() + linespacing; } V_FreeBrokenLines(brk); } else { - self->DrawString(font, string, x, y, alpha, trans, ialign, salign, spacing, monospaced, shadowX, shadowY); + self->DrawString(font->mFont, string, x, y, flags, alpha, trans, font->mSpacing, font->mMonospaced, font->mShadowX, font->mShadowY); } return 0; } +//============================================================================ +// +// draw stuff +// +//============================================================================ + +void DBaseStatusBar::Fill(PalEntry color, double x, double y, double w, double h, int flags) +{ + // resolve auto-alignment before making any adjustments to the position values. + if (!(flags & DI_SCREEN_MANUAL_ALIGN)) + { + if (x < 0) flags |= DI_SCREEN_RIGHT; + else flags |= DI_SCREEN_LEFT; + if (y < 0) flags |= DI_SCREEN_BOTTOM; + else flags |= DI_SCREEN_TOP; + } + + double Alpha = color.a * this->Alpha / 255; + if (Alpha <= 0) return; + x += drawOffset.X; + y += drawOffset.Y; + + if (!fullscreenOffsets) + { + x += ST_X; + //y += ST_Y; + + // Todo: Allow other scaling values, too. + if (Scaled) + { + screen->VirtualToRealCoords(x, y, w, h, HorizontalResolution, VerticalResolution, true, true); + } + } + else + { + double orgx, orgy; + + switch (flags & DI_SCREEN_HMASK) + { + default: orgx = 0; break; + case DI_SCREEN_HCENTER: orgx = screen->GetWidth() / 2; break; + case DI_SCREEN_RIGHT: orgx = screen->GetWidth(); break; + } + + switch (flags & DI_SCREEN_VMASK) + { + default: orgy = 0; break; + case DI_SCREEN_VCENTER: orgy = screen->GetHeight() / 2; break; + case DI_SCREEN_BOTTOM: orgy = screen->GetHeight(); break; + } + + // move stuff in the top right corner a bit down if the fps counter is on. + if ((flags & (DI_SCREEN_HMASK | DI_SCREEN_VMASK)) == DI_SCREEN_RIGHT_TOP && vid_fps) y += 10; + + DVector2 Scale = GetHUDScale(); + + x *= Scale.X; + y *= Scale.Y; + w *= Scale.X; + h *= Scale.Y; + x += orgx; + y += orgy; + } + screen->Dim(color, float(Alpha), int(x), int(y), int(w), int(h)); +} + + +DEFINE_ACTION_FUNCTION(DBaseStatusBar, Fill) +{ + PARAM_SELF_PROLOGUE(DBaseStatusBar); + PARAM_COLOR(color); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(w); + PARAM_FLOAT(h); + PARAM_INT_DEF(flags); + if (!screen->IsLocked()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + self->Fill(color, x, y, w, h); + return 0; +} + //============================================================================ // // CCMD showpop @@ -1876,6 +2063,8 @@ DEFINE_FIELD(DBaseStatusBar, drawOffset); DEFINE_FIELD(DBaseStatusBar, drawClip); DEFINE_FIELD(DBaseStatusBar, fullscreenOffsets); DEFINE_FIELD(DBaseStatusBar, defaultScale); +DEFINE_FIELD(DBaseStatusBar, artiflashTick); +DEFINE_FIELD(DBaseStatusBar, itemflashFade); DEFINE_GLOBAL(StatusBar); @@ -1928,9 +2117,9 @@ DEFINE_ACTION_FUNCTION(DBaseStatusBar, FormatNumber) { PARAM_PROLOGUE; PARAM_INT(number); - PARAM_INT(minsize); - PARAM_INT(maxsize); - PARAM_INT(flags); + PARAM_INT_DEF(minsize); + PARAM_INT_DEF(maxsize); + PARAM_INT_DEF(flags); PARAM_STRING_DEF(prefix); static int maxvals[] = { 1, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999 }; @@ -1956,10 +2145,10 @@ DEFINE_ACTION_FUNCTION(DBaseStatusBar, ReceivedWeapon) DEFINE_ACTION_FUNCTION(DBaseStatusBar, GetMugshot) { PARAM_SELF_PROLOGUE(DBaseStatusBar); - PARAM_POINTER(player, player_t); - PARAM_STRING(def_face); PARAM_INT(accuracy); PARAM_INT_DEF(stateflags); - auto tex = self->mugshot.GetFace(player, def_face, accuracy, (FMugShot::StateFlags)stateflags); + PARAM_STRING_DEF(def_face); + auto tex = self->mugshot.GetFace(self->CPlayer, def_face, accuracy, (FMugShot::StateFlags)stateflags); ACTION_RETURN_INT(tex ? tex->id.GetIndex() : -1); } + diff --git a/src/gl/scene/gl_flats.cpp b/src/gl/scene/gl_flats.cpp index 76c6466ab..0d14378af 100644 --- a/src/gl/scene/gl_flats.cpp +++ b/src/gl/scene/gl_flats.cpp @@ -424,7 +424,7 @@ void GLFlat::Draw(int pass, bool trans) // trans only has meaning for GLPASS_LIG else gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); gl_RenderState.SetMaterial(gltexture, CLAMP_NONE, 0, -1, false); gl_SetPlaneTextureRotation(&plane, gltexture); - DrawSubsectors(pass, !gl.legacyMode, true); + DrawSubsectors(pass, !gl.legacyMode && (gl.lightmethod == LM_DIRECT || dynlightindex > -1), true); gl_RenderState.EnableTextureMatrix(false); } if (renderstyle==STYLE_Add) gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); diff --git a/src/gl/scene/gl_spritelight.cpp b/src/gl/scene/gl_spritelight.cpp index 3283f0086..793a10c7c 100644 --- a/src/gl/scene/gl_spritelight.cpp +++ b/src/gl/scene/gl_spritelight.cpp @@ -62,7 +62,7 @@ void gl_SetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t * while (node) { light=node->lightsource; - if (light->visibletoplayer && !(light->flags2&MF2_DORMANT) && (!(light->flags4&MF4_DONTLIGHTSELF) || light->target != self)) + if (light->visibletoplayer && !(light->flags2&MF2_DORMANT) && (!(light->flags4&MF4_DONTLIGHTSELF) || light->target != self) && !(light->flags4&MF4_DONTLIGHTACTORS)) { float dist; diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index 43c56018a..08afb72ae 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -361,6 +361,7 @@ FNativePalette *OpenGLFrameBuffer::CreatePalette(FRemapTable *remap) //========================================================================== bool OpenGLFrameBuffer::Begin2D(bool) { + ClearClipRect(); gl_RenderState.mViewMatrix.loadIdentity(); gl_RenderState.mProjectionMatrix.ortho(0, GetWidth(), GetHeight(), 0, -1.0f, 1.0f); gl_RenderState.ApplyMatrices(); @@ -428,7 +429,7 @@ void OpenGLFrameBuffer::Dim(PalEntry) Super::Dim(0); } -void OpenGLFrameBuffer::Dim(PalEntry color, float damount, int x1, int y1, int w, int h) +void OpenGLFrameBuffer::DoDim(PalEntry color, float damount, int x1, int y1, int w, int h) { if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr) GLRenderer->m2DDrawer->AddDim(color, damount, x1, y1, w, h); @@ -451,7 +452,7 @@ void OpenGLFrameBuffer::FlatFill (int left, int top, int right, int bottom, FTex // // //========================================================================== -void OpenGLFrameBuffer::Clear(int left, int top, int right, int bottom, int palcolor, uint32_t color) +void OpenGLFrameBuffer::DoClear(int left, int top, int right, int bottom, int palcolor, uint32_t color) { if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr) GLRenderer->m2DDrawer->AddClear(left, top, right, bottom, palcolor, color); diff --git a/src/gl/system/gl_framebuffer.h b/src/gl/system/gl_framebuffer.h index 67d5969e5..72bdb7315 100644 --- a/src/gl/system/gl_framebuffer.h +++ b/src/gl/system/gl_framebuffer.h @@ -63,9 +63,9 @@ public: void DrawTextureParms(FTexture *img, DrawParms &parms); void DrawLine(int x1, int y1, int x2, int y2, int palcolor, uint32_t color); void DrawPixel(int x1, int y1, int palcolor, uint32_t color); - void Clear(int left, int top, int right, int bottom, int palcolor, uint32_t color); + void DoClear(int left, int top, int right, int bottom, int palcolor, uint32_t color); void Dim(PalEntry color=0); - void Dim (PalEntry color, float damount, int x1, int y1, int w, int h); + void DoDim (PalEntry color, float damount, int x1, int y1, int w, int h); void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin=false); void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, diff --git a/src/gl/system/gl_swframebuffer.cpp b/src/gl/system/gl_swframebuffer.cpp index 6ff2e0943..acf5dc40b 100644 --- a/src/gl/system/gl_swframebuffer.cpp +++ b/src/gl/system/gl_swframebuffer.cpp @@ -2410,6 +2410,7 @@ bool OpenGLSWFrameBuffer::OpenGLPal::Update() bool OpenGLSWFrameBuffer::Begin2D(bool copy3d) { + ClearClipRect(); if (!Accel2D) { return false; @@ -2488,7 +2489,7 @@ FNativePalette *OpenGLSWFrameBuffer::CreatePalette(FRemapTable *remap) // //========================================================================== -void OpenGLSWFrameBuffer::Clear(int left, int top, int right, int bottom, int palcolor, uint32_t color) +void OpenGLSWFrameBuffer::DoClear(int left, int top, int right, int bottom, int palcolor, uint32_t color) { if (In2D < 2) { @@ -2517,7 +2518,7 @@ void OpenGLSWFrameBuffer::Clear(int left, int top, int right, int bottom, int pa // //========================================================================== -void OpenGLSWFrameBuffer::Dim(PalEntry color, float amount, int x1, int y1, int w, int h) +void OpenGLSWFrameBuffer::DoDim(PalEntry color, float amount, int x1, int y1, int w, int h) { if (amount <= 0) { diff --git a/src/gl/system/gl_swframebuffer.h b/src/gl/system/gl_swframebuffer.h index dc202a05c..03cc5a4e0 100644 --- a/src/gl/system/gl_swframebuffer.h +++ b/src/gl/system/gl_swframebuffer.h @@ -55,8 +55,8 @@ public: FNativeTexture *CreateTexture(FTexture *gametex, bool wrapping) override; FNativePalette *CreatePalette(FRemapTable *remap) override; void DrawTextureParms(FTexture *img, DrawParms &parms) override; - void Clear(int left, int top, int right, int bottom, int palcolor, uint32_t color) override; - void Dim(PalEntry color, float amount, int x1, int y1, int w, int h) override; + void DoClear(int left, int top, int right, int bottom, int palcolor, uint32_t color) override; + void DoDim(PalEntry color, float amount, int x1, int y1, int w, int h) override; void FlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin) override; void DrawLine(int x0, int y0, int x1, int y1, int palColor, uint32_t realcolor) override; void DrawPixel(int x, int y, int palcolor, uint32_t rgbcolor) override; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 5c8607308..437e7ff89 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -339,35 +339,7 @@ void cht_DoCheat (player_t *player, int cheat) } else { - player->mo->Revive(); - player->playerstate = PST_LIVE; - player->health = player->mo->health = player->mo->GetDefault()->health; - player->viewheight = ((APlayerPawn *)player->mo->GetDefault())->ViewHeight; - player->mo->renderflags &= ~RF_INVISIBLE; - player->mo->Height = player->mo->GetDefault()->Height; - player->mo->radius = player->mo->GetDefault()->radius; - player->mo->special1 = 0; // required for the Hexen fighter's fist attack. - // This gets set by AActor::Die as flag for the wimpy death and must be reset here. - player->mo->SetState (player->mo->SpawnState); - if (!(player->mo->flags2 & MF2_DONTTRANSLATE)) - { - player->mo->Translation = TRANSLATION(TRANSLATION_Players, uint8_t(player-players)); - } - if (player->ReadyWeapon != nullptr) - { - P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->GetUpState()); - } - - if (player->morphTics) - { - P_UndoPlayerMorph(player, player); - } - - // player is now alive. - // fire E_PlayerRespawned and start the ACS SCRIPT_Respawn. - E_PlayerRespawned(int(player - players)); - // - FBehavior::StaticStartTypedScripts(SCRIPT_Respawn, player->mo, true); + player->Resurrect(); } } diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index cf82b27f5..5ae578499 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -280,6 +280,7 @@ void DMenu::CallDrawer() { VMValue params[] = { (DObject*)this }; GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + screen->ClearClipRect(); // make sure the scripts don't leave a valid clipping rect behind. } } diff --git a/src/namedef.h b/src/namedef.h index ca99ff650..a193945de 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -901,3 +901,4 @@ xx(Player5) xx(Player6) xx(Player7) xx(Player8) +xx(PlayerChunk) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index a0794f1d6..055274d3d 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -654,6 +654,36 @@ DEFINE_ACTION_FUNCTION(AActor, GetCVar) return 0; } +//========================================================================== +// +// GetCVar +// +// NON-ACTION function that works like ACS's GetCVar. +// +//========================================================================== + +DEFINE_ACTION_FUNCTION(AActor, GetCVarString) +{ + if (numret > 0) + { + assert(ret != nullptr); + PARAM_SELF_PROLOGUE(AActor); + PARAM_STRING(cvarname); + + FBaseCVar *cvar = GetCVar(self, cvarname); + if (cvar == nullptr) + { + ret->SetString(""); + } + else + { + ret->SetString(cvar->GetGenericRep(CVAR_String).String); + } + return 1; + } + return 0; +} + //========================================================================== // // GetPlayerInput diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 870b0a8df..ff8c093c0 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1045,6 +1045,12 @@ AInventory *AActor::FirstInv () return Inventory->NextInv (); } +DEFINE_ACTION_FUNCTION(AActor, FirstInv) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_OBJECT(self->FirstInv()); +} + //============================================================================ // // AActor :: UseInventory diff --git a/src/p_user.cpp b/src/p_user.cpp index 19de4cb18..694daffa1 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -62,6 +62,8 @@ #include "g_levellocals.h" #include "actorinlines.h" #include "r_data/r_translate.h" +#include "p_acs.h" +#include "events.h" static FRandom pr_skullpop ("SkullPop"); @@ -707,6 +709,65 @@ void player_t::SendPitchLimits() const } +bool player_t::HasWeaponsInSlot(int slot) const +{ + for (int i = 0; i < weapons.Slots[slot].Size(); i++) + { + PClassActor *weap = weapons.Slots[slot].GetWeapon(i); + if (weap != NULL && mo->FindInventory(weap)) return true; + } + return false; +} + +DEFINE_ACTION_FUNCTION(_PlayerInfo, HasWeaponsInSlot) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_INT(slot); + ACTION_RETURN_BOOL(self->HasWeaponsInSlot(slot)); +} + + +bool player_t::Resurrect() +{ + if (mo == nullptr || mo->IsKindOf(NAME_PlayerChunk)) return false; + mo->Revive(); + playerstate = PST_LIVE; + health = mo->health = mo->GetDefault()->health; + viewheight = ((APlayerPawn *)mo->GetDefault())->ViewHeight; + mo->renderflags &= ~RF_INVISIBLE; + mo->Height = mo->GetDefault()->Height; + mo->radius = mo->GetDefault()->radius; + mo->special1 = 0; // required for the Hexen fighter's fist attack. + // This gets set by AActor::Die as flag for the wimpy death and must be reset here. + mo->SetState(mo->SpawnState); + if (!(mo->flags2 & MF2_DONTTRANSLATE)) + { + mo->Translation = TRANSLATION(TRANSLATION_Players, uint8_t(this - players)); + } + if (ReadyWeapon != nullptr) + { + P_SetPsprite(this, PSP_WEAPON, ReadyWeapon->GetUpState()); + } + + if (morphTics) + { + P_UndoPlayerMorph(this, this); + } + + // player is now alive. + // fire E_PlayerRespawned and start the ACS SCRIPT_Respawn. + E_PlayerRespawned(int(this - players)); + // + FBehavior::StaticStartTypedScripts(SCRIPT_Respawn, mo, true); +} + +DEFINE_ACTION_FUNCTION(_PlayerInfo, Resurrect) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + ACTION_RETURN_BOOL(self->Resurrect()); +} + + DEFINE_ACTION_FUNCTION(_PlayerInfo, GetUserName) { PARAM_SELF_STRUCT_PROLOGUE(player_t); diff --git a/src/polyrenderer/drawers/poly_draw_args.cpp b/src/polyrenderer/drawers/poly_draw_args.cpp index eaa812dc9..4c526d1ef 100644 --- a/src/polyrenderer/drawers/poly_draw_args.cpp +++ b/src/polyrenderer/drawers/poly_draw_args.cpp @@ -45,6 +45,14 @@ void PolyDrawArgs::SetClipPlane(const PolyClipPlane &plane) mClipPlane[3] = plane.D; } +void PolyDrawArgs::SetTexture(const uint8_t *texels, int width, int height) +{ + mTexturePixels = texels; + mTextureWidth = width; + mTextureHeight = height; + mTranslation = nullptr; +} + void PolyDrawArgs::SetTexture(FTexture *texture) { mTextureWidth = texture->GetWidth(); @@ -132,3 +140,214 @@ void PolyDrawArgs::DrawArray(const TriVertex *vertices, int vcount, PolyDrawMode mDrawMode = mode; PolyRenderer::Instance()->DrawQueue->Push(*this, PolyTriangleDrawer::is_mirror()); } + +void PolyDrawArgs::SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FTexture *tex, bool fullbright) +{ + bool forcePal = (renderstyle == LegacyRenderStyles[STYLE_Shaded] || renderstyle == LegacyRenderStyles[STYLE_AddShaded]); + SetTexture(tex, translationID, forcePal); + + if (renderstyle == LegacyRenderStyles[STYLE_Normal] || (r_drawfuzz == 0 && renderstyle == LegacyRenderStyles[STYLE_OptFuzzy])) + { + SetStyle(Translation() ? TriBlendMode::TranslatedAdd : TriBlendMode::TextureAdd, 1.0, 0.0); + } + else if (renderstyle == LegacyRenderStyles[STYLE_Add] && fullbright && alpha == 1.0 && !Translation()) + { + SetStyle(TriBlendMode::TextureAddSrcColor, 1.0, 1.0); + } + else if (renderstyle == LegacyRenderStyles[STYLE_Add]) + { + SetStyle(Translation() ? TriBlendMode::TranslatedAdd : TriBlendMode::TextureAdd, alpha, 1.0); + } + else if (renderstyle == LegacyRenderStyles[STYLE_Subtract]) + { + SetStyle(Translation() ? TriBlendMode::TranslatedRevSub : TriBlendMode::TextureRevSub, alpha, 1.0); + } + else if (renderstyle == LegacyRenderStyles[STYLE_SoulTrans]) + { + SetStyle(Translation() ? TriBlendMode::TranslatedAdd : TriBlendMode::TextureAdd, transsouls, 1.0 - transsouls); + } + else if (renderstyle == LegacyRenderStyles[STYLE_Fuzzy] || (r_drawfuzz == 2 && renderstyle == LegacyRenderStyles[STYLE_OptFuzzy])) + { // NYI - Fuzzy - for now, just a copy of "Shadow" + SetStyle(Translation() ? TriBlendMode::TranslatedAdd : TriBlendMode::TextureAdd, 0.0, 160 / 255.0); + } + else if (renderstyle == LegacyRenderStyles[STYLE_Shadow] || (r_drawfuzz == 1 && renderstyle == LegacyRenderStyles[STYLE_OptFuzzy])) + { + SetStyle(Translation() ? TriBlendMode::TranslatedAdd : TriBlendMode::TextureAdd, 0.0, 160 / 255.0); + } + else if (renderstyle == LegacyRenderStyles[STYLE_TranslucentStencil]) + { + SetColor(0xff000000 | fillcolor, fillcolor >> 24); + SetStyle(TriBlendMode::Stencil, alpha, 1.0 - alpha); + } + else if (renderstyle == LegacyRenderStyles[STYLE_AddStencil]) + { + SetColor(0xff000000 | fillcolor, fillcolor >> 24); + SetStyle(TriBlendMode::AddStencil, alpha, 1.0); + } + else if (renderstyle == LegacyRenderStyles[STYLE_Shaded]) + { + SetColor(0xff000000 | fillcolor, fillcolor >> 24); + SetStyle(TriBlendMode::Shaded, alpha, 1.0 - alpha); + } + else if (renderstyle == LegacyRenderStyles[STYLE_AddShaded]) + { + SetColor(0xff000000 | fillcolor, fillcolor >> 24); + SetStyle(TriBlendMode::AddShaded, alpha, 1.0); + } + else + { + SetStyle(Translation() ? TriBlendMode::TranslatedAdd : TriBlendMode::TextureAdd, alpha, 1.0 - alpha); + } +} + +///////////////////////////////////////////////////////////////////////////// + +void RectDrawArgs::SetTexture(const uint8_t *texels, int width, int height) +{ + mTexturePixels = texels; + mTextureWidth = width; + mTextureHeight = height; + mTranslation = nullptr; +} + +void RectDrawArgs::SetTexture(FTexture *texture) +{ + mTextureWidth = texture->GetWidth(); + mTextureHeight = texture->GetHeight(); + if (PolyRenderer::Instance()->RenderTarget->IsBgra()) + mTexturePixels = (const uint8_t *)texture->GetPixelsBgra(); + else + mTexturePixels = texture->GetPixels(); + mTranslation = nullptr; +} + +void RectDrawArgs::SetTexture(FTexture *texture, uint32_t translationID, bool forcePal) +{ + if (translationID != 0xffffffff && translationID != 0) + { + FRemapTable *table = TranslationToTable(translationID); + if (table != nullptr && !table->Inactive) + { + if (PolyRenderer::Instance()->RenderTarget->IsBgra()) + mTranslation = (uint8_t*)table->Palette; + else + mTranslation = table->Remap; + + mTextureWidth = texture->GetWidth(); + mTextureHeight = texture->GetHeight(); + mTexturePixels = texture->GetPixels(); + return; + } + } + + if (forcePal) + { + mTextureWidth = texture->GetWidth(); + mTextureHeight = texture->GetHeight(); + mTexturePixels = texture->GetPixels(); + } + else + { + SetTexture(texture); + } +} + +void RectDrawArgs::SetLight(FSWColormap *base_colormap, uint32_t lightlevel) +{ + mLight = clamp(lightlevel, 0, 255); + mLightRed = base_colormap->Color.r * 256 / 255; + mLightGreen = base_colormap->Color.g * 256 / 255; + mLightBlue = base_colormap->Color.b * 256 / 255; + mLightAlpha = base_colormap->Color.a * 256 / 255; + mFadeRed = base_colormap->Fade.r; + mFadeGreen = base_colormap->Fade.g; + mFadeBlue = base_colormap->Fade.b; + mFadeAlpha = base_colormap->Fade.a; + mDesaturate = MIN(abs(base_colormap->Desaturate), 255) * 255 / 256; + mSimpleShade = (base_colormap->Color.d == 0x00ffffff && base_colormap->Fade.d == 0x00000000 && base_colormap->Desaturate == 0); + mColormaps = base_colormap->Maps; +} + +void RectDrawArgs::SetColor(uint32_t bgra, uint8_t palindex) +{ + if (PolyRenderer::Instance()->RenderTarget->IsBgra()) + { + mColor = bgra; + } + else + { + mColor = palindex; + } +} + +void RectDrawArgs::Draw(double x0, double x1, double y0, double y1, double u0, double u1, double v0, double v1) +{ + mX0 = (float)x0; + mX1 = (float)x1; + mY0 = (float)y0; + mY1 = (float)y1; + mU0 = (float)u0; + mU1 = (float)u1; + mV0 = (float)v0; + mV1 = (float)v1; + PolyRenderer::Instance()->DrawQueue->Push(*this); +} + +void RectDrawArgs::SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FTexture *tex, bool fullbright) +{ + bool forcePal = (renderstyle == LegacyRenderStyles[STYLE_Shaded] || renderstyle == LegacyRenderStyles[STYLE_AddShaded]); + SetTexture(tex, translationID, forcePal); + + if (renderstyle == LegacyRenderStyles[STYLE_Normal] || (r_drawfuzz == 0 && renderstyle == LegacyRenderStyles[STYLE_OptFuzzy])) + { + SetStyle(Translation() ? TriBlendMode::TranslatedAdd : TriBlendMode::TextureAdd, 1.0, 0.0); + } + else if (renderstyle == LegacyRenderStyles[STYLE_Add] && fullbright && alpha == 1.0 && !Translation()) + { + SetStyle(TriBlendMode::TextureAddSrcColor, 1.0, 1.0); + } + else if (renderstyle == LegacyRenderStyles[STYLE_Add]) + { + SetStyle(Translation() ? TriBlendMode::TranslatedAdd : TriBlendMode::TextureAdd, alpha, 1.0); + } + else if (renderstyle == LegacyRenderStyles[STYLE_Subtract]) + { + SetStyle(Translation() ? TriBlendMode::TranslatedRevSub : TriBlendMode::TextureRevSub, alpha, 1.0); + } + else if (renderstyle == LegacyRenderStyles[STYLE_SoulTrans]) + { + SetStyle(Translation() ? TriBlendMode::TranslatedAdd : TriBlendMode::TextureAdd, transsouls, 1.0 - transsouls); + } + else if (renderstyle == LegacyRenderStyles[STYLE_Fuzzy] || (r_drawfuzz == 2 && renderstyle == LegacyRenderStyles[STYLE_OptFuzzy])) + { // NYI - Fuzzy - for now, just a copy of "Shadow" + SetStyle(Translation() ? TriBlendMode::TranslatedAdd : TriBlendMode::TextureAdd, 0.0, 160 / 255.0); + } + else if (renderstyle == LegacyRenderStyles[STYLE_Shadow] || (r_drawfuzz == 1 && renderstyle == LegacyRenderStyles[STYLE_OptFuzzy])) + { + SetStyle(Translation() ? TriBlendMode::TranslatedAdd : TriBlendMode::TextureAdd, 0.0, 160 / 255.0); + } + else if (renderstyle == LegacyRenderStyles[STYLE_TranslucentStencil]) + { + SetColor(0xff000000 | fillcolor, fillcolor >> 24); + SetStyle(TriBlendMode::Stencil, alpha, 1.0 - alpha); + } + else if (renderstyle == LegacyRenderStyles[STYLE_AddStencil]) + { + SetColor(0xff000000 | fillcolor, fillcolor >> 24); + SetStyle(TriBlendMode::AddStencil, alpha, 1.0); + } + else if (renderstyle == LegacyRenderStyles[STYLE_Shaded]) + { + SetColor(0xff000000 | fillcolor, fillcolor >> 24); + SetStyle(TriBlendMode::Shaded, alpha, 1.0 - alpha); + } + else if (renderstyle == LegacyRenderStyles[STYLE_AddShaded]) + { + SetColor(0xff000000 | fillcolor, fillcolor >> 24); + SetStyle(TriBlendMode::AddShaded, alpha, 1.0); + } + else + { + SetStyle(Translation() ? TriBlendMode::TranslatedAdd : TriBlendMode::TextureAdd, alpha, 1.0 - alpha); + } +} diff --git a/src/polyrenderer/drawers/poly_draw_args.h b/src/polyrenderer/drawers/poly_draw_args.h index 20c73ec58..c90aaadd0 100644 --- a/src/polyrenderer/drawers/poly_draw_args.h +++ b/src/polyrenderer/drawers/poly_draw_args.h @@ -49,6 +49,7 @@ class PolyDrawArgs { public: void SetClipPlane(const PolyClipPlane &plane); + void SetTexture(const uint8_t *texels, int width, int height); void SetTexture(FTexture *texture); void SetTexture(FTexture *texture, uint32_t translationID, bool forcePal = false); void SetLight(FSWColormap *basecolormap, uint32_t lightlevel, double globVis, bool fixed); @@ -60,6 +61,7 @@ public: void SetWriteSubsectorDepth(bool enable) { mWriteSubsector = enable; } void SetFaceCullCCW(bool counterclockwise) { mFaceCullCCW = counterclockwise; } void SetStyle(TriBlendMode blendmode, double srcalpha = 1.0, double destalpha = 1.0) { mBlendMode = blendmode; mSrcAlpha = (uint32_t)(srcalpha * 256.0 + 0.5); mDestAlpha = (uint32_t)(destalpha * 256.0 + 0.5); } + void SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FTexture *texture, bool fullbright); void SetTransform(const TriMatrix *objectToClip) { mObjectToClip = objectToClip; } void SetColor(uint32_t bgra, uint8_t palindex); void DrawArray(const TriVertex *vertices, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles); @@ -127,7 +129,7 @@ private: uint8_t mStencilWriteValue = 0; const uint8_t *mColormaps = nullptr; float mClipPlane[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; - TriBlendMode mBlendMode = TriBlendMode::Copy; + TriBlendMode mBlendMode = TriBlendMode::FillOpaque; uint32_t mLight = 0; uint32_t mSubsectorDepth = 0; uint32_t mColor = 0; @@ -147,3 +149,71 @@ private: bool mNearestFilter = true; bool mFixedLight = false; }; + +class RectDrawArgs +{ +public: + void SetTexture(const uint8_t *texels, int width, int height); + void SetTexture(FTexture *texture); + void SetTexture(FTexture *texture, uint32_t translationID, bool forcePal = false); + void SetLight(FSWColormap *basecolormap, uint32_t lightlevel); + void SetStyle(TriBlendMode blendmode, double srcalpha = 1.0, double destalpha = 1.0) { mBlendMode = blendmode; mSrcAlpha = (uint32_t)(srcalpha * 256.0 + 0.5); mDestAlpha = (uint32_t)(destalpha * 256.0 + 0.5); } + void SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FTexture *texture, bool fullbright); + void SetColor(uint32_t bgra, uint8_t palindex); + void Draw(double x0, double x1, double y0, double y1, double u0, double u1, double v0, double v1); + + const uint8_t *TexturePixels() const { return mTexturePixels; } + int TextureWidth() const { return mTextureWidth; } + int TextureHeight() const { return mTextureHeight; } + const uint8_t *Translation() const { return mTranslation; } + + TriBlendMode BlendMode() const { return mBlendMode; } + uint32_t Color() const { return mColor; } + uint32_t SrcAlpha() const { return mSrcAlpha; } + uint32_t DestAlpha() const { return mDestAlpha; } + + uint32_t Light() const { return mLight; } + const uint8_t *BaseColormap() const { return mColormaps; } + uint16_t ShadeLightAlpha() const { return mLightAlpha; } + uint16_t ShadeLightRed() const { return mLightRed; } + uint16_t ShadeLightGreen() const { return mLightGreen; } + uint16_t ShadeLightBlue() const { return mLightBlue; } + uint16_t ShadeFadeAlpha() const { return mFadeAlpha; } + uint16_t ShadeFadeRed() const { return mFadeRed; } + uint16_t ShadeFadeGreen() const { return mFadeGreen; } + uint16_t ShadeFadeBlue() const { return mFadeBlue; } + uint16_t ShadeDesaturate() const { return mDesaturate; } + bool SimpleShade() const { return mSimpleShade; } + + float X0() const { return mX0; } + float X1() const { return mX1; } + float Y0() const { return mY0; } + float Y1() const { return mY1; } + float U0() const { return mU0; } + float U1() const { return mU1; } + float V0() const { return mV0; } + float V1() const { return mV1; } + +private: + const uint8_t *mTexturePixels = nullptr; + int mTextureWidth = 0; + int mTextureHeight = 0; + const uint8_t *mTranslation = nullptr; + const uint8_t *mColormaps = nullptr; + TriBlendMode mBlendMode = TriBlendMode::FillOpaque; + uint32_t mLight = 0; + uint32_t mColor = 0; + uint32_t mSrcAlpha = 0; + uint32_t mDestAlpha = 0; + uint16_t mLightAlpha = 0; + uint16_t mLightRed = 0; + uint16_t mLightGreen = 0; + uint16_t mLightBlue = 0; + uint16_t mFadeAlpha = 0; + uint16_t mFadeRed = 0; + uint16_t mFadeGreen = 0; + uint16_t mFadeBlue = 0; + uint16_t mDesaturate = 0; + bool mSimpleShade = true; + float mX0, mX1, mY0, mY1, mU0, mU1, mV0, mV1; +}; diff --git a/src/polyrenderer/drawers/poly_drawer32_sse2.h b/src/polyrenderer/drawers/poly_drawer32_sse2.h index a3568b6c1..bb94632bc 100644 --- a/src/polyrenderer/drawers/poly_drawer32_sse2.h +++ b/src/polyrenderer/drawers/poly_drawer32_sse2.h @@ -24,436 +24,13 @@ #include "screen_triangle.h" -template -class TriScreenDrawer32 +namespace TriScreenDrawerModes { -public: - static void Execute(const TriDrawTriangleArgs *args, WorkerThreadData *thread) + template + FORCEINLINE unsigned int VECTORCALL Sample32(int32_t u, int32_t v, const uint32_t *texPixels, int texWidth, int texHeight, uint32_t oneU, uint32_t oneV, uint32_t color, const uint32_t *translation) { - using namespace TriScreenDrawerModes; - - bool is_simple_shade = args->uniforms->SimpleShade(); - - if (SamplerT::Mode == (int)Samplers::Texture) - { - bool is_nearest_filter = args->uniforms->NearestFilter(); - - if (is_simple_shade) - { - if (is_nearest_filter) - Loop(args, thread); - else - Loop(args, thread); - } - else - { - if (is_nearest_filter) - Loop(args, thread); - else - Loop(args, thread); - } - } - else // no linear filtering for translated, shaded, fill or skycap - { - if (is_simple_shade) - { - Loop(args, thread); - } - else - { - Loop(args, thread); - } - } - } - - template - FORCEINLINE static void VECTORCALL Loop(const TriDrawTriangleArgs *args, WorkerThreadData *thread) - { - using namespace TriScreenDrawerModes; - - int numSpans = thread->NumFullSpans; - auto fullSpans = thread->FullSpans; - int numBlocks = thread->NumPartialBlocks; - auto partialBlocks = thread->PartialBlocks; - int startX = thread->StartX; - int startY = thread->StartY; - - bool is_fixed_light = args->uniforms->FixedLight(); - uint32_t lightmask = is_fixed_light ? 0 : 0xffffffff; - uint32_t srcalpha = args->uniforms->SrcAlpha(); - uint32_t destalpha = args->uniforms->DestAlpha(); - - // Calculate gradients - const TriVertex &v1 = *args->v1; - const TriVertex &v2 = *args->v2; - const TriVertex &v3 = *args->v3; - ScreenTriangleStepVariables gradientX; - ScreenTriangleStepVariables gradientY; - ScreenTriangleStepVariables start; - gradientX.W = FindGradientX(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.w, v2.w, v3.w); - gradientY.W = FindGradientY(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.w, v2.w, v3.w); - start.W = v1.w + gradientX.W * (startX - v1.x) + gradientY.W * (startY - v1.y); - for (int i = 0; i < TriVertex::NumVarying; i++) - { - gradientX.Varying[i] = FindGradientX(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.varying[i] * v1.w, v2.varying[i] * v2.w, v3.varying[i] * v3.w); - gradientY.Varying[i] = FindGradientY(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.varying[i] * v1.w, v2.varying[i] * v2.w, v3.varying[i] * v3.w); - start.Varying[i] = v1.varying[i] * v1.w + gradientX.Varying[i] * (startX - v1.x) + gradientY.Varying[i] * (startY - v1.y); - } - - // Output - uint32_t * RESTRICT destOrg = (uint32_t*)args->dest; - int pitch = args->pitch; - - // Light - uint32_t light = args->uniforms->Light(); - float shade = 2.0f - (light + 12.0f) / 128.0f; - float globVis = args->uniforms->GlobVis() * (1.0f / 32.0f); - light += (light >> 7); // 255 -> 256 - - // Sampling stuff - uint32_t color = args->uniforms->Color(); - const uint32_t * RESTRICT translation = (const uint32_t *)args->uniforms->Translation(); - const uint32_t * RESTRICT texPixels = (const uint32_t *)args->uniforms->TexturePixels(); - uint32_t texWidth = args->uniforms->TextureWidth(); - uint32_t texHeight = args->uniforms->TextureHeight(); - uint32_t oneU, oneV; - if (SamplerT::Mode != (int)Samplers::Fill) - { - oneU = ((0x800000 + texWidth - 1) / texWidth) * 2 + 1; - oneV = ((0x800000 + texHeight - 1) / texHeight) * 2 + 1; - } - else - { - oneU = 0; - oneV = 0; - } - - // Shade constants - __m128i inv_desaturate, shade_fade, shade_light; - int desaturate; - if (ShadeModeT::Mode == (int)ShadeMode::Advanced) - { - inv_desaturate = _mm_setr_epi16(256, 256 - args->uniforms->ShadeDesaturate(), 256 - args->uniforms->ShadeDesaturate(), 256 - args->uniforms->ShadeDesaturate(), 256, 256 - args->uniforms->ShadeDesaturate(), 256 - args->uniforms->ShadeDesaturate(), 256 - args->uniforms->ShadeDesaturate()); - shade_fade = _mm_set_epi16(args->uniforms->ShadeFadeAlpha(), args->uniforms->ShadeFadeRed(), args->uniforms->ShadeFadeGreen(), args->uniforms->ShadeFadeBlue(), args->uniforms->ShadeFadeAlpha(), args->uniforms->ShadeFadeRed(), args->uniforms->ShadeFadeGreen(), args->uniforms->ShadeFadeBlue()); - shade_light = _mm_set_epi16(args->uniforms->ShadeLightAlpha(), args->uniforms->ShadeLightRed(), args->uniforms->ShadeLightGreen(), args->uniforms->ShadeLightBlue(), args->uniforms->ShadeLightAlpha(), args->uniforms->ShadeLightRed(), args->uniforms->ShadeLightGreen(), args->uniforms->ShadeLightBlue()); - desaturate = args->uniforms->ShadeDesaturate(); - } - else - { - inv_desaturate = _mm_setzero_si128(); - shade_fade = _mm_setzero_si128(); - shade_fade = _mm_setzero_si128(); - shade_light = _mm_setzero_si128(); - desaturate = 0; - } - - for (int i = 0; i < numSpans; i++) - { - const auto &span = fullSpans[i]; - - uint32_t *dest = destOrg + span.X + span.Y * pitch; - int width = span.Length; - int height = 8; - - ScreenTriangleStepVariables blockPosY; - blockPosY.W = start.W + gradientX.W * (span.X - startX) + gradientY.W * (span.Y - startY); - for (int j = 0; j < TriVertex::NumVarying; j++) - blockPosY.Varying[j] = start.Varying[j] + gradientX.Varying[j] * (span.X - startX) + gradientY.Varying[j] * (span.Y - startY); - - for (int y = 0; y < height; y++) - { - ScreenTriangleStepVariables blockPosX = blockPosY; - - float rcpW = 0x01000000 / blockPosX.W; - int32_t varyingPos[TriVertex::NumVarying]; - for (int j = 0; j < TriVertex::NumVarying; j++) - varyingPos[j] = (int32_t)(blockPosX.Varying[j] * rcpW); - - fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); - - for (int x = 0; x < width; x++) - { - blockPosX.W += gradientX.W * 8; - for (int j = 0; j < TriVertex::NumVarying; j++) - blockPosX.Varying[j] += gradientX.Varying[j] * 8; - - rcpW = 0x01000000 / blockPosX.W; - int32_t varyingStep[TriVertex::NumVarying]; - for (int j = 0; j < TriVertex::NumVarying; j++) - { - int32_t nextPos = (int32_t)(blockPosX.Varying[j] * rcpW); - varyingStep[j] = (nextPos - varyingPos[j]) / 8; - } - - fixed_t lightnext = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosX.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - fixed_t lightstep = (lightnext - lightpos) / 8; - lightstep = lightstep & lightmask; - - for (int ix = 0; ix < 4; ix++) - { - // Load bgcolor - __m128i bgcolor; - if (BlendT::Mode != (int)BlendModes::Opaque) - bgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)(dest + x * 8 + ix * 2)), _mm_setzero_si128()); - else - bgcolor = _mm_setzero_si128(); - - // Sample fgcolor - unsigned int ifgcolor[2], ifgshade[2]; - ifgcolor[0] = Sample(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight, oneU, oneV, color, translation); - ifgshade[0] = SampleShade(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight); - for (int j = 0; j < TriVertex::NumVarying; j++) - varyingPos[j] += varyingStep[j]; - - ifgcolor[1] = Sample(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight, oneU, oneV, color, translation); - ifgshade[1] = SampleShade(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight); - for (int j = 0; j < TriVertex::NumVarying; j++) - varyingPos[j] += varyingStep[j]; - - // Setup light - int lightpos0 = lightpos >> 8; - lightpos += lightstep; - int lightpos1 = lightpos >> 8; - lightpos += lightstep; - __m128i mlight = _mm_set_epi16(256, lightpos1, lightpos1, lightpos1, 256, lightpos0, lightpos0, lightpos0); - - __m128i shade_fade_lit; - if (ShadeModeT::Mode == (int)ShadeMode::Advanced) - { - __m128i inv_light = _mm_sub_epi16(_mm_set_epi16(0, 256, 256, 256, 0, 256, 256, 256), mlight); - shade_fade_lit = _mm_mullo_epi16(shade_fade, inv_light); - } - else - { - shade_fade_lit = _mm_setzero_si128(); - } - - // Shade and blend - __m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128()); - fgcolor = Shade(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light); - __m128i outcolor = Blend(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha); - - // Store result - _mm_storel_epi64((__m128i*)(dest + x * 8 + ix * 2), outcolor); - } - } - - blockPosY.W += gradientY.W; - for (int j = 0; j < TriVertex::NumVarying; j++) - blockPosY.Varying[j] += gradientY.Varying[j]; - - dest += pitch; - } - } - - for (int i = 0; i < numBlocks; i++) - { - const auto &block = partialBlocks[i]; - - ScreenTriangleStepVariables blockPosY; - blockPosY.W = start.W + gradientX.W * (block.X - startX) + gradientY.W * (block.Y - startY); - for (int j = 0; j < TriVertex::NumVarying; j++) - blockPosY.Varying[j] = start.Varying[j] + gradientX.Varying[j] * (block.X - startX) + gradientY.Varying[j] * (block.Y - startY); - - uint32_t *dest = destOrg + block.X + block.Y * pitch; - uint32_t mask0 = block.Mask0; - uint32_t mask1 = block.Mask1; - - // mask0 loop: - for (int y = 0; y < 4; y++) - { - ScreenTriangleStepVariables blockPosX = blockPosY; - - float rcpW = 0x01000000 / blockPosX.W; - int32_t varyingPos[TriVertex::NumVarying]; - for (int j = 0; j < TriVertex::NumVarying; j++) - varyingPos[j] = (int32_t)(blockPosX.Varying[j] * rcpW); - - fixed_t lightpos = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); - - blockPosX.W += gradientX.W * 8; - for (int j = 0; j < TriVertex::NumVarying; j++) - blockPosX.Varying[j] += gradientX.Varying[j] * 8; - - rcpW = 0x01000000 / blockPosX.W; - int32_t varyingStep[TriVertex::NumVarying]; - for (int j = 0; j < TriVertex::NumVarying; j++) - { - int32_t nextPos = (int32_t)(blockPosX.Varying[j] * rcpW); - varyingStep[j] = (nextPos - varyingPos[j]) / 8; - } - - fixed_t lightnext = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosX.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - fixed_t lightstep = (lightnext - lightpos) / 8; - lightstep = lightstep & lightmask; - - for (int x = 0; x < 4; x++) - { - // Load bgcolor - uint32_t desttmp[2]; - if (mask0 & (1 << 31)) desttmp[0] = dest[x * 2]; - if (mask0 & (1 << 30)) desttmp[1] = dest[x * 2 + 1]; - - __m128i bgcolor; - if (BlendT::Mode != (int)BlendModes::Opaque) - bgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)desttmp), _mm_setzero_si128()); - else - bgcolor = _mm_setzero_si128(); - - // Sample fgcolor - unsigned int ifgcolor[2], ifgshade[2]; - ifgcolor[0] = Sample(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight, oneU, oneV, color, translation); - ifgshade[0] = SampleShade(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight); - for (int j = 0; j < TriVertex::NumVarying; j++) - varyingPos[j] += varyingStep[j]; - - ifgcolor[1] = Sample(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight, oneU, oneV, color, translation); - ifgshade[1] = SampleShade(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight); - for (int j = 0; j < TriVertex::NumVarying; j++) - varyingPos[j] += varyingStep[j]; - - // Setup light - int lightpos0 = lightpos >> 8; - lightpos += lightstep; - int lightpos1 = lightpos >> 8; - lightpos += lightstep; - __m128i mlight = _mm_set_epi16(256, lightpos1, lightpos1, lightpos1, 256, lightpos0, lightpos0, lightpos0); - - __m128i shade_fade_lit; - if (ShadeModeT::Mode == (int)ShadeMode::Advanced) - { - __m128i inv_light = _mm_sub_epi16(_mm_set_epi16(0, 256, 256, 256, 0, 256, 256, 256), mlight); - shade_fade_lit = _mm_mullo_epi16(shade_fade, inv_light); - } - else - { - shade_fade_lit = _mm_setzero_si128(); - } - - // Shade and blend - __m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128()); - fgcolor = Shade(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light); - __m128i outcolor = Blend(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha); - - // Store result - _mm_storel_epi64((__m128i*)desttmp, outcolor); - if (mask0 & (1 << 31)) dest[x * 2] = desttmp[0]; - if (mask0 & (1 << 30)) dest[x * 2 + 1] = desttmp[1]; - - mask0 <<= 2; - } - - blockPosY.W += gradientY.W; - for (int j = 0; j < TriVertex::NumVarying; j++) - blockPosY.Varying[j] += gradientY.Varying[j]; - - dest += pitch; - } - - // mask1 loop: - for (int y = 0; y < 4; y++) - { - ScreenTriangleStepVariables blockPosX = blockPosY; - - float rcpW = 0x01000000 / blockPosX.W; - int32_t varyingPos[TriVertex::NumVarying]; - for (int j = 0; j < TriVertex::NumVarying; j++) - varyingPos[j] = (int32_t)(blockPosX.Varying[j] * rcpW); - - fixed_t lightpos = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); - - blockPosX.W += gradientX.W * 8; - for (int j = 0; j < TriVertex::NumVarying; j++) - blockPosX.Varying[j] += gradientX.Varying[j] * 8; - - rcpW = 0x01000000 / blockPosX.W; - int32_t varyingStep[TriVertex::NumVarying]; - for (int j = 0; j < TriVertex::NumVarying; j++) - { - int32_t nextPos = (int32_t)(blockPosX.Varying[j] * rcpW); - varyingStep[j] = (nextPos - varyingPos[j]) / 8; - } - - fixed_t lightnext = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosX.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - fixed_t lightstep = (lightnext - lightpos) / 8; - lightstep = lightstep & lightmask; - - for (int x = 0; x < 4; x++) - { - // Load bgcolor - uint32_t desttmp[2]; - if (mask1 & (1 << 31)) desttmp[0] = dest[x * 2]; - if (mask1 & (1 << 30)) desttmp[1] = dest[x * 2 + 1]; - - __m128i bgcolor; - if (BlendT::Mode != (int)BlendModes::Opaque) - bgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)desttmp), _mm_setzero_si128()); - else - bgcolor = _mm_setzero_si128(); - - // Sample fgcolor - unsigned int ifgcolor[2], ifgshade[2]; - ifgcolor[0] = Sample(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight, oneU, oneV, color, translation); - ifgshade[0] = SampleShade(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight); - for (int j = 0; j < TriVertex::NumVarying; j++) - varyingPos[j] += varyingStep[j]; - - ifgcolor[1] = Sample(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight, oneU, oneV, color, translation); - ifgshade[1] = SampleShade(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight); - for (int j = 0; j < TriVertex::NumVarying; j++) - varyingPos[j] += varyingStep[j]; - - // Setup light - int lightpos0 = lightpos >> 8; - lightpos += lightstep; - int lightpos1 = lightpos >> 8; - lightpos += lightstep; - __m128i mlight = _mm_set_epi16(256, lightpos1, lightpos1, lightpos1, 256, lightpos0, lightpos0, lightpos0); - - __m128i shade_fade_lit; - if (ShadeModeT::Mode == (int)ShadeMode::Advanced) - { - __m128i inv_light = _mm_sub_epi16(_mm_set_epi16(0, 256, 256, 256, 0, 256, 256, 256), mlight); - shade_fade_lit = _mm_mullo_epi16(shade_fade, inv_light); - } - else - { - shade_fade_lit = _mm_setzero_si128(); - } - - // Shade and blend - __m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128()); - fgcolor = Shade(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light); - __m128i outcolor = Blend(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha); - - // Store result - _mm_storel_epi64((__m128i*)desttmp, outcolor); - if (mask1 & (1 << 31)) dest[x * 2] = desttmp[0]; - if (mask1 & (1 << 30)) dest[x * 2 + 1] = desttmp[1]; - - mask1 <<= 2; - } - - blockPosY.W += gradientY.W; - for (int j = 0; j < TriVertex::NumVarying; j++) - blockPosY.Varying[j] += gradientY.Varying[j]; - - dest += pitch; - } - } - } - -private: - template - FORCEINLINE static unsigned int VECTORCALL Sample(int32_t u, int32_t v, const uint32_t *texPixels, int texWidth, int texHeight, uint32_t oneU, uint32_t oneV, uint32_t color, const uint32_t *translation) - { - using namespace TriScreenDrawerModes; - uint32_t texel; - if (SamplerT::Mode == (int)Samplers::Shaded || SamplerT::Mode == (int)Samplers::Fill) + if (SamplerT::Mode == (int)Samplers::Shaded || SamplerT::Mode == (int)Samplers::Stencil || SamplerT::Mode == (int)Samplers::Fill) { return color; } @@ -529,10 +106,9 @@ private: } } - FORCEINLINE static unsigned int VECTORCALL SampleShade(int32_t u, int32_t v, const uint32_t *texPixels, int texWidth, int texHeight) + template + FORCEINLINE unsigned int VECTORCALL SampleShade32(int32_t u, int32_t v, const uint32_t *texPixels, int texWidth, int texHeight) { - using namespace TriScreenDrawerModes; - if (SamplerT::Mode == (int)Samplers::Shaded) { const uint8_t *texpal = (const uint8_t *)texPixels; @@ -542,6 +118,14 @@ private: sampleshadeout += sampleshadeout >> 7; // 255 -> 256 return sampleshadeout; } + else if (SamplerT::Mode == (int)Samplers::Stencil) + { + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + unsigned int sampleshadeout = APART(texPixels[texelX * texHeight + texelY]); + sampleshadeout += sampleshadeout >> 7; // 255 -> 256 + return sampleshadeout; + } else { return 0; @@ -549,10 +133,8 @@ private: } template - FORCEINLINE static __m128i VECTORCALL Shade(__m128i fgcolor, __m128i mlight, unsigned int ifgcolor0, unsigned int ifgcolor1, int desaturate, __m128i inv_desaturate, __m128i shade_fade, __m128i shade_light) + FORCEINLINE __m128i VECTORCALL Shade32(__m128i fgcolor, __m128i mlight, unsigned int ifgcolor0, unsigned int ifgcolor1, int desaturate, __m128i inv_desaturate, __m128i shade_fade, __m128i shade_light) { - using namespace TriScreenDrawerModes; - if (ShadeModeT::Mode == (int)ShadeMode::Simple) { fgcolor = _mm_srli_epi16(_mm_mullo_epi16(fgcolor, mlight), 8); @@ -579,10 +161,9 @@ private: return fgcolor; } - FORCEINLINE static __m128i VECTORCALL Blend(__m128i fgcolor, __m128i bgcolor, unsigned int ifgcolor0, unsigned int ifgcolor1, unsigned int ifgshade0, unsigned int ifgshade1, uint32_t srcalpha, uint32_t destalpha) + template + FORCEINLINE __m128i VECTORCALL Blend32(__m128i fgcolor, __m128i bgcolor, unsigned int ifgcolor0, unsigned int ifgcolor1, unsigned int ifgshade0, unsigned int ifgshade1, uint32_t srcalpha, uint32_t destalpha) { - using namespace TriScreenDrawerModes; - if (BlendT::Mode == (int)BlendModes::Opaque) { __m128i outcolor = fgcolor; @@ -621,6 +202,8 @@ private: } else if (BlendT::Mode == (int)BlendModes::AddClampShaded) { + ifgshade0 = (ifgshade0 * srcalpha + 128) >> 8; + ifgshade1 = (ifgshade1 * srcalpha + 128) >> 8; __m128i alpha = _mm_set_epi16(ifgshade1, ifgshade1, ifgshade1, ifgshade1, ifgshade0, ifgshade0, ifgshade0, ifgshade0); fgcolor = _mm_srli_epi16(_mm_mullo_epi16(fgcolor, alpha), 8); @@ -679,6 +262,421 @@ private: return outcolor; } } +} + +template +class TriScreenDrawer32 +{ +public: + static void Execute(const TriDrawTriangleArgs *args, WorkerThreadData *thread) + { + using namespace TriScreenDrawerModes; + + bool is_simple_shade = args->uniforms->SimpleShade(); + + if (SamplerT::Mode == (int)Samplers::Texture) + { + bool is_nearest_filter = args->uniforms->NearestFilter(); + + if (is_simple_shade) + { + if (is_nearest_filter) + Loop(args, thread); + else + Loop(args, thread); + } + else + { + if (is_nearest_filter) + Loop(args, thread); + else + Loop(args, thread); + } + } + else // no linear filtering for translated, shaded, stencil, fill or skycap + { + if (is_simple_shade) + { + Loop(args, thread); + } + else + { + Loop(args, thread); + } + } + } + +private: + template + FORCEINLINE static void VECTORCALL Loop(const TriDrawTriangleArgs *args, WorkerThreadData *thread) + { + using namespace TriScreenDrawerModes; + + int numSpans = thread->NumFullSpans; + auto fullSpans = thread->FullSpans; + int numBlocks = thread->NumPartialBlocks; + auto partialBlocks = thread->PartialBlocks; + int startX = thread->StartX; + int startY = thread->StartY; + + bool is_fixed_light = args->uniforms->FixedLight(); + uint32_t lightmask = is_fixed_light ? 0 : 0xffffffff; + uint32_t srcalpha = args->uniforms->SrcAlpha(); + uint32_t destalpha = args->uniforms->DestAlpha(); + + // Calculate gradients + const TriVertex &v1 = *args->v1; + const TriVertex &v2 = *args->v2; + const TriVertex &v3 = *args->v3; + ScreenTriangleStepVariables gradientX; + ScreenTriangleStepVariables gradientY; + ScreenTriangleStepVariables start; + gradientX.W = FindGradientX(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.w, v2.w, v3.w); + gradientY.W = FindGradientY(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.w, v2.w, v3.w); + gradientX.U = FindGradientX(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.u * v1.w, v2.u * v2.w, v3.u * v3.w); + gradientY.U = FindGradientY(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.u * v1.w, v2.u * v2.w, v3.u * v3.w); + gradientX.V = FindGradientX(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.v * v1.w, v2.v * v2.w, v3.v * v3.w); + gradientY.V = FindGradientY(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.v * v1.w, v2.v * v2.w, v3.v * v3.w); + start.W = v1.w + gradientX.W * (startX - v1.x) + gradientY.W * (startY - v1.y); + start.U = v1.u * v1.w + gradientX.U * (startX - v1.x) + gradientY.U * (startY - v1.y); + start.V = v1.v * v1.w + gradientX.V * (startX - v1.x) + gradientY.V * (startY - v1.y); + + // Output + uint32_t * RESTRICT destOrg = (uint32_t*)args->dest; + int pitch = args->pitch; + + // Light + uint32_t light = args->uniforms->Light(); + float shade = 2.0f - (light + 12.0f) / 128.0f; + float globVis = args->uniforms->GlobVis() * (1.0f / 32.0f); + light += (light >> 7); // 255 -> 256 + + // Sampling stuff + uint32_t color = args->uniforms->Color(); + const uint32_t * RESTRICT translation = (const uint32_t *)args->uniforms->Translation(); + const uint32_t * RESTRICT texPixels = (const uint32_t *)args->uniforms->TexturePixels(); + uint32_t texWidth = args->uniforms->TextureWidth(); + uint32_t texHeight = args->uniforms->TextureHeight(); + uint32_t oneU, oneV; + if (SamplerT::Mode != (int)Samplers::Fill) + { + oneU = ((0x800000 + texWidth - 1) / texWidth) * 2 + 1; + oneV = ((0x800000 + texHeight - 1) / texHeight) * 2 + 1; + } + else + { + oneU = 0; + oneV = 0; + } + + // Shade constants + __m128i inv_desaturate, shade_fade, shade_light; + int desaturate; + if (ShadeModeT::Mode == (int)ShadeMode::Advanced) + { + inv_desaturate = _mm_setr_epi16(256, 256 - args->uniforms->ShadeDesaturate(), 256 - args->uniforms->ShadeDesaturate(), 256 - args->uniforms->ShadeDesaturate(), 256, 256 - args->uniforms->ShadeDesaturate(), 256 - args->uniforms->ShadeDesaturate(), 256 - args->uniforms->ShadeDesaturate()); + shade_fade = _mm_set_epi16(args->uniforms->ShadeFadeAlpha(), args->uniforms->ShadeFadeRed(), args->uniforms->ShadeFadeGreen(), args->uniforms->ShadeFadeBlue(), args->uniforms->ShadeFadeAlpha(), args->uniforms->ShadeFadeRed(), args->uniforms->ShadeFadeGreen(), args->uniforms->ShadeFadeBlue()); + shade_light = _mm_set_epi16(args->uniforms->ShadeLightAlpha(), args->uniforms->ShadeLightRed(), args->uniforms->ShadeLightGreen(), args->uniforms->ShadeLightBlue(), args->uniforms->ShadeLightAlpha(), args->uniforms->ShadeLightRed(), args->uniforms->ShadeLightGreen(), args->uniforms->ShadeLightBlue()); + desaturate = args->uniforms->ShadeDesaturate(); + } + else + { + inv_desaturate = _mm_setzero_si128(); + shade_fade = _mm_setzero_si128(); + shade_fade = _mm_setzero_si128(); + shade_light = _mm_setzero_si128(); + desaturate = 0; + } + + for (int i = 0; i < numSpans; i++) + { + const auto &span = fullSpans[i]; + + uint32_t *dest = destOrg + span.X + span.Y * pitch; + int width = span.Length; + int height = 8; + + ScreenTriangleStepVariables blockPosY; + blockPosY.W = start.W + gradientX.W * (span.X - startX) + gradientY.W * (span.Y - startY); + blockPosY.U = start.U + gradientX.U * (span.X - startX) + gradientY.U * (span.Y - startY); + blockPosY.V = start.V + gradientX.V * (span.X - startX) + gradientY.V * (span.Y - startY); + + for (int y = 0; y < height; y++) + { + ScreenTriangleStepVariables blockPosX = blockPosY; + + float rcpW = 0x01000000 / blockPosX.W; + int32_t posU = (int32_t)(blockPosX.U * rcpW); + int32_t posV = (int32_t)(blockPosX.V * rcpW); + + fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + + for (int x = 0; x < width; x++) + { + blockPosX.W += gradientX.W * 8; + blockPosX.U += gradientX.U * 8; + blockPosX.V += gradientX.V * 8; + + rcpW = 0x01000000 / blockPosX.W; + int32_t nextU = (int32_t)(blockPosX.U * rcpW); + int32_t nextV = (int32_t)(blockPosX.V * rcpW); + int32_t stepU = (nextU - posU) / 8; + int32_t stepV = (nextV - posV) / 8; + + fixed_t lightnext = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosX.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + fixed_t lightstep = (lightnext - lightpos) / 8; + lightstep = lightstep & lightmask; + + for (int ix = 0; ix < 4; ix++) + { + // Load bgcolor + __m128i bgcolor; + if (BlendT::Mode != (int)BlendModes::Opaque) + bgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)(dest + x * 8 + ix * 2)), _mm_setzero_si128()); + else + bgcolor = _mm_setzero_si128(); + + // Sample fgcolor + unsigned int ifgcolor[2], ifgshade[2]; + ifgcolor[0] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); + ifgshade[0] = SampleShade32(posU, posV, texPixels, texWidth, texHeight); + posU += stepU; + posV += stepV; + + ifgcolor[1] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); + ifgshade[1] = SampleShade32(posU, posV, texPixels, texWidth, texHeight); + posU += stepU; + posV += stepV; + + // Setup light + int lightpos0 = lightpos >> 8; + lightpos += lightstep; + int lightpos1 = lightpos >> 8; + lightpos += lightstep; + __m128i mlight = _mm_set_epi16(256, lightpos1, lightpos1, lightpos1, 256, lightpos0, lightpos0, lightpos0); + + __m128i shade_fade_lit; + if (ShadeModeT::Mode == (int)ShadeMode::Advanced) + { + __m128i inv_light = _mm_sub_epi16(_mm_set_epi16(0, 256, 256, 256, 0, 256, 256, 256), mlight); + shade_fade_lit = _mm_mullo_epi16(shade_fade, inv_light); + } + else + { + shade_fade_lit = _mm_setzero_si128(); + } + + // Shade and blend + __m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128()); + fgcolor = Shade32(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light); + __m128i outcolor = Blend32(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha); + + // Store result + _mm_storel_epi64((__m128i*)(dest + x * 8 + ix * 2), outcolor); + } + } + + blockPosY.W += gradientY.W; + blockPosY.U += gradientY.U; + blockPosY.V += gradientY.V; + + dest += pitch; + } + } + + for (int i = 0; i < numBlocks; i++) + { + const auto &block = partialBlocks[i]; + + ScreenTriangleStepVariables blockPosY; + blockPosY.W = start.W + gradientX.W * (block.X - startX) + gradientY.W * (block.Y - startY); + blockPosY.U = start.U + gradientX.U * (block.X - startX) + gradientY.U * (block.Y - startY); + blockPosY.V = start.V + gradientX.V * (block.X - startX) + gradientY.V * (block.Y - startY); + + uint32_t *dest = destOrg + block.X + block.Y * pitch; + uint32_t mask0 = block.Mask0; + uint32_t mask1 = block.Mask1; + + // mask0 loop: + for (int y = 0; y < 4; y++) + { + ScreenTriangleStepVariables blockPosX = blockPosY; + + float rcpW = 0x01000000 / blockPosX.W; + int32_t posU = (int32_t)(blockPosX.U * rcpW); + int32_t posV = (int32_t)(blockPosX.V * rcpW); + + fixed_t lightpos = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + + blockPosX.W += gradientX.W * 8; + blockPosX.U += gradientX.U * 8; + blockPosX.V += gradientX.V * 8; + + rcpW = 0x01000000 / blockPosX.W; + int32_t nextU = (int32_t)(blockPosX.U * rcpW); + int32_t nextV = (int32_t)(blockPosX.V * rcpW); + int32_t stepU = (nextU - posU) / 8; + int32_t stepV = (nextV - posV) / 8; + + fixed_t lightnext = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosX.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + fixed_t lightstep = (lightnext - lightpos) / 8; + lightstep = lightstep & lightmask; + + for (int x = 0; x < 4; x++) + { + // Load bgcolor + uint32_t desttmp[2]; + if (mask0 & (1 << 31)) desttmp[0] = dest[x * 2]; + if (mask0 & (1 << 30)) desttmp[1] = dest[x * 2 + 1]; + + __m128i bgcolor; + if (BlendT::Mode != (int)BlendModes::Opaque) + bgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)desttmp), _mm_setzero_si128()); + else + bgcolor = _mm_setzero_si128(); + + // Sample fgcolor + unsigned int ifgcolor[2], ifgshade[2]; + ifgcolor[0] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); + ifgshade[0] = SampleShade32(posU, posV, texPixels, texWidth, texHeight); + posU += stepU; + posV += stepV; + + ifgcolor[1] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); + ifgshade[1] = SampleShade32(posU, posV, texPixels, texWidth, texHeight); + posU += stepU; + posV += stepV; + + // Setup light + int lightpos0 = lightpos >> 8; + lightpos += lightstep; + int lightpos1 = lightpos >> 8; + lightpos += lightstep; + __m128i mlight = _mm_set_epi16(256, lightpos1, lightpos1, lightpos1, 256, lightpos0, lightpos0, lightpos0); + + __m128i shade_fade_lit; + if (ShadeModeT::Mode == (int)ShadeMode::Advanced) + { + __m128i inv_light = _mm_sub_epi16(_mm_set_epi16(0, 256, 256, 256, 0, 256, 256, 256), mlight); + shade_fade_lit = _mm_mullo_epi16(shade_fade, inv_light); + } + else + { + shade_fade_lit = _mm_setzero_si128(); + } + + // Shade and blend + __m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128()); + fgcolor = Shade32(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light); + __m128i outcolor = Blend32(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha); + + // Store result + _mm_storel_epi64((__m128i*)desttmp, outcolor); + if (mask0 & (1 << 31)) dest[x * 2] = desttmp[0]; + if (mask0 & (1 << 30)) dest[x * 2 + 1] = desttmp[1]; + + mask0 <<= 2; + } + + blockPosY.W += gradientY.W; + blockPosY.U += gradientY.U; + blockPosY.V += gradientY.V; + + dest += pitch; + } + + // mask1 loop: + for (int y = 0; y < 4; y++) + { + ScreenTriangleStepVariables blockPosX = blockPosY; + + float rcpW = 0x01000000 / blockPosX.W; + int32_t posU = (int32_t)(blockPosX.U * rcpW); + int32_t posV = (int32_t)(blockPosX.V * rcpW); + + fixed_t lightpos = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + + blockPosX.W += gradientX.W * 8; + blockPosX.U += gradientX.U * 8; + blockPosX.V += gradientX.V * 8; + + rcpW = 0x01000000 / blockPosX.W; + int32_t nextU = (int32_t)(blockPosX.U * rcpW); + int32_t nextV = (int32_t)(blockPosX.V * rcpW); + int32_t stepU = (nextU - posU) / 8; + int32_t stepV = (nextV - posV) / 8; + + fixed_t lightnext = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosX.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + fixed_t lightstep = (lightnext - lightpos) / 8; + lightstep = lightstep & lightmask; + + for (int x = 0; x < 4; x++) + { + // Load bgcolor + uint32_t desttmp[2]; + if (mask1 & (1 << 31)) desttmp[0] = dest[x * 2]; + if (mask1 & (1 << 30)) desttmp[1] = dest[x * 2 + 1]; + + __m128i bgcolor; + if (BlendT::Mode != (int)BlendModes::Opaque) + bgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)desttmp), _mm_setzero_si128()); + else + bgcolor = _mm_setzero_si128(); + + // Sample fgcolor + unsigned int ifgcolor[2], ifgshade[2]; + ifgcolor[0] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); + ifgshade[0] = SampleShade32(posU, posV, texPixels, texWidth, texHeight); + posU += stepU; + posV += stepV; + + ifgcolor[1] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); + ifgshade[1] = SampleShade32(posU, posV, texPixels, texWidth, texHeight); + posU += stepU; + posV += stepV; + + // Setup light + int lightpos0 = lightpos >> 8; + lightpos += lightstep; + int lightpos1 = lightpos >> 8; + lightpos += lightstep; + __m128i mlight = _mm_set_epi16(256, lightpos1, lightpos1, lightpos1, 256, lightpos0, lightpos0, lightpos0); + + __m128i shade_fade_lit; + if (ShadeModeT::Mode == (int)ShadeMode::Advanced) + { + __m128i inv_light = _mm_sub_epi16(_mm_set_epi16(0, 256, 256, 256, 0, 256, 256, 256), mlight); + shade_fade_lit = _mm_mullo_epi16(shade_fade, inv_light); + } + else + { + shade_fade_lit = _mm_setzero_si128(); + } + + // Shade and blend + __m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128()); + fgcolor = Shade32(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light); + __m128i outcolor = Blend32(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha); + + // Store result + _mm_storel_epi64((__m128i*)desttmp, outcolor); + if (mask1 & (1 << 31)) dest[x * 2] = desttmp[0]; + if (mask1 & (1 << 30)) dest[x * 2 + 1] = desttmp[1]; + + mask1 <<= 2; + } + + blockPosY.W += gradientY.W; + blockPosY.U += gradientY.U; + blockPosY.V += gradientY.V; + + dest += pitch; + } + } + } static float FindGradientX(float x0, float y0, float x1, float y1, float x2, float y2, float c0, float c1, float c2) { @@ -694,3 +692,168 @@ private: return top / bottom; } }; + +template +class RectScreenDrawer32 +{ +public: + static void Execute(const void *destOrg, int destWidth, int destHeight, int destPitch, const RectDrawArgs *args, WorkerThreadData *thread) + { + using namespace TriScreenDrawerModes; + + if (args->SimpleShade()) + { + Loop(destOrg, destWidth, destHeight, destPitch, args, thread); + } + else + { + Loop(destOrg, destWidth, destHeight, destPitch, args, thread); + } + } + +private: + template + FORCEINLINE static void VECTORCALL Loop(const void *destOrg, int destWidth, int destHeight, int destPitch, const RectDrawArgs *args, WorkerThreadData *thread) + { + using namespace TriScreenDrawerModes; + + int x0 = clamp((int)(args->X0() + 0.5f), 0, destWidth); + int x1 = clamp((int)(args->X1() + 0.5f), 0, destWidth); + int y0 = clamp((int)(args->Y0() + 0.5f), 0, destHeight); + int y1 = clamp((int)(args->Y1() + 0.5f), 0, destHeight); + + if (x1 <= x0 || y1 <= y0) + return; + + uint32_t srcalpha = args->SrcAlpha(); + uint32_t destalpha = args->DestAlpha(); + + // Setup step variables + float fstepU = (args->U1() - args->U0()) / (args->X1() - args->X0()); + float fstepV = (args->V1() - args->V0()) / (args->Y1() - args->Y0()); + uint32_t startU = (int32_t)((args->U0() + (x0 + 0.5f - args->X0()) * fstepU) * 0x1000000); + uint32_t startV = (int32_t)((args->V0() + (y0 + 0.5f - args->Y0()) * fstepV) * 0x1000000); + uint32_t stepU = (int32_t)(fstepU * 0x1000000); + uint32_t stepV = (int32_t)(fstepV * 0x1000000); + + // Sampling stuff + uint32_t color = args->Color(); + const uint32_t * RESTRICT translation = (const uint32_t *)args->Translation(); + const uint32_t * RESTRICT texPixels = (const uint32_t *)args->TexturePixels(); + uint32_t texWidth = args->TextureWidth(); + uint32_t texHeight = args->TextureHeight(); + uint32_t oneU, oneV; + if (SamplerT::Mode != (int)Samplers::Fill) + { + oneU = ((0x800000 + texWidth - 1) / texWidth) * 2 + 1; + oneV = ((0x800000 + texHeight - 1) / texHeight) * 2 + 1; + } + else + { + oneU = 0; + oneV = 0; + } + + // Shade constants + __m128i inv_desaturate, shade_fade, shade_light; + int desaturate; + if (ShadeModeT::Mode == (int)ShadeMode::Advanced) + { + inv_desaturate = _mm_setr_epi16(256, 256 - args->ShadeDesaturate(), 256 - args->ShadeDesaturate(), 256 - args->ShadeDesaturate(), 256, 256 - args->ShadeDesaturate(), 256 - args->ShadeDesaturate(), 256 - args->ShadeDesaturate()); + shade_fade = _mm_set_epi16(args->ShadeFadeAlpha(), args->ShadeFadeRed(), args->ShadeFadeGreen(), args->ShadeFadeBlue(), args->ShadeFadeAlpha(), args->ShadeFadeRed(), args->ShadeFadeGreen(), args->ShadeFadeBlue()); + shade_light = _mm_set_epi16(args->ShadeLightAlpha(), args->ShadeLightRed(), args->ShadeLightGreen(), args->ShadeLightBlue(), args->ShadeLightAlpha(), args->ShadeLightRed(), args->ShadeLightGreen(), args->ShadeLightBlue()); + desaturate = args->ShadeDesaturate(); + } + else + { + inv_desaturate = _mm_setzero_si128(); + shade_fade = _mm_setzero_si128(); + shade_light = _mm_setzero_si128(); + desaturate = 0; + } + + // Setup light + uint32_t lightpos = args->Light(); + lightpos += lightpos >> 7; // 255 -> 256 + __m128i mlight = _mm_set_epi16(256, lightpos, lightpos, lightpos, 256, lightpos, lightpos, lightpos); + __m128i shade_fade_lit; + if (ShadeModeT::Mode == (int)ShadeMode::Advanced) + { + __m128i inv_light = _mm_sub_epi16(_mm_set_epi16(0, 256, 256, 256, 0, 256, 256, 256), mlight); + shade_fade_lit = _mm_mullo_epi16(shade_fade, inv_light); + } + else + { + shade_fade_lit = _mm_setzero_si128(); + } + + int count = x1 - x0; + int sseCount = count / 2; + + uint32_t posV = startV; + for (int y = y0; y < y1; y++, posV += stepV) + { + int coreBlock = y / 8; + if (coreBlock % thread->num_cores != thread->core) + continue; + + uint32_t *dest = ((uint32_t*)destOrg) + y * destPitch + x0; + + uint32_t posU = startU; + for (int i = 0; i < sseCount; i++) + { + // Load bgcolor + __m128i bgcolor; + if (BlendT::Mode != (int)BlendModes::Opaque) + bgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)dest), _mm_setzero_si128()); + else + bgcolor = _mm_setzero_si128(); + + // Sample fgcolor + unsigned int ifgcolor[2], ifgshade[2]; + ifgcolor[0] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); + ifgshade[0] = SampleShade32(posU, posV, texPixels, texWidth, texHeight); + posU += stepU; + + ifgcolor[1] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); + ifgshade[1] = SampleShade32(posU, posV, texPixels, texWidth, texHeight); + posU += stepU; + + // Shade and blend + __m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128()); + fgcolor = Shade32(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light); + __m128i outcolor = Blend32(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha); + + // Store result + _mm_storel_epi64((__m128i*)dest, outcolor); + dest += 2; + } + + if (sseCount * 2 != count) + { + // Load bgcolor + __m128i bgcolor; + if (BlendT::Mode != (int)BlendModes::Opaque) + bgcolor = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*dest), _mm_setzero_si128()); + else + bgcolor = _mm_setzero_si128(); + + // Sample fgcolor + unsigned int ifgcolor[2], ifgshade[2]; + ifgcolor[0] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); + ifgshade[0] = SampleShade32(posU, posV, texPixels, texWidth, texHeight); + ifgcolor[1] = 0; + ifgshade[1] = 0; + posU += stepU; + + // Shade and blend + __m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128()); + fgcolor = Shade32(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light); + __m128i outcolor = Blend32(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha); + + // Store result + *dest = _mm_cvtsi128_si32(outcolor); + } + } + } +}; diff --git a/src/polyrenderer/drawers/poly_drawer8.h b/src/polyrenderer/drawers/poly_drawer8.h index 2ae40e524..c6f98bd09 100644 --- a/src/polyrenderer/drawers/poly_drawer8.h +++ b/src/polyrenderer/drawers/poly_drawer8.h @@ -24,255 +24,13 @@ #include "screen_triangle.h" -template -class TriScreenDrawer8 +namespace TriScreenDrawerModes { -public: - static void Execute(const TriDrawTriangleArgs *args, WorkerThreadData *thread) + template + FORCEINLINE unsigned int Sample8(int32_t u, int32_t v, const uint8_t *texPixels, int texWidth, int texHeight, uint32_t color, const uint8_t *translation) { - using namespace TriScreenDrawerModes; - - int numSpans = thread->NumFullSpans; - auto fullSpans = thread->FullSpans; - int numBlocks = thread->NumPartialBlocks; - auto partialBlocks = thread->PartialBlocks; - int startX = thread->StartX; - int startY = thread->StartY; - - bool is_fixed_light = args->uniforms->FixedLight(); - uint32_t lightmask = is_fixed_light ? 0 : 0xffffffff; - auto colormaps = args->uniforms->BaseColormap(); - uint32_t srcalpha = args->uniforms->SrcAlpha(); - uint32_t destalpha = args->uniforms->DestAlpha(); - - // Calculate gradients - const TriVertex &v1 = *args->v1; - const TriVertex &v2 = *args->v2; - const TriVertex &v3 = *args->v3; - ScreenTriangleStepVariables gradientX; - ScreenTriangleStepVariables gradientY; - ScreenTriangleStepVariables start; - gradientX.W = FindGradientX(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.w, v2.w, v3.w); - gradientY.W = FindGradientY(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.w, v2.w, v3.w); - start.W = v1.w + gradientX.W * (startX - v1.x) + gradientY.W * (startY - v1.y); - for (int i = 0; i < TriVertex::NumVarying; i++) - { - gradientX.Varying[i] = FindGradientX(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.varying[i] * v1.w, v2.varying[i] * v2.w, v3.varying[i] * v3.w); - gradientY.Varying[i] = FindGradientY(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.varying[i] * v1.w, v2.varying[i] * v2.w, v3.varying[i] * v3.w); - start.Varying[i] = v1.varying[i] * v1.w + gradientX.Varying[i] * (startX - v1.x) + gradientY.Varying[i] * (startY - v1.y); - } - - // Output - uint8_t * RESTRICT destOrg = args->dest; - int pitch = args->pitch; - - // Light - uint32_t light = args->uniforms->Light(); - float shade = 2.0f - (light + 12.0f) / 128.0f; - float globVis = args->uniforms->GlobVis() * (1.0f / 32.0f); - light += light >> 7; // 255 -> 256 - - // Sampling stuff - uint32_t color = args->uniforms->Color(); - const uint8_t * RESTRICT translation = args->uniforms->Translation(); - const uint8_t * RESTRICT texPixels = args->uniforms->TexturePixels(); - uint32_t texWidth = args->uniforms->TextureWidth(); - uint32_t texHeight = args->uniforms->TextureHeight(); - - for (int i = 0; i < numSpans; i++) - { - const auto &span = fullSpans[i]; - - uint8_t *dest = destOrg + span.X + span.Y * pitch; - int width = span.Length; - int height = 8; - - ScreenTriangleStepVariables blockPosY; - blockPosY.W = start.W + gradientX.W * (span.X - startX) + gradientY.W * (span.Y - startY); - for (int j = 0; j < TriVertex::NumVarying; j++) - blockPosY.Varying[j] = start.Varying[j] + gradientX.Varying[j] * (span.X - startX) + gradientY.Varying[j] * (span.Y - startY); - - for (int y = 0; y < height; y++) - { - ScreenTriangleStepVariables blockPosX = blockPosY; - - float rcpW = 0x01000000 / blockPosX.W; - int32_t varyingPos[TriVertex::NumVarying]; - for (int j = 0; j < TriVertex::NumVarying; j++) - varyingPos[j] = (int32_t)(blockPosX.Varying[j] * rcpW); - - fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); - - for (int x = 0; x < width; x++) - { - blockPosX.W += gradientX.W * 8; - for (int j = 0; j < TriVertex::NumVarying; j++) - blockPosX.Varying[j] += gradientX.Varying[j] * 8; - - rcpW = 0x01000000 / blockPosX.W; - int32_t varyingStep[TriVertex::NumVarying]; - for (int j = 0; j < TriVertex::NumVarying; j++) - { - int32_t nextPos = (int32_t)(blockPosX.Varying[j] * rcpW); - varyingStep[j] = (nextPos - varyingPos[j]) / 8; - } - - fixed_t lightnext = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosX.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - fixed_t lightstep = (lightnext - lightpos) / 8; - lightstep = lightstep & lightmask; - - for (int ix = 0; ix < 8; ix++) - { - int lightshade = lightpos >> 8; - uint8_t bgcolor = dest[x * 8 + ix]; - uint8_t fgcolor = Sample(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight, color, translation); - uint32_t fgshade = SampleShade(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight); - dest[x * 8 + ix] = ShadeAndBlend(fgcolor, bgcolor, fgshade, lightshade, colormaps, srcalpha, destalpha); - for (int j = 0; j < TriVertex::NumVarying; j++) - varyingPos[j] += varyingStep[j]; - lightpos += lightstep; - } - } - - blockPosY.W += gradientY.W; - for (int j = 0; j < TriVertex::NumVarying; j++) - blockPosY.Varying[j] += gradientY.Varying[j]; - - dest += pitch; - } - } - - for (int i = 0; i < numBlocks; i++) - { - const auto &block = partialBlocks[i]; - - ScreenTriangleStepVariables blockPosY; - blockPosY.W = start.W + gradientX.W * (block.X - startX) + gradientY.W * (block.Y - startY); - for (int j = 0; j < TriVertex::NumVarying; j++) - blockPosY.Varying[j] = start.Varying[j] + gradientX.Varying[j] * (block.X - startX) + gradientY.Varying[j] * (block.Y - startY); - - uint8_t *dest = destOrg + block.X + block.Y * pitch; - uint32_t mask0 = block.Mask0; - uint32_t mask1 = block.Mask1; - - // mask0 loop: - for (int y = 0; y < 4; y++) - { - ScreenTriangleStepVariables blockPosX = blockPosY; - - float rcpW = 0x01000000 / blockPosX.W; - int32_t varyingPos[TriVertex::NumVarying]; - for (int j = 0; j < TriVertex::NumVarying; j++) - varyingPos[j] = (int32_t)(blockPosX.Varying[j] * rcpW); - - fixed_t lightpos = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); - - blockPosX.W += gradientX.W * 8; - for (int j = 0; j < TriVertex::NumVarying; j++) - blockPosX.Varying[j] += gradientX.Varying[j] * 8; - - rcpW = 0x01000000 / blockPosX.W; - int32_t varyingStep[TriVertex::NumVarying]; - for (int j = 0; j < TriVertex::NumVarying; j++) - { - int32_t nextPos = (int32_t)(blockPosX.Varying[j] * rcpW); - varyingStep[j] = (nextPos - varyingPos[j]) / 8; - } - - fixed_t lightnext = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosX.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - fixed_t lightstep = (lightnext - lightpos) / 8; - lightstep = lightstep & lightmask; - - for (int x = 0; x < 8; x++) - { - if (mask0 & (1 << 31)) - { - int lightshade = lightpos >> 8; - uint8_t bgcolor = dest[x]; - uint8_t fgcolor = Sample(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight, color, translation); - uint32_t fgshade = SampleShade(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight); - dest[x] = ShadeAndBlend(fgcolor, bgcolor, fgshade, lightshade, colormaps, srcalpha, destalpha); - } - - for (int j = 0; j < TriVertex::NumVarying; j++) - varyingPos[j] += varyingStep[j]; - lightpos += lightstep; - - mask0 <<= 1; - } - - blockPosY.W += gradientY.W; - for (int j = 0; j < TriVertex::NumVarying; j++) - blockPosY.Varying[j] += gradientY.Varying[j]; - - dest += pitch; - } - - // mask1 loop: - for (int y = 0; y < 4; y++) - { - ScreenTriangleStepVariables blockPosX = blockPosY; - - float rcpW = 0x01000000 / blockPosX.W; - int32_t varyingPos[TriVertex::NumVarying]; - for (int j = 0; j < TriVertex::NumVarying; j++) - varyingPos[j] = (int32_t)(blockPosX.Varying[j] * rcpW); - - fixed_t lightpos = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); - - blockPosX.W += gradientX.W * 8; - for (int j = 0; j < TriVertex::NumVarying; j++) - blockPosX.Varying[j] += gradientX.Varying[j] * 8; - - rcpW = 0x01000000 / blockPosX.W; - int32_t varyingStep[TriVertex::NumVarying]; - for (int j = 0; j < TriVertex::NumVarying; j++) - { - int32_t nextPos = (int32_t)(blockPosX.Varying[j] * rcpW); - varyingStep[j] = (nextPos - varyingPos[j]) / 8; - } - - fixed_t lightnext = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosX.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); - fixed_t lightstep = (lightnext - lightpos) / 8; - lightstep = lightstep & lightmask; - - for (int x = 0; x < 8; x++) - { - if (mask1 & (1 << 31)) - { - int lightshade = lightpos >> 8; - uint8_t bgcolor = dest[x]; - uint8_t fgcolor = Sample(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight, color, translation); - uint32_t fgshade = SampleShade(varyingPos[0], varyingPos[1], texPixels, texWidth, texHeight); - dest[x] = ShadeAndBlend(fgcolor, bgcolor, fgshade, lightshade, colormaps, srcalpha, destalpha); - } - - for (int j = 0; j < TriVertex::NumVarying; j++) - varyingPos[j] += varyingStep[j]; - lightpos += lightstep; - - mask1 <<= 1; - } - - blockPosY.W += gradientY.W; - for (int j = 0; j < TriVertex::NumVarying; j++) - blockPosY.Varying[j] += gradientY.Varying[j]; - - dest += pitch; - } - } - } - -private: - FORCEINLINE static unsigned int Sample(int32_t u, int32_t v, const uint8_t *texPixels, int texWidth, int texHeight, uint32_t color, const uint8_t *translation) - { - using namespace TriScreenDrawerModes; - uint8_t texel; - if (SamplerT::Mode == (int)Samplers::Shaded || SamplerT::Mode == (int)Samplers::Fill) + if (SamplerT::Mode == (int)Samplers::Shaded || SamplerT::Mode == (int)Samplers::Stencil || SamplerT::Mode == (int)Samplers::Fill) { return color; } @@ -301,13 +59,14 @@ private: if (a == 256) return texel; + uint32_t capcolor = GPalette.BaseColors[color].d; uint32_t texelrgb = GPalette.BaseColors[texel].d; uint32_t r = RPART(texelrgb); uint32_t g = GPART(texelrgb); uint32_t b = BPART(texelrgb); - uint32_t capcolor_red = RPART(color); - uint32_t capcolor_green = GPART(color); - uint32_t capcolor_blue = BPART(color); + uint32_t capcolor_red = RPART(capcolor); + uint32_t capcolor_green = GPART(capcolor); + uint32_t capcolor_blue = BPART(capcolor); r = (r * a + capcolor_red * inv_a + 127) >> 8; g = (g * a + capcolor_green * inv_a + 127) >> 8; b = (b * a + capcolor_blue * inv_a + 127) >> 8; @@ -319,10 +78,9 @@ private: } } - FORCEINLINE static unsigned int SampleShade(int32_t u, int32_t v, const uint8_t *texPixels, int texWidth, int texHeight) + template + FORCEINLINE unsigned int SampleShade8(int32_t u, int32_t v, const uint8_t *texPixels, int texWidth, int texHeight) { - using namespace TriScreenDrawerModes; - if (SamplerT::Mode == (int)Samplers::Shaded) { uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; @@ -331,16 +89,21 @@ private: sampleshadeout += sampleshadeout >> 7; // 255 -> 256 return sampleshadeout; } + else if (SamplerT::Mode == (int)Samplers::Stencil) + { + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; + uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; + return texPixels[texelX * texHeight + texelY] != 0 ? 256 : 0; + } else { return 0; } } - FORCEINLINE static uint8_t ShadeAndBlend(uint8_t fgcolor, uint8_t bgcolor, uint32_t fgshade, uint32_t lightshade, const uint8_t *colormaps, uint32_t srcalpha, uint32_t destalpha) + template + FORCEINLINE uint8_t ShadeAndBlend8(uint8_t fgcolor, uint8_t bgcolor, uint32_t fgshade, uint32_t lightshade, const uint8_t *colormaps, uint32_t srcalpha, uint32_t destalpha) { - using namespace TriScreenDrawerModes; - lightshade = ((256 - lightshade) * NUMCOLORMAPS) & 0xffffff00; uint8_t shadedfg = colormaps[lightshade + fgcolor]; @@ -372,6 +135,7 @@ private: } else if (BlendT::Mode == (int)BlendModes::Shaded) { + fgshade = (fgshade * srcalpha + 128) >> 8; uint32_t alpha = fgshade; uint32_t inv_alpha = 256 - fgshade; int32_t fg_r = GPalette.BaseColors[shadedfg].r; @@ -390,6 +154,7 @@ private: } else if (BlendT::Mode == (int)BlendModes::AddClampShaded) { + fgshade = (fgshade * srcalpha + 128) >> 8; uint32_t alpha = fgshade; int32_t fg_r = GPalette.BaseColors[shadedfg].r; int32_t fg_g = GPalette.BaseColors[shadedfg].g; @@ -417,28 +182,263 @@ private: if (BlendT::Mode == (int)BlendModes::AddClamp) { - fg_r = MIN((fg_r * srcalpha + bg_r * destalpha + 127) >> 8, 255); - fg_g = MIN((fg_g * srcalpha + bg_g * destalpha + 127) >> 8, 255); - fg_b = MIN((fg_b * srcalpha + bg_b * destalpha + 127) >> 8, 255); + fg_r = MIN(int32_t(fg_r * srcalpha + bg_r * destalpha + 127) >> 8, 255); + fg_g = MIN(int32_t(fg_g * srcalpha + bg_g * destalpha + 127) >> 8, 255); + fg_b = MIN(int32_t(fg_b * srcalpha + bg_b * destalpha + 127) >> 8, 255); } else if (BlendT::Mode == (int)BlendModes::SubClamp) { - fg_r = MAX((fg_r * srcalpha - bg_r * destalpha + 127) >> 8, 0); - fg_g = MAX((fg_g * srcalpha - bg_g * destalpha + 127) >> 8, 0); - fg_b = MAX((fg_b * srcalpha - bg_b * destalpha + 127) >> 8, 0); + fg_r = MAX(int32_t(fg_r * srcalpha - bg_r * destalpha + 127) >> 8, 0); + fg_g = MAX(int32_t(fg_g * srcalpha - bg_g * destalpha + 127) >> 8, 0); + fg_b = MAX(int32_t(fg_b * srcalpha - bg_b * destalpha + 127) >> 8, 0); } else if (BlendT::Mode == (int)BlendModes::RevSubClamp) { - fg_r = MAX((bg_r * srcalpha - fg_r * destalpha + 127) >> 8, 0); - fg_g = MAX((bg_g * srcalpha - fg_g * destalpha + 127) >> 8, 0); - fg_b = MAX((bg_b * srcalpha - fg_b * destalpha + 127) >> 8, 0); + fg_r = MAX(int32_t(bg_r * srcalpha - fg_r * destalpha + 127) >> 8, 0); + fg_g = MAX(int32_t(bg_g * srcalpha - fg_g * destalpha + 127) >> 8, 0); + fg_b = MAX(int32_t(bg_b * srcalpha - fg_b * destalpha + 127) >> 8, 0); } shadedfg = RGB256k.All[((fg_r >> 2) << 12) | ((fg_g >> 2) << 6) | (fg_b >> 2)]; return (fgcolor != 0) ? shadedfg : bgcolor; } } +} +template +class TriScreenDrawer8 +{ +public: + static void Execute(const TriDrawTriangleArgs *args, WorkerThreadData *thread) + { + using namespace TriScreenDrawerModes; + + int numSpans = thread->NumFullSpans; + auto fullSpans = thread->FullSpans; + int numBlocks = thread->NumPartialBlocks; + auto partialBlocks = thread->PartialBlocks; + int startX = thread->StartX; + int startY = thread->StartY; + + bool is_fixed_light = args->uniforms->FixedLight(); + uint32_t lightmask = is_fixed_light ? 0 : 0xffffffff; + auto colormaps = args->uniforms->BaseColormap(); + uint32_t srcalpha = args->uniforms->SrcAlpha(); + uint32_t destalpha = args->uniforms->DestAlpha(); + + // Calculate gradients + const TriVertex &v1 = *args->v1; + const TriVertex &v2 = *args->v2; + const TriVertex &v3 = *args->v3; + ScreenTriangleStepVariables gradientX; + ScreenTriangleStepVariables gradientY; + ScreenTriangleStepVariables start; + gradientX.W = FindGradientX(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.w, v2.w, v3.w); + gradientY.W = FindGradientY(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.w, v2.w, v3.w); + gradientX.U = FindGradientX(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.u * v1.w, v2.u * v2.w, v3.u * v3.w); + gradientY.U = FindGradientY(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.u * v1.w, v2.u * v2.w, v3.u * v3.w); + gradientX.V = FindGradientX(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.v * v1.w, v2.v * v2.w, v3.v * v3.w); + gradientY.V = FindGradientY(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, v1.v * v1.w, v2.v * v2.w, v3.v * v3.w); + start.W = v1.w + gradientX.W * (startX - v1.x) + gradientY.W * (startY - v1.y); + start.U = v1.u * v1.w + gradientX.U * (startX - v1.x) + gradientY.U * (startY - v1.y); + start.V = v1.v * v1.w + gradientX.V * (startX - v1.x) + gradientY.V * (startY - v1.y); + + // Output + uint8_t * RESTRICT destOrg = args->dest; + int pitch = args->pitch; + + // Light + uint32_t light = args->uniforms->Light(); + float shade = 2.0f - (light + 12.0f) / 128.0f; + float globVis = args->uniforms->GlobVis() * (1.0f / 32.0f); + light += light >> 7; // 255 -> 256 + + // Sampling stuff + uint32_t color = args->uniforms->Color(); + const uint8_t * RESTRICT translation = args->uniforms->Translation(); + const uint8_t * RESTRICT texPixels = args->uniforms->TexturePixels(); + uint32_t texWidth = args->uniforms->TextureWidth(); + uint32_t texHeight = args->uniforms->TextureHeight(); + + for (int i = 0; i < numSpans; i++) + { + const auto &span = fullSpans[i]; + + uint8_t *dest = destOrg + span.X + span.Y * pitch; + int width = span.Length; + int height = 8; + + ScreenTriangleStepVariables blockPosY; + blockPosY.W = start.W + gradientX.W * (span.X - startX) + gradientY.W * (span.Y - startY); + blockPosY.U = start.U + gradientX.U * (span.X - startX) + gradientY.U * (span.Y - startY); + blockPosY.V = start.V + gradientX.V * (span.X - startX) + gradientY.V * (span.Y - startY); + + for (int y = 0; y < height; y++) + { + ScreenTriangleStepVariables blockPosX = blockPosY; + + float rcpW = 0x01000000 / blockPosX.W; + int32_t posU = (int32_t)(blockPosX.U * rcpW); + int32_t posV = (int32_t)(blockPosX.V * rcpW); + + fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + + for (int x = 0; x < width; x++) + { + blockPosX.W += gradientX.W * 8; + blockPosX.U += gradientX.U * 8; + blockPosX.V += gradientX.V * 8; + + rcpW = 0x01000000 / blockPosX.W; + int32_t nextU = (int32_t)(blockPosX.U * rcpW); + int32_t nextV = (int32_t)(blockPosX.V * rcpW); + int32_t stepU = (nextU - posU) / 8; + int32_t stepV = (nextV - posV) / 8; + + fixed_t lightnext = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosX.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + fixed_t lightstep = (lightnext - lightpos) / 8; + lightstep = lightstep & lightmask; + + for (int ix = 0; ix < 8; ix++) + { + int lightshade = lightpos >> 8; + uint8_t bgcolor = dest[x * 8 + ix]; + uint8_t fgcolor = Sample8(posU, posV, texPixels, texWidth, texHeight, color, translation); + uint32_t fgshade = SampleShade8(posU, posV, texPixels, texWidth, texHeight); + dest[x * 8 + ix] = ShadeAndBlend8(fgcolor, bgcolor, fgshade, lightshade, colormaps, srcalpha, destalpha); + posU += stepU; + posV += stepV; + lightpos += lightstep; + } + } + + blockPosY.W += gradientY.W; + blockPosY.U += gradientY.U; + blockPosY.V += gradientY.V; + + dest += pitch; + } + } + + for (int i = 0; i < numBlocks; i++) + { + const auto &block = partialBlocks[i]; + + ScreenTriangleStepVariables blockPosY; + blockPosY.W = start.W + gradientX.W * (block.X - startX) + gradientY.W * (block.Y - startY); + blockPosY.U = start.U + gradientX.U * (block.X - startX) + gradientY.U * (block.Y - startY); + blockPosY.V = start.V + gradientX.V * (block.X - startX) + gradientY.V * (block.Y - startY); + + uint8_t *dest = destOrg + block.X + block.Y * pitch; + uint32_t mask0 = block.Mask0; + uint32_t mask1 = block.Mask1; + + // mask0 loop: + for (int y = 0; y < 4; y++) + { + ScreenTriangleStepVariables blockPosX = blockPosY; + + float rcpW = 0x01000000 / blockPosX.W; + int32_t posU = (int32_t)(blockPosX.U * rcpW); + int32_t posV = (int32_t)(blockPosX.V * rcpW); + + fixed_t lightpos = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + + blockPosX.W += gradientX.W * 8; + blockPosX.U += gradientX.U * 8; + blockPosX.V += gradientX.V * 8; + + rcpW = 0x01000000 / blockPosX.W; + int32_t nextU = (int32_t)(blockPosX.U * rcpW); + int32_t nextV = (int32_t)(blockPosX.V * rcpW); + int32_t stepU = (nextU - posU) / 8; + int32_t stepV = (nextV - posV) / 8; + + fixed_t lightnext = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosX.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + fixed_t lightstep = (lightnext - lightpos) / 8; + lightstep = lightstep & lightmask; + + for (int x = 0; x < 8; x++) + { + if (mask0 & (1 << 31)) + { + int lightshade = lightpos >> 8; + uint8_t bgcolor = dest[x]; + uint8_t fgcolor = Sample8(posU, posV, texPixels, texWidth, texHeight, color, translation); + uint32_t fgshade = SampleShade8(posU, posV, texPixels, texWidth, texHeight); + dest[x] = ShadeAndBlend8(fgcolor, bgcolor, fgshade, lightshade, colormaps, srcalpha, destalpha); + } + + posU += stepU; + posV += stepV; + lightpos += lightstep; + + mask0 <<= 1; + } + + blockPosY.W += gradientY.W; + blockPosY.U += gradientY.U; + blockPosY.V += gradientY.V; + + dest += pitch; + } + + // mask1 loop: + for (int y = 0; y < 4; y++) + { + ScreenTriangleStepVariables blockPosX = blockPosY; + + float rcpW = 0x01000000 / blockPosX.W; + int32_t posU = (int32_t)(blockPosX.U * rcpW); + int32_t posV = (int32_t)(blockPosX.V * rcpW); + + fixed_t lightpos = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + + blockPosX.W += gradientX.W * 8; + blockPosX.U += gradientX.U * 8; + blockPosX.V += gradientX.V * 8; + + rcpW = 0x01000000 / blockPosX.W; + int32_t nextU = (int32_t)(blockPosX.U * rcpW); + int32_t nextV = (int32_t)(blockPosX.V * rcpW); + int32_t stepU = (nextU - posU) / 8; + int32_t stepV = (nextV - posV) / 8; + + fixed_t lightnext = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosX.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); + fixed_t lightstep = (lightnext - lightpos) / 8; + lightstep = lightstep & lightmask; + + for (int x = 0; x < 8; x++) + { + if (mask1 & (1 << 31)) + { + int lightshade = lightpos >> 8; + uint8_t bgcolor = dest[x]; + uint8_t fgcolor = Sample8(posU, posV, texPixels, texWidth, texHeight, color, translation); + uint32_t fgshade = SampleShade8(posU, posV, texPixels, texWidth, texHeight); + dest[x] = ShadeAndBlend8(fgcolor, bgcolor, fgshade, lightshade, colormaps, srcalpha, destalpha); + } + + posU += stepU; + posV += stepV; + lightpos += lightstep; + + mask1 <<= 1; + } + + blockPosY.W += gradientY.W; + blockPosY.U += gradientY.U; + blockPosY.V += gradientY.V; + + dest += pitch; + } + } + } + +private: static float FindGradientX(float x0, float y0, float x1, float y1, float x2, float y2, float c0, float c1, float c2) { float top = (c1 - c2) * (y0 - y2) - (c0 - c2) * (y1 - y2); @@ -453,3 +453,68 @@ private: return top / bottom; } }; + +template +class RectScreenDrawer8 +{ +public: + static void Execute(const void *destOrg, int destWidth, int destHeight, int destPitch, const RectDrawArgs *args, WorkerThreadData *thread) + { + using namespace TriScreenDrawerModes; + + int x0 = clamp((int)(args->X0() + 0.5f), 0, destWidth); + int x1 = clamp((int)(args->X1() + 0.5f), 0, destWidth); + int y0 = clamp((int)(args->Y0() + 0.5f), 0, destHeight); + int y1 = clamp((int)(args->Y1() + 0.5f), 0, destHeight); + + if (x1 <= x0 || y1 <= y0) + return; + + auto colormaps = args->BaseColormap(); + uint32_t srcalpha = args->SrcAlpha(); + uint32_t destalpha = args->DestAlpha(); + + // Setup step variables + float fstepU = (args->U1() - args->U0()) / (args->X1() - args->X0()); + float fstepV = (args->V1() - args->V0()) / (args->Y1() - args->Y0()); + uint32_t startU = (int32_t)((args->U0() + (x0 + 0.5f - args->X0()) * fstepU) * 0x1000000); + uint32_t startV = (int32_t)((args->V0() + (y0 + 0.5f - args->Y0()) * fstepV) * 0x1000000); + uint32_t stepU = (int32_t)(fstepU * 0x1000000); + uint32_t stepV = (int32_t)(fstepV * 0x1000000); + + // Sampling stuff + uint32_t color = args->Color(); + const uint8_t * RESTRICT translation = args->Translation(); + const uint8_t * RESTRICT texPixels = args->TexturePixels(); + uint32_t texWidth = args->TextureWidth(); + uint32_t texHeight = args->TextureHeight(); + + // Setup light + uint32_t lightshade = args->Light(); + lightshade += lightshade >> 7; // 255 -> 256 + + int count = x1 - x0; + + uint32_t posV = startV; + for (int y = y0; y < y1; y++, posV += stepV) + { + int coreBlock = y / 8; + if (coreBlock % thread->num_cores != thread->core) + continue; + + uint8_t *dest = ((uint8_t*)destOrg) + y * destPitch + x0; + + uint32_t posU = startU; + for (int i = 0; i < count; i++) + { + uint8_t bgcolor = *dest; + uint8_t fgcolor = Sample8(posU, posV, texPixels, texWidth, texHeight, color, translation); + uint32_t fgshade = SampleShade8(posU, posV, texPixels, texWidth, texHeight); + *dest = ShadeAndBlend8(fgcolor, bgcolor, fgshade, lightshade, colormaps, srcalpha, destalpha); + + posU += stepU; + dest++; + } + } + } +}; diff --git a/src/polyrenderer/drawers/poly_triangle.cpp b/src/polyrenderer/drawers/poly_triangle.cpp index d07102f1e..4bf57e12e 100644 --- a/src/polyrenderer/drawers/poly_triangle.cpp +++ b/src/polyrenderer/drawers/poly_triangle.cpp @@ -99,10 +99,8 @@ void PolyTriangleDrawer::draw_arrays(const PolyDrawArgs &drawargs, WorkerThreadD { int bmode = (int)drawargs.BlendMode(); - if (drawargs.WriteColor() && drawargs.TexturePixels()) - drawfuncs[num_drawfuncs++] = dest_bgra ? ScreenTriangle::TriDraw32[bmode] : ScreenTriangle::TriDraw8[bmode]; - else if (drawargs.WriteColor()) - drawfuncs[num_drawfuncs++] = dest_bgra ? ScreenTriangle::TriFill32[bmode] : ScreenTriangle::TriFill8[bmode]; + if (drawargs.WriteColor()) + drawfuncs[num_drawfuncs++] = dest_bgra ? ScreenTriangle::TriDrawers32[bmode] : ScreenTriangle::TriDrawers8[bmode]; } if (drawargs.WriteStencil()) @@ -234,13 +232,12 @@ void PolyTriangleDrawer::draw_shaded_triangle(const ShadedTriVertex *vert, bool // Keep varyings in -128 to 128 range if possible if (numclipvert > 0) { - for (int j = 0; j < TriVertex::NumVarying; j++) + float newOriginU = floorf(clippedvert[0].u * 0.1f) * 10.0f; + float newOriginV = floorf(clippedvert[0].v * 0.1f) * 10.0f; + for (int i = 0; i < numclipvert; i++) { - float newOrigin = floorf(clippedvert[0].varying[j] * 0.1f) * 10.0f; - for (int i = 0; i < numclipvert; i++) - { - clippedvert[i].varying[j] -= newOrigin; - } + clippedvert[i].u -= newOriginU; + clippedvert[i].v -= newOriginV; } } @@ -426,8 +423,8 @@ int PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, TriVertex *clippe v.y += verts[w].y * weight; v.z += verts[w].z * weight; v.w += verts[w].w * weight; - for (int iv = 0; iv < TriVertex::NumVarying; iv++) - v.varying[iv] += verts[w].varying[iv] * weight; + v.u += verts[w].u * weight; + v.v += verts[w].v * weight; } } return inputverts; @@ -452,3 +449,23 @@ void DrawPolyTrianglesCommand::Execute(DrawerThread *thread) PolyTriangleDrawer::draw_arrays(args, &thread_data); } + +///////////////////////////////////////////////////////////////////////////// + +void DrawRectCommand::Execute(DrawerThread *thread) +{ + WorkerThreadData thread_data; + thread_data.core = thread->core; + thread_data.num_cores = thread->num_cores; + + auto renderTarget = PolyRenderer::Instance()->RenderTarget; + const void *destOrg = renderTarget->GetBuffer(); + int destWidth = renderTarget->GetWidth(); + int destHeight = renderTarget->GetHeight(); + int destPitch = renderTarget->GetPitch(); + int blendmode = (int)args.BlendMode(); + if (renderTarget->IsBgra()) + ScreenTriangle::RectDrawers32[blendmode](destOrg, destWidth, destHeight, destPitch, &args, &thread_data); + else + ScreenTriangle::RectDrawers8[blendmode](destOrg, destWidth, destHeight, destPitch, &args, &thread_data); +} diff --git a/src/polyrenderer/drawers/poly_triangle.h b/src/polyrenderer/drawers/poly_triangle.h index d3019fc36..7cd6dbe76 100644 --- a/src/polyrenderer/drawers/poly_triangle.h +++ b/src/polyrenderer/drawers/poly_triangle.h @@ -71,3 +71,15 @@ public: private: PolyDrawArgs args; }; + +class DrawRectCommand : public DrawerCommand +{ +public: + DrawRectCommand(const RectDrawArgs &args) : args(args) { } + + void Execute(DrawerThread *thread) override; + FString DebugInfo() override { return "DrawRect"; } + +private: + RectDrawArgs args; +}; diff --git a/src/polyrenderer/drawers/screen_triangle.cpp b/src/polyrenderer/drawers/screen_triangle.cpp index ab0928d0e..d61bd79a2 100644 --- a/src/polyrenderer/drawers/screen_triangle.cpp +++ b/src/polyrenderer/drawers/screen_triangle.cpp @@ -922,87 +922,128 @@ void ScreenTriangle::SubsectorWrite(const TriDrawTriangleArgs *args, WorkerThrea } } -std::vector ScreenTriangle::TriDraw8 = +void(*ScreenTriangle::TriDrawers8[])(const TriDrawTriangleArgs *, WorkerThreadData *) = { - &TriScreenDrawer8::Execute, // "Copy", "opaque", false - &TriScreenDrawer8::Execute, // "AlphaBlend", "masked", false - &TriScreenDrawer8::Execute, // "AddSolid", "translucent", false - &TriScreenDrawer8::Execute, // "Add", "add", false - &TriScreenDrawer8::Execute, // "Sub", "sub", false - &TriScreenDrawer8::Execute, // "RevSub", "revsub", false - &TriScreenDrawer8::Execute, // "Stencil", "stencil", false - &TriScreenDrawer8::Execute, // "Shaded", "shaded", false - &TriScreenDrawer8::Execute, // "TranslateCopy", "opaque", true - &TriScreenDrawer8::Execute, // "TranslateAlphaBlend", "masked", true - &TriScreenDrawer8::Execute, // "TranslateAdd", "add", true - &TriScreenDrawer8::Execute, // "TranslateSub", "sub", true - &TriScreenDrawer8::Execute, // "TranslateRevSub", "revsub", true - &TriScreenDrawer8::Execute, // "AddSrcColorOneMinusSrcColor", "addsrccolor", false - &TriScreenDrawer8::Execute // "Skycap", "skycap", false -}; - -std::vector ScreenTriangle::TriFill8 = -{ - &TriScreenDrawer8::Execute, // "Copy", "opaque", false - &TriScreenDrawer8::Execute, // "AlphaBlend", "masked", false - &TriScreenDrawer8::Execute, // "AddSolid", "translucent", false - &TriScreenDrawer8::Execute, // "Add", "add", false - &TriScreenDrawer8::Execute, // "Sub", "sub", false - &TriScreenDrawer8::Execute, // "RevSub", "revsub", false - &TriScreenDrawer8::Execute, // "Stencil", "stencil", false - &TriScreenDrawer8::Execute, // "Shaded", "shaded", false - &TriScreenDrawer8::Execute, // "TranslateCopy", "opaque", true - &TriScreenDrawer8::Execute, // "TranslateAlphaBlend", "masked", true - &TriScreenDrawer8::Execute, // "TranslateAdd", "add", true - &TriScreenDrawer8::Execute, // "TranslateSub", "sub", true - &TriScreenDrawer8::Execute, // "TranslateRevSub", "revsub", true - &TriScreenDrawer8::Execute, // "AddSrcColorOneMinusSrcColor", "addsrccolor", false - &TriScreenDrawer8::Execute // "Skycap", "skycap", false + &TriScreenDrawer8::Execute, // TextureOpaque + &TriScreenDrawer8::Execute, // TextureMasked + &TriScreenDrawer8::Execute, // TextureAdd + &TriScreenDrawer8::Execute, // TextureSub + &TriScreenDrawer8::Execute, // TextureRevSub + &TriScreenDrawer8::Execute, // TextureAddSrcColor + &TriScreenDrawer8::Execute, // TranslatedOpaque + &TriScreenDrawer8::Execute, // TranslatedMasked + &TriScreenDrawer8::Execute, // TranslatedAdd + &TriScreenDrawer8::Execute, // TranslatedSub + &TriScreenDrawer8::Execute, // TranslatedRevSub + &TriScreenDrawer8::Execute, // TranslatedAddSrcColor + &TriScreenDrawer8::Execute, // Shaded + &TriScreenDrawer8::Execute, // AddShaded + &TriScreenDrawer8::Execute, // Stencil + &TriScreenDrawer8::Execute, // AddStencil + &TriScreenDrawer8::Execute, // FillOpaque + &TriScreenDrawer8::Execute, // FillAdd + &TriScreenDrawer8::Execute, // FillSub + &TriScreenDrawer8::Execute, // FillRevSub + &TriScreenDrawer8::Execute, // FillAddSrcColor + &TriScreenDrawer8::Execute // Skycap }; #ifdef NO_SSE -std::vector ScreenTriangle::TriDraw32; -std::vector ScreenTriangle::TriFill32; +void(*ScreenTriangle::TriDrawers32[])(const TriDrawTriangleArgs *, WorkerThreadData *) = +{ + nullptr +}; #else -std::vector ScreenTriangle::TriDraw32 = +void(*ScreenTriangle::TriDrawers32[])(const TriDrawTriangleArgs *, WorkerThreadData *) = { - &TriScreenDrawer32::Execute, // "Copy", "opaque", false - &TriScreenDrawer32::Execute, // "AlphaBlend", "masked", false - &TriScreenDrawer32::Execute, // "AddSolid", "translucent", false - &TriScreenDrawer32::Execute, // "Add", "add", false - &TriScreenDrawer32::Execute, // "Sub", "sub", false - &TriScreenDrawer32::Execute, // "RevSub", "revsub", false - &TriScreenDrawer32::Execute, // "Stencil", "stencil", false - &TriScreenDrawer32::Execute, // "Shaded", "shaded", false - &TriScreenDrawer32::Execute, // "TranslateCopy", "opaque", true - &TriScreenDrawer32::Execute, // "TranslateAlphaBlend", "masked", true - &TriScreenDrawer32::Execute, // "TranslateAdd", "add", true - &TriScreenDrawer32::Execute, // "TranslateSub", "sub", true - &TriScreenDrawer32::Execute, // "TranslateRevSub", "revsub", true - &TriScreenDrawer32::Execute, // "AddSrcColorOneMinusSrcColor", "addsrccolor", false - &TriScreenDrawer32::Execute // "Skycap", "skycap", false + &TriScreenDrawer32::Execute, // TextureOpaque + &TriScreenDrawer32::Execute, // TextureMasked + &TriScreenDrawer32::Execute, // TextureAdd + &TriScreenDrawer32::Execute, // TextureSub + &TriScreenDrawer32::Execute, // TextureRevSub + &TriScreenDrawer32::Execute, // TextureAddSrcColor + &TriScreenDrawer32::Execute, // TranslatedOpaque + &TriScreenDrawer32::Execute, // TranslatedMasked + &TriScreenDrawer32::Execute, // TranslatedAdd + &TriScreenDrawer32::Execute, // TranslatedSub + &TriScreenDrawer32::Execute, // TranslatedRevSub + &TriScreenDrawer32::Execute, // TranslatedAddSrcColor + &TriScreenDrawer32::Execute, // Shaded + &TriScreenDrawer32::Execute, // AddShaded + &TriScreenDrawer32::Execute, // Stencil + &TriScreenDrawer32::Execute, // AddStencil + &TriScreenDrawer32::Execute, // FillOpaque + &TriScreenDrawer32::Execute, // FillAdd + &TriScreenDrawer32::Execute, // FillSub + &TriScreenDrawer32::Execute, // FillRevSub + &TriScreenDrawer32::Execute, // FillAddSrcColor + &TriScreenDrawer32::Execute // Skycap }; -std::vector ScreenTriangle::TriFill32 = +#endif + +void(*ScreenTriangle::RectDrawers8[])(const void *, int, int, int, const RectDrawArgs *, WorkerThreadData *) = +{ + &RectScreenDrawer8::Execute, // TextureOpaque + &RectScreenDrawer8::Execute, // TextureMasked + &RectScreenDrawer8::Execute, // TextureAdd + &RectScreenDrawer8::Execute, // TextureSub + &RectScreenDrawer8::Execute, // TextureRevSub + &RectScreenDrawer8::Execute, // TextureAddSrcColor + &RectScreenDrawer8::Execute, // TranslatedOpaque + &RectScreenDrawer8::Execute, // TranslatedMasked + &RectScreenDrawer8::Execute, // TranslatedAdd + &RectScreenDrawer8::Execute, // TranslatedSub + &RectScreenDrawer8::Execute, // TranslatedRevSub + &RectScreenDrawer8::Execute, // TranslatedAddSrcColor + &RectScreenDrawer8::Execute, // Shaded + &RectScreenDrawer8::Execute, // AddShaded + &RectScreenDrawer8::Execute, // Stencil + &RectScreenDrawer8::Execute, // AddStencil + &RectScreenDrawer8::Execute, // FillOpaque + &RectScreenDrawer8::Execute, // FillAdd + &RectScreenDrawer8::Execute, // FillSub + &RectScreenDrawer8::Execute, // FillRevSub + &RectScreenDrawer8::Execute, // FillAddSrcColor + &RectScreenDrawer8::Execute // Skycap +}; + +#ifdef NO_SSE + +void(*ScreenTriangle::RectDrawers32[])(const void *, int, int, int, const RectDrawArgs *, WorkerThreadData *) = +{ + nullptr +}; + +#else + +void(*ScreenTriangle::RectDrawers32[])(const void *, int, int, int, const RectDrawArgs *, WorkerThreadData *) = { - &TriScreenDrawer32::Execute, // "Copy", "opaque", false - &TriScreenDrawer32::Execute, // "AlphaBlend", "masked", false - &TriScreenDrawer32::Execute, // "AddSolid", "translucent", false - &TriScreenDrawer32::Execute, // "Add", "add", false - &TriScreenDrawer32::Execute, // "Sub", "sub", false - &TriScreenDrawer32::Execute, // "RevSub", "revsub", false - &TriScreenDrawer32::Execute, // "Stencil", "stencil", false - &TriScreenDrawer32::Execute, // "Shaded", "shaded", false - &TriScreenDrawer32::Execute, // "TranslateCopy", "opaque", true - &TriScreenDrawer32::Execute, // "TranslateAlphaBlend", "masked", true - &TriScreenDrawer32::Execute, // "TranslateAdd", "add", true - &TriScreenDrawer32::Execute, // "TranslateSub", "sub", true - &TriScreenDrawer32::Execute, // "TranslateRevSub", "revsub", true - &TriScreenDrawer32::Execute, // "AddSrcColorOneMinusSrcColor", "addsrccolor", false - &TriScreenDrawer32::Execute // "Skycap", "skycap", false + &RectScreenDrawer32::Execute, // TextureOpaque + &RectScreenDrawer32::Execute, // TextureMasked + &RectScreenDrawer32::Execute, // TextureAdd + &RectScreenDrawer32::Execute, // TextureSub + &RectScreenDrawer32::Execute, // TextureRevSub + &RectScreenDrawer32::Execute, // TextureAddSrcColor + &RectScreenDrawer32::Execute, // TranslatedOpaque + &RectScreenDrawer32::Execute, // TranslatedMasked + &RectScreenDrawer32::Execute, // TranslatedAdd + &RectScreenDrawer32::Execute, // TranslatedSub + &RectScreenDrawer32::Execute, // TranslatedRevSub + &RectScreenDrawer32::Execute, // TranslatedAddSrcColor + &RectScreenDrawer32::Execute, // Shaded + &RectScreenDrawer32::Execute, // AddShaded + &RectScreenDrawer32::Execute, // Stencil + &RectScreenDrawer32::Execute, // AddStencil + &RectScreenDrawer32::Execute, // FillOpaque + &RectScreenDrawer32::Execute, // FillAdd + &RectScreenDrawer32::Execute, // FillSub + &RectScreenDrawer32::Execute, // FillRevSub + &RectScreenDrawer32::Execute, // FillAddSrcColor + &RectScreenDrawer32::Execute // Skycap }; #endif diff --git a/src/polyrenderer/drawers/screen_triangle.h b/src/polyrenderer/drawers/screen_triangle.h index 81d7cdb68..ab1364990 100644 --- a/src/polyrenderer/drawers/screen_triangle.h +++ b/src/polyrenderer/drawers/screen_triangle.h @@ -61,11 +61,10 @@ struct WorkerThreadData struct TriVertex { TriVertex() { } - TriVertex(float x, float y, float z, float w, float u, float v) : x(x), y(y), z(z), w(w) { varying[0] = u; varying[1] = v; } + TriVertex(float x, float y, float z, float w, float u, float v) : x(x), y(y), z(z), w(w), u(u), v(v) { } - enum { NumVarying = 2 }; float x, y, z, w; - float varying[NumVarying]; + float u, v; }; struct TriDrawTriangleArgs @@ -86,27 +85,34 @@ struct TriDrawTriangleArgs const PolyDrawArgs *uniforms; }; +class RectDrawArgs; + enum class TriBlendMode { - Copy, // blend_copy(shade(fg)) - AlphaBlend, // blend_alpha_blend(shade(fg), bg) - AddSolid, // blend_add(shade(fg), bg, srcalpha, destalpha) - Add, // blend_add(shade(fg), bg, srcalpha, calc_blend_bgalpha(fg, destalpha)) - Sub, // blend_sub(shade(fg), bg, srcalpha, calc_blend_bgalpha(fg, destalpha)) - RevSub, // blend_revsub(shade(fg), bg, srcalpha, calc_blend_bgalpha(fg, destalpha)) - Stencil, // blend_stencil(shade(color), fg.a, bg, srcalpha, calc_blend_bgalpha(fg, destalpha)) - Shaded, // blend_stencil(shade(color), fg.index, bg, srcalpha, calc_blend_bgalpha(fg, destalpha)) - TranslateCopy, // blend_copy(shade(translate(fg))) - TranslateAlphaBlend, // blend_alpha_blend(shade(translate(fg)), bg) - TranslateAdd, // blend_add(shade(translate(fg)), bg, srcalpha, calc_blend_bgalpha(fg, destalpha)) - TranslateSub, // blend_sub(shade(translate(fg)), bg, srcalpha, calc_blend_bgalpha(fg, destalpha)) - TranslateRevSub,// blend_revsub(shade(translate(fg)), bg, srcalpha, calc_blend_bgalpha(fg, destalpha)) - AddSrcColorOneMinusSrcColor, // glBlendMode(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR) used by GZDoom's fullbright additive sprites - Skycap // Fade to sky color when the V texture coordinate go beyond the [-1, 1] range + TextureOpaque, + TextureMasked, + TextureAdd, + TextureSub, + TextureRevSub, + TextureAddSrcColor, + TranslatedOpaque, + TranslatedMasked, + TranslatedAdd, + TranslatedSub, + TranslatedRevSub, + TranslatedAddSrcColor, + Shaded, + AddShaded, + Stencil, + AddStencil, + FillOpaque, + FillAdd, + FillSub, + FillRevSub, + FillAddSrcColor, + Skycap }; -inline int NumTriBlendModes() { return (int)TriBlendMode::Skycap + 1; } - class ScreenTriangle { public: @@ -115,16 +121,15 @@ public: static void StencilWrite(const TriDrawTriangleArgs *args, WorkerThreadData *thread); static void SubsectorWrite(const TriDrawTriangleArgs *args, WorkerThreadData *thread); - static std::vector TriDraw8; - static std::vector TriDraw32; - static std::vector TriFill8; - static std::vector TriFill32; + static void(*TriDrawers8[])(const TriDrawTriangleArgs *, WorkerThreadData *); + static void(*TriDrawers32[])(const TriDrawTriangleArgs *, WorkerThreadData *); + static void(*RectDrawers8[])(const void *, int, int, int, const RectDrawArgs *, WorkerThreadData *); + static void(*RectDrawers32[])(const void *, int, int, int, const RectDrawArgs *, WorkerThreadData *); }; struct ScreenTriangleStepVariables { - float W; - float Varying[TriVertex::NumVarying]; + float W, U, V; }; namespace TriScreenDrawerModes @@ -147,10 +152,11 @@ namespace TriScreenDrawerModes struct SimpleShade { static const int Mode = (int)ShadeMode::Simple; }; struct AdvancedShade { static const int Mode = (int)ShadeMode::Advanced; }; - enum class Samplers { Texture, Fill, Shaded, Translated, Skycap }; + enum class Samplers { Texture, Fill, Shaded, Stencil, Translated, Skycap }; struct TextureSampler { static const int Mode = (int)Samplers::Texture; }; struct FillSampler { static const int Mode = (int)Samplers::Fill; }; struct ShadedSampler { static const int Mode = (int)Samplers::Shaded; }; + struct StencilSampler { static const int Mode = (int)Samplers::Stencil; }; struct TranslatedSampler { static const int Mode = (int)Samplers::Translated; }; struct SkycapSampler { static const int Mode = (int)Samplers::Skycap; }; } diff --git a/src/polyrenderer/math/tri_matrix.cpp b/src/polyrenderer/math/tri_matrix.cpp index b50e7bb6c..f6bb03a5e 100644 --- a/src/polyrenderer/math/tri_matrix.cpp +++ b/src/polyrenderer/math/tri_matrix.cpp @@ -199,7 +199,7 @@ ShadedTriVertex TriMatrix::operator*(TriVertex v) const ShadedTriVertex sv; _mm_storeu_ps(&sv.x, mv); #endif - for (int i = 0; i < TriVertex::NumVarying; i++) - sv.varying[i] = v.varying[i]; + sv.u = v.u; + sv.v = v.v; return sv; } diff --git a/src/polyrenderer/poly_renderer.cpp b/src/polyrenderer/poly_renderer.cpp index 1fb6de710..9cf282454 100644 --- a/src/polyrenderer/poly_renderer.cpp +++ b/src/polyrenderer/poly_renderer.cpp @@ -63,7 +63,6 @@ void PolyRenderer::RenderView(player_t *player) int width = SCREENWIDTH; int height = SCREENHEIGHT; - int stHeight = gST_Y; float trueratio; ActiveRatio(width, height, &trueratio); //viewport->SetViewport(&Thread, width, height, trueratio); diff --git a/src/polyrenderer/scene/poly_decal.cpp b/src/polyrenderer/scene/poly_decal.cpp index 829f444b6..bbda32b04 100644 --- a/src/polyrenderer/scene/poly_decal.cpp +++ b/src/polyrenderer/scene/poly_decal.cpp @@ -123,10 +123,10 @@ void RenderPolyDecal::Render(const TriMatrix &worldToClip, const PolyClipPlane & vertices[i].y = (float)p.Y; vertices[i].z = (float)(zpos + spriteHeight * offsets[i].second - spriteHeight * 0.5); vertices[i].w = 1.0f; - vertices[i].varying[0] = (float)(offsets[i].first * tex->Scale.X); - vertices[i].varying[1] = (float)((1.0f - offsets[i].second) * tex->Scale.Y); + vertices[i].u = (float)(offsets[i].first * tex->Scale.X); + vertices[i].v = (float)((1.0f - offsets[i].second) * tex->Scale.Y); if (flipTextureX) - vertices[i].varying[0] = 1.0f - vertices[i].varying[0]; + vertices[i].u = 1.0f - vertices[i].u; } bool fullbrightSprite = (decal->RenderFlags & RF_FULLBRIGHT) == RF_FULLBRIGHT; @@ -134,10 +134,9 @@ void RenderPolyDecal::Render(const TriMatrix &worldToClip, const PolyClipPlane & PolyDrawArgs args; args.SetLight(GetColorTable(front->Colormap), lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), fullbrightSprite); - args.SetTexture(tex, decal->Translation, true); args.SetSubsectorDepth(subsectorDepth); args.SetColor(0xff000000 | decal->AlphaColor, decal->AlphaColor >> 24); - args.SetStyle(TriBlendMode::Shaded, decal->Alpha, 1.0 - decal->Alpha); // R_SetPatchStyle (decal->RenderStyle, (float)decal->Alpha, decal->Translation, decal->AlphaColor); + args.SetStyle(decal->RenderStyle, decal->Alpha, decal->AlphaColor, decal->Translation, tex, false); args.SetTransform(&worldToClip); args.SetFaceCullCCW(true); args.SetStencilTestValue(stencilValue); diff --git a/src/polyrenderer/scene/poly_particle.cpp b/src/polyrenderer/scene/poly_particle.cpp index d4a49334b..ab80400dd 100644 --- a/src/polyrenderer/scene/poly_particle.cpp +++ b/src/polyrenderer/scene/poly_particle.cpp @@ -29,6 +29,8 @@ #include "polyrenderer/poly_renderer.h" #include "polyrenderer/scene/poly_light.h" +EXTERN_CVAR(Int, gl_particles_style) + void RenderPolyParticle::Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, particle_t *particle, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue) { DVector3 pos = particle->Pos; @@ -64,8 +66,8 @@ void RenderPolyParticle::Render(const TriMatrix &worldToClip, const PolyClipPlan vertices[i].y = (float)p.Y; vertices[i].z = (float)(zpos + psize * (2.0 * offsets[i].second - 1.0)); vertices[i].w = 1.0f; - vertices[i].varying[0] = (float)(offsets[i].first); - vertices[i].varying[1] = (float)(1.0f - offsets[i].second); + vertices[i].u = (float)(offsets[i].first); + vertices[i].v = (float)(1.0f - offsets[i].second); } bool fullbrightSprite = particle->bright != 0; @@ -76,12 +78,40 @@ void RenderPolyParticle::Render(const TriMatrix &worldToClip, const PolyClipPlan args.SetSubsectorDepth(subsectorDepth); args.SetSubsectorDepthTest(true); args.SetColor(particle->color | 0xff000000, particle->color >> 24); - args.SetStyle(TriBlendMode::AlphaBlend, particle->alpha, 1.0 - particle->alpha); + args.SetStyle(TriBlendMode::Shaded, particle->alpha, 1.0 - particle->alpha); args.SetTransform(&worldToClip); args.SetFaceCullCCW(true); args.SetStencilTestValue(stencilValue); args.SetWriteStencil(false); args.SetWriteSubsectorDepth(false); args.SetClipPlane(clipPlane); + args.SetTexture(GetParticleTexture(), ParticleTextureSize, ParticleTextureSize); args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan); } + +uint8_t *RenderPolyParticle::GetParticleTexture() +{ + static uint8_t particle_texture[NumParticleTextures][ParticleTextureSize * ParticleTextureSize]; + static bool first_call = true; + if (first_call) + { + double center = ParticleTextureSize * 0.5f; + for (int y = 0; y < ParticleTextureSize; y++) + { + for (int x = 0; x < ParticleTextureSize; x++) + { + double dx = (center - x - 0.5f) / center; + double dy = (center - y - 0.5f) / center; + double dist2 = dx * dx + dy * dy; + double round_alpha = clamp(1.7f - dist2 * 1.7f, 0.0f, 1.0f); + double smooth_alpha = clamp(1.1f - dist2 * 1.1f, 0.0f, 1.0f); + + particle_texture[0][x + y * ParticleTextureSize] = 255; + particle_texture[1][x + y * ParticleTextureSize] = (int)(round_alpha * 255.0f + 0.5f); + particle_texture[2][x + y * ParticleTextureSize] = (int)(smooth_alpha * 255.0f + 0.5f); + } + } + first_call = false; + } + return particle_texture[MIN(gl_particles_style, NumParticleTextures)]; +} diff --git a/src/polyrenderer/scene/poly_particle.h b/src/polyrenderer/scene/poly_particle.h index e91174591..a5cc3d0d0 100644 --- a/src/polyrenderer/scene/poly_particle.h +++ b/src/polyrenderer/scene/poly_particle.h @@ -29,4 +29,13 @@ class RenderPolyParticle { public: void Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, particle_t *particle, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue); + +private: + static uint8_t *GetParticleTexture(); + + enum + { + NumParticleTextures = 3, + ParticleTextureSize = 64 + }; }; diff --git a/src/polyrenderer/scene/poly_plane.cpp b/src/polyrenderer/scene/poly_plane.cpp index d41328d57..d4cd0fb02 100644 --- a/src/polyrenderer/scene/poly_plane.cpp +++ b/src/polyrenderer/scene/poly_plane.cpp @@ -133,7 +133,7 @@ void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, const PolyClip args.SetLight(GetColorTable(sub->sector->Colormap), lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false); args.SetSubsectorDepth(subsectorDepth); args.SetTransform(&worldToClip); - args.SetStyle(TriBlendMode::Copy); + args.SetStyle(TriBlendMode::TextureOpaque); args.SetFaceCullCCW(true); args.SetStencilTestValue(stencilValue); args.SetWriteStencil(true, stencilValue + 1); @@ -312,7 +312,7 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const PolyClipPlane & if (!isSky) { args.SetTexture(tex); - args.SetStyle(TriBlendMode::Copy); + args.SetStyle(TriBlendMode::TextureOpaque); args.DrawArray(vertices, sub->numlines, PolyDrawMode::TriangleFan); } else @@ -410,8 +410,8 @@ TriVertex RenderPolyPlane::PlaneVertex(vertex_t *v1, double height, const UVTran v.y = (float)v1->fPos().Y; v.z = (float)height; v.w = 1.0f; - v.varying[0] = transform.GetU(v.x, v.y); - v.varying[1] = transform.GetV(v.x, v.y); + v.u = transform.GetU(v.x, v.y); + v.v = transform.GetV(v.x, v.y); return v; } diff --git a/src/polyrenderer/scene/poly_playersprite.cpp b/src/polyrenderer/scene/poly_playersprite.cpp index 9920d2dc9..360af43bc 100644 --- a/src/polyrenderer/scene/poly_playersprite.cpp +++ b/src/polyrenderer/scene/poly_playersprite.cpp @@ -576,52 +576,28 @@ fixed_t RenderPolyPlayerSprites::LightLevelToShade(int lightlevel, bool foggy) void PolyNoAccelPlayerSprite::Render() { -#if 0 if (xscale == 0 || fabs(yscale) < (1.0f / 32000.0f)) { // scaled to 0; can't see return; } - SpriteDrawerArgs drawerargs; - drawerargs.SetLight(Light.BaseColormap, 0, Light.ColormapNum << FRACBITS); - - FDynamicColormap *basecolormap = static_cast(Light.BaseColormap); - - bool visible = drawerargs.SetStyle(RenderStyle, Alpha, Translation, FillColor, basecolormap, Light.ColormapNum << FRACBITS); - if (!visible) - return; - - double spryscale = yscale; - bool sprflipvert = false; - fixed_t iscale = FLOAT2FIXED(1 / yscale); + RectDrawArgs args; + args.SetStyle(RenderStyle, Alpha, FillColor, Translation, pic, false); + args.SetLight(Light.BaseColormap, 255 - (Light.ColormapNum << 3)); double centerY = viewheight / 2; - - double sprtopscreen; + double y1, y2; if (renderflags & RF_YFLIP) { - sprflipvert = true; - spryscale = -spryscale; - iscale = -iscale; - sprtopscreen = centerY + (texturemid - pic->GetHeight()) * spryscale; + y1 = centerY + (texturemid - pic->GetHeight()) * (-yscale); + y2 = y1 + pic->GetHeight() * (-yscale); } else { - sprflipvert = false; - sprtopscreen = centerY - texturemid * spryscale; + y1 = centerY - texturemid * yscale; + y2 = y1 + pic->GetHeight() * yscale; } - - // clip to screen bounds - short *mfloorclip = screenheightarray; - short *mceilingclip = zeroarray; - - fixed_t frac = startfrac; - for (int x = x1; x < x2; x++) - { - drawerargs.DrawMaskedColumn(x, iscale, pic, frac, spryscale, sprtopscreen, sprflipvert, mfloorclip, mceilingclip, false); - frac += xiscale; - } -#endif + args.Draw(x1, x2, y1, y2, 0.0f, 1.0f, 0.0f, 1.0f); } ///////////////////////////////////////////////////////////////////////////// diff --git a/src/polyrenderer/scene/poly_scene.cpp b/src/polyrenderer/scene/poly_scene.cpp index 3aeda994c..a655ca845 100644 --- a/src/polyrenderer/scene/poly_scene.cpp +++ b/src/polyrenderer/scene/poly_scene.cpp @@ -253,7 +253,7 @@ void RenderPolyScene::RenderPortals(int portalDepth) args.SetLight(&NormalLight, 255, PolyRenderer::Instance()->Light.WallGlobVis(foggy), true); args.SetColor(0, 0); args.SetClipPlane(PortalPlane); - args.SetStyle(TriBlendMode::Copy); + args.SetStyle(TriBlendMode::FillOpaque); for (auto &portal : SectorPortals) { diff --git a/src/polyrenderer/scene/poly_sky.cpp b/src/polyrenderer/scene/poly_sky.cpp index 374163f96..7cb322032 100644 --- a/src/polyrenderer/scene/poly_sky.cpp +++ b/src/polyrenderer/scene/poly_sky.cpp @@ -70,18 +70,20 @@ void PolySkyDome::Render(const TriMatrix &worldToClip) uint32_t topcapcolor = frontskytex->GetSkyCapColor(false); uint32_t bottomcapcolor = frontskytex->GetSkyCapColor(true); + uint8_t topcapindex = RGB256k.All[((RPART(topcapcolor) >> 2) << 12) | ((GPART(topcapcolor) >> 2) << 6) | (BPART(topcapcolor) >> 2)]; + uint8_t bottomcapindex = RGB256k.All[((RPART(bottomcapcolor) >> 2) << 12) | ((GPART(bottomcapcolor) >> 2) << 6) | (BPART(bottomcapcolor) >> 2)]; for (int i = 1; i <= mRows; i++) { - RenderRow(args, i, topcapcolor); - RenderRow(args, rc + i, bottomcapcolor); + RenderRow(args, i, topcapcolor, topcapindex); + RenderRow(args, rc + i, bottomcapcolor, bottomcapindex); } } -void PolySkyDome::RenderRow(PolyDrawArgs &args, int row, uint32_t capcolor) +void PolySkyDome::RenderRow(PolyDrawArgs &args, int row, uint32_t capcolor, uint8_t capcolorindex) { args.SetFaceCullCCW(false); - args.SetColor(capcolor, 0); + args.SetColor(capcolor, capcolorindex); args.SetStyle(TriBlendMode::Skycap); args.DrawArray(&mVertices[mPrimStart[row]], mPrimStart[row + 1] - mPrimStart[row], PolyDrawMode::TriangleStrip); } @@ -93,7 +95,7 @@ void PolySkyDome::RenderCapColorRow(PolyDrawArgs &args, FTexture *skytex, int ro args.SetFaceCullCCW(bottomCap); args.SetColor(solid, palsolid); - args.SetStyle(TriBlendMode::Copy); + args.SetStyle(TriBlendMode::FillOpaque); args.DrawArray(&mVertices[mPrimStart[row]], mPrimStart[row + 1] - mPrimStart[row], PolyDrawMode::TriangleFan); } @@ -137,8 +139,8 @@ TriVertex PolySkyDome::SetVertexXYZ(float xx, float yy, float zz, float uu, floa v.y = zz; v.z = yy; v.w = 1.0f; - v.varying[0] = uu; - v.varying[1] = vv; + v.u = uu; + v.v = vv; return v; } diff --git a/src/polyrenderer/scene/poly_sky.h b/src/polyrenderer/scene/poly_sky.h index 1a8cd8ef2..87d6cabce 100644 --- a/src/polyrenderer/scene/poly_sky.h +++ b/src/polyrenderer/scene/poly_sky.h @@ -38,7 +38,7 @@ private: void SkyVertex(int r, int c, bool yflip); void CreateSkyHemisphere(bool zflip); void CreateDome(); - void RenderRow(PolyDrawArgs &args, int row, uint32_t capcolor); + void RenderRow(PolyDrawArgs &args, int row, uint32_t capcolor, uint8_t capcolorindex); void RenderCapColorRow(PolyDrawArgs &args, FTexture *skytex, int row, bool bottomCap); TriVertex SetVertexXYZ(float xx, float yy, float zz, float uu = 0, float vv = 0); diff --git a/src/polyrenderer/scene/poly_sprite.cpp b/src/polyrenderer/scene/poly_sprite.cpp index 2a98af721..ae7295f1e 100644 --- a/src/polyrenderer/scene/poly_sprite.cpp +++ b/src/polyrenderer/scene/poly_sprite.cpp @@ -128,10 +128,10 @@ void RenderPolySprite::Render(const TriMatrix &worldToClip, const PolyClipPlane vertices[i].y = (float)p.Y; vertices[i].z = (float)(pos.Z + spriteHeight * offsets[i].second); vertices[i].w = 1.0f; - vertices[i].varying[0] = (float)(offsets[i].first * tex->Scale.X); - vertices[i].varying[1] = (float)((1.0f - offsets[i].second) * tex->Scale.Y); + vertices[i].u = (float)(offsets[i].first * tex->Scale.X); + vertices[i].v = (float)((1.0f - offsets[i].second) * tex->Scale.Y); if (flipTextureX) - vertices[i].varying[0] = 1.0f - vertices[i].varying[0]; + vertices[i].u = 1.0f - vertices[i].u; } bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT)); @@ -144,67 +144,8 @@ void RenderPolySprite::Render(const TriMatrix &worldToClip, const PolyClipPlane args.SetFaceCullCCW(true); args.SetStencilTestValue(stencilValue); args.SetWriteStencil(true, stencilValue); - args.SetTexture(tex, thing->Translation); args.SetClipPlane(clipPlane); - - if (thing->RenderStyle == LegacyRenderStyles[STYLE_Normal] || - (r_drawfuzz == 0 && thing->RenderStyle == LegacyRenderStyles[STYLE_OptFuzzy])) - { - args.SetStyle(args.Translation() ? TriBlendMode::TranslateAdd : TriBlendMode::Add, 1.0, 0.0); - } - else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Add] && fullbrightSprite && thing->Alpha == 1.0 && !args.Translation()) - { - args.SetStyle(TriBlendMode::AddSrcColorOneMinusSrcColor, 1.0, 1.0); - } - else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Add]) - { - args.SetStyle(args.Translation() ? TriBlendMode::TranslateAdd : TriBlendMode::Add, thing->Alpha, 1.0); - } - else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Subtract]) - { - args.SetStyle(args.Translation() ? TriBlendMode::TranslateRevSub : TriBlendMode::RevSub, thing->Alpha, 1.0); - } - else if (thing->RenderStyle == LegacyRenderStyles[STYLE_SoulTrans]) - { - args.SetStyle(args.Translation() ? TriBlendMode::TranslateAdd : TriBlendMode::Add, transsouls, 1.0 - transsouls); - } - else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Fuzzy] || - (r_drawfuzz == 2 && thing->RenderStyle == LegacyRenderStyles[STYLE_OptFuzzy])) - { // NYI - Fuzzy - for now, just a copy of "Shadow" - args.SetStyle(args.Translation() ? TriBlendMode::TranslateAdd : TriBlendMode::Add, 0.0, 160 / 255.0); - } - else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Shadow] || - (r_drawfuzz == 1 && thing->RenderStyle == LegacyRenderStyles[STYLE_OptFuzzy])) - { - args.SetStyle(args.Translation() ? TriBlendMode::TranslateAdd : TriBlendMode::Add, 0.0, 160 / 255.0); - } - else if (thing->RenderStyle == LegacyRenderStyles[STYLE_TranslucentStencil]) - { - args.SetColor(0xff000000 | thing->fillcolor, thing->fillcolor >> 24); - args.SetStyle(TriBlendMode::Stencil, thing->Alpha, 1.0 - thing->Alpha); - } - else if (thing->RenderStyle == LegacyRenderStyles[STYLE_AddStencil]) - { - args.SetColor(0xff000000 | thing->fillcolor, thing->fillcolor >> 24); - args.SetStyle(TriBlendMode::Stencil, thing->Alpha, 1.0 - thing->Alpha); - } - else if (thing->RenderStyle == LegacyRenderStyles[STYLE_Shaded]) - { - args.SetColor(0, 0); - args.SetStyle(TriBlendMode::Shaded, thing->Alpha, 1.0 - thing->Alpha); - args.SetTexture(tex, thing->Translation, true); - } - else if (thing->RenderStyle == LegacyRenderStyles[STYLE_AddShaded]) - { - args.SetColor(0, 0); - args.SetStyle(TriBlendMode::Shaded, thing->Alpha, 1.0 - thing->Alpha); - args.SetTexture(tex, thing->Translation, true); - } - else - { - args.SetStyle(args.Translation() ? TriBlendMode::TranslateAdd : TriBlendMode::Add, thing->Alpha, 1.0 - thing->Alpha); - } - + args.SetStyle(thing->RenderStyle, thing->Alpha, thing->fillcolor, thing->Translation, tex, fullbrightSprite); args.SetSubsectorDepthTest(true); args.SetWriteSubsectorDepth(false); args.SetWriteStencil(false); diff --git a/src/polyrenderer/scene/poly_wall.cpp b/src/polyrenderer/scene/poly_wall.cpp index 263487f70..ae11577e4 100644 --- a/src/polyrenderer/scene/poly_wall.cpp +++ b/src/polyrenderer/scene/poly_wall.cpp @@ -230,14 +230,14 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const PolyClipPlane &c if (tex) { PolyWallTextureCoords texcoords(tex, LineSeg, Line, Side, Texpart, TopZ, BottomZ, UnpeggedCeil); - vertices[0].varying[0] = (float)texcoords.u1; - vertices[0].varying[1] = (float)texcoords.v1; - vertices[1].varying[0] = (float)texcoords.u2; - vertices[1].varying[1] = (float)texcoords.v1; - vertices[2].varying[0] = (float)texcoords.u2; - vertices[2].varying[1] = (float)texcoords.v2; - vertices[3].varying[0] = (float)texcoords.u1; - vertices[3].varying[1] = (float)texcoords.v2; + vertices[0].u = (float)texcoords.u1; + vertices[0].v = (float)texcoords.v1; + vertices[1].u = (float)texcoords.u2; + vertices[1].v = (float)texcoords.v1; + vertices[2].u = (float)texcoords.u2; + vertices[2].v = (float)texcoords.v2; + vertices[3].u = (float)texcoords.u1; + vertices[3].v = (float)texcoords.v2; } // Masked walls clamp to the 0-1 range (no texture repeat) @@ -272,12 +272,15 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const PolyClipPlane &c } else if (!Masked) { - args.SetStyle(TriBlendMode::Copy); + args.SetStyle(TriBlendMode::TextureOpaque); args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan); } else { - args.SetStyle((Line->flags & ML_ADDTRANS) ? TriBlendMode::Add : TriBlendMode::AlphaBlend, Line->alpha, 1.0); + bool addtrans = !!(Line->flags & ML_ADDTRANS); + double srcalpha = MIN(Line->alpha, 1.0); + double destalpha = addtrans ? 1.0 : 1.0 - srcalpha; + args.SetStyle(TriBlendMode::TextureAdd, srcalpha, destalpha); args.SetSubsectorDepthTest(true); args.SetWriteSubsectorDepth(true); args.SetWriteStencil(false); @@ -291,8 +294,8 @@ void RenderPolyWall::ClampHeight(TriVertex &v1, TriVertex &v2) { float top = v1.z; float bottom = v2.z; - float texv1 = v1.varying[1]; - float texv2 = v2.varying[1]; + float texv1 = v1.v; + float texv2 = v2.v; float delta = (texv2 - texv1); float t1 = texv1 < 0.0f ? -texv1 / delta : 0.0f; @@ -301,10 +304,10 @@ void RenderPolyWall::ClampHeight(TriVertex &v1, TriVertex &v2) float inv_t2 = 1.0f - t2; v1.z = top * inv_t1 + bottom * t1; - v1.varying[1] = texv1 * inv_t1 + texv2 * t1; + v1.v = texv1 * inv_t1 + texv2 * t1; v2.z = top * inv_t2 + bottom * t2; - v2.varying[1] = texv1 * inv_t2 + texv2 * t2; + v2.v = texv1 * inv_t2 + texv2 * t2; } FTexture *RenderPolyWall::GetTexture() diff --git a/src/polyrenderer/scene/poly_wallsprite.cpp b/src/polyrenderer/scene/poly_wallsprite.cpp index 8108849b9..d00e6d2bd 100644 --- a/src/polyrenderer/scene/poly_wallsprite.cpp +++ b/src/polyrenderer/scene/poly_wallsprite.cpp @@ -90,10 +90,10 @@ void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, const PolyClipPl vertices[i].y = (float)p.Y; vertices[i].z = (float)(pos.Z + spriteHeight * offsets[i].second); vertices[i].w = 1.0f; - vertices[i].varying[0] = (float)(offsets[i].first * tex->Scale.X); - vertices[i].varying[1] = (float)((1.0f - offsets[i].second) * tex->Scale.Y); + vertices[i].u = (float)(offsets[i].first * tex->Scale.X); + vertices[i].v = (float)((1.0f - offsets[i].second) * tex->Scale.Y); if (flipTextureX) - vertices[i].varying[0] = 1.0f - vertices[i].varying[0]; + vertices[i].u = 1.0f - vertices[i].u; } bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT)); @@ -109,6 +109,6 @@ void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, const PolyClipPl args.SetSubsectorDepthTest(true); args.SetWriteSubsectorDepth(false); args.SetWriteStencil(false); - args.SetStyle(TriBlendMode::AlphaBlend); + args.SetStyle(TriBlendMode::TextureMasked); args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan); } diff --git a/src/portal.cpp b/src/portal.cpp index 1ec92799f..acf6e022d 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -167,7 +167,7 @@ static void BuildBlockmap() void FLinePortalTraverse::AddLineIntercepts(int bx, int by) { - if (by < 0 || by >= PortalBlockmap.dx || bx < 0 || bx >= PortalBlockmap.dy) return; + if (by < 0 || by >= PortalBlockmap.dy || bx < 0 || bx >= PortalBlockmap.dx) return; FPortalBlock &block = PortalBlockmap(bx, by); diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index 084ff52d7..2974866ca 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -508,7 +508,6 @@ public: FxConstant(PType *type, VMValue &vmval, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { - ValueType = value.Type = type; isresolved = true; switch (vmval.Type) { @@ -522,13 +521,14 @@ public: break; case REGT_STRING: - value = ExpVal(vmval.s()); + new(&value) ExpVal(vmval.s()); break; case REGT_POINTER: value.pointer = vmval.a; break; } + ValueType = value.Type = type; } static FxExpression *MakeConstant(PSymbol *sym, const FScriptPosition &pos); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 32363abdc..01a79dfc1 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -488,6 +488,7 @@ static FFlagDef DynLightFlagDefs[] = DEFINE_FLAG(MF4, DONTLIGHTSELF, ADynamicLight, flags4), DEFINE_FLAG(MF4, ATTENUATE, ADynamicLight, flags4), DEFINE_FLAG(MF4, NOSHADOWMAP, ADynamicLight, flags4), + DEFINE_FLAG(MF4, DONTLIGHTACTORS, ADynamicLight, flags4), }; static FFlagDef PowerSpeedFlagDefs[] = diff --git a/src/swrenderer/drawers/r_draw.cpp b/src/swrenderer/drawers/r_draw.cpp index a4467266e..1f7b2d560 100644 --- a/src/swrenderer/drawers/r_draw.cpp +++ b/src/swrenderer/drawers/r_draw.cpp @@ -64,7 +64,7 @@ namespace swrenderer int fuzzpos; int fuzzviewheight; - uint32_t particle_texture[PARTICLE_TEXTURE_SIZE * PARTICLE_TEXTURE_SIZE]; + uint32_t particle_texture[NUM_PARTICLE_TEXTURES][PARTICLE_TEXTURE_SIZE * PARTICLE_TEXTURE_SIZE]; short zeroarray[MAXWIDTH]; short screenheightarray[MAXWIDTH]; @@ -139,6 +139,8 @@ namespace swrenderer void R_InitParticleTexture() { + static_assert(NUM_PARTICLE_TEXTURES == 3, "R_InitParticleTexture must be updated if NUM_PARTICLE_TEXTURES is changed"); + double center = PARTICLE_TEXTURE_SIZE * 0.5f; for (int y = 0; y < PARTICLE_TEXTURE_SIZE; y++) { @@ -147,9 +149,12 @@ namespace swrenderer double dx = (center - x - 0.5f) / center; double dy = (center - y - 0.5f) / center; double dist2 = dx * dx + dy * dy; - double alpha = clamp(1.1f - dist2 * 1.1f, 0.0f, 1.0f); + double round_alpha = clamp(1.7f - dist2 * 1.7f, 0.0f, 1.0f); + double smooth_alpha = clamp(1.1f - dist2 * 1.1f, 0.0f, 1.0f); - particle_texture[x + y * PARTICLE_TEXTURE_SIZE] = (int)(alpha * 128.0f + 0.5f); + particle_texture[0][x + y * PARTICLE_TEXTURE_SIZE] = 128; + particle_texture[1][x + y * PARTICLE_TEXTURE_SIZE] = (int)(round_alpha * 128.0f + 0.5f); + particle_texture[2][x + y * PARTICLE_TEXTURE_SIZE] = (int)(smooth_alpha * 128.0f + 0.5f); } } } diff --git a/src/swrenderer/drawers/r_draw.h b/src/swrenderer/drawers/r_draw.h index 5c37873c8..e9b893aba 100644 --- a/src/swrenderer/drawers/r_draw.h +++ b/src/swrenderer/drawers/r_draw.h @@ -44,8 +44,9 @@ namespace swrenderer extern int fuzzpos; extern int fuzzviewheight; + #define NUM_PARTICLE_TEXTURES 3 #define PARTICLE_TEXTURE_SIZE 64 - extern uint32_t particle_texture[PARTICLE_TEXTURE_SIZE * PARTICLE_TEXTURE_SIZE]; + extern uint32_t particle_texture[NUM_PARTICLE_TEXTURES][PARTICLE_TEXTURE_SIZE * PARTICLE_TEXTURE_SIZE]; class SWPixelFormatDrawers { diff --git a/src/swrenderer/drawers/r_draw_pal.cpp b/src/swrenderer/drawers/r_draw_pal.cpp index 522eb51b1..3f75a30ac 100644 --- a/src/swrenderer/drawers/r_draw_pal.cpp +++ b/src/swrenderer/drawers/r_draw_pal.cpp @@ -48,6 +48,7 @@ // [SP] r_blendmethod - false = rgb555 matching (ZDoom classic), true = rgb666 (refactored) CVAR(Bool, r_blendmethod, false, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) +EXTERN_CVAR(Int, gl_particles_style) /* [RH] This translucency algorithm is based on DOSDoom 0.65's, but uses @@ -2946,7 +2947,8 @@ namespace swrenderer uint8_t *dest = thread->dest_for_thread(_dest_y, pitch, _dest); pitch = pitch * thread->num_cores; - const uint32_t *source = &particle_texture[(_fracposx >> FRACBITS) * PARTICLE_TEXTURE_SIZE]; + int particle_texture_index = MIN(gl_particles_style, NUM_PARTICLE_TEXTURES - 1); + const uint32_t *source = &particle_texture[particle_texture_index][(_fracposx >> FRACBITS) * PARTICLE_TEXTURE_SIZE]; uint32_t particle_alpha = _alpha; uint32_t fracstep = PARTICLE_TEXTURE_SIZE * FRACUNIT / _count; diff --git a/src/swrenderer/drawers/r_draw_rgba.cpp b/src/swrenderer/drawers/r_draw_rgba.cpp index 453071eae..3dbd38f46 100644 --- a/src/swrenderer/drawers/r_draw_rgba.cpp +++ b/src/swrenderer/drawers/r_draw_rgba.cpp @@ -780,7 +780,8 @@ namespace swrenderer uint32_t *dest = thread->dest_for_thread(_dest_y, _pitch, _dest); int pitch = _pitch * thread->num_cores; - const uint32_t *source = &particle_texture[(_fracposx >> FRACBITS) * PARTICLE_TEXTURE_SIZE]; + int particle_texture_index = MIN(gl_particles_style, NUM_PARTICLE_TEXTURES - 1); + const uint32_t *source = &particle_texture[particle_texture_index][(_fracposx >> FRACBITS) * PARTICLE_TEXTURE_SIZE]; uint32_t particle_alpha = _alpha; uint32_t fracstep = PARTICLE_TEXTURE_SIZE * FRACUNIT / _count; diff --git a/src/swrenderer/line/r_walldraw.cpp b/src/swrenderer/line/r_walldraw.cpp index bf8d856e9..f07a63bb8 100644 --- a/src/swrenderer/line/r_walldraw.cpp +++ b/src/swrenderer/line/r_walldraw.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "doomdef.h" #include "doomstat.h" @@ -99,7 +100,7 @@ namespace swrenderer v = v - floor(v); double v_step = uv_stepd / texture->GetHeight(); - if (isnan(v) || isnan(v_step)) // this should never happen, but it apparently does.. + if (std::isnan(v) || std::isnan(v_step)) // this should never happen, but it apparently does.. { uv_stepd = 0.0; v = 0.0; diff --git a/src/swrenderer/things/r_sprite.cpp b/src/swrenderer/things/r_sprite.cpp index 2e8a0f3aa..c98e9dcc6 100644 --- a/src/swrenderer/things/r_sprite.cpp +++ b/src/swrenderer/things/r_sprite.cpp @@ -237,7 +237,7 @@ namespace swrenderer while (node != nullptr) { ADynamicLight *light = node->lightsource; - if (light->visibletoplayer && !(light->flags2&MF2_DORMANT) && (!(light->flags4&MF4_DONTLIGHTSELF) || light->target != thing)) + if (light->visibletoplayer && !(light->flags2&MF2_DORMANT) && (!(light->flags4&MF4_DONTLIGHTSELF) || light->target != thing) && !(light->flags4&MF4_DONTLIGHTACTORS)) { float lx = (float)(light->X() - thing->X()); float ly = (float)(light->Y() - thing->Y()); diff --git a/src/textures/shadertexture.cpp b/src/textures/shadertexture.cpp new file mode 100644 index 000000000..93e423470 --- /dev/null +++ b/src/textures/shadertexture.cpp @@ -0,0 +1,133 @@ +/* +** shadertexture.cpp +** +** simple shader gradient textures, used by the status bars. +** +**--------------------------------------------------------------------------- +** Copyright 2008 Braden Obrzut +** Copyright 2017 Christoph Oelckers +** 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 "doomtype.h" +#include "doomstat.h" +#include "d_player.h" +#include "templates.h" +#include "menu/menu.h" +#include "colormatcher.h" +#include "textures/textures.h" +#include "w_wad.h" +#include "v_font.h" +#include "v_video.h" +#include "g_level.h" +#include "gi.h" +#include "r_defs.h" +#include "r_state.h" +#include "r_data/r_translate.h" + + +class FBarShader : public FTexture +{ +public: + FBarShader(bool vertical, bool reverse) + { + int i; + + Name.Format("BarShader%c%c", vertical ? 'v' : 'h', reverse ? 'r' : 'f'); + Width = vertical ? 2 : 256; + Height = vertical ? 256 : 2; + CalcBitSize(); + + // Fill the column/row with shading values. + // Vertical shaders have have minimum alpha at the top + // and maximum alpha at the bottom, unless flipped by + // setting reverse to true. Horizontal shaders are just + // the opposite. + if (vertical) + { + if (!reverse) + { + for (i = 0; i < 256; ++i) + { + Pixels[i] = i; + Pixels[256+i] = i; + } + } + else + { + for (i = 0; i < 256; ++i) + { + Pixels[i] = 255 - i; + Pixels[256+i] = 255 -i; + } + } + } + else + { + if (!reverse) + { + for (i = 0; i < 256; ++i) + { + Pixels[i*2] = 255 - i; + Pixels[i*2+1] = 255 - i; + } + } + else + { + for (i = 0; i < 256; ++i) + { + Pixels[i*2] = i; + Pixels[i*2+1] = i; + } + } + } + DummySpan[0].TopOffset = 0; + DummySpan[0].Length = vertical ? 256 : 2; + DummySpan[1].TopOffset = 0; + DummySpan[1].Length = 0; + } + const uint8_t *GetColumn(unsigned int column, const Span **spans_out) + { + if (spans_out != NULL) + { + *spans_out = DummySpan; + } + return Pixels + ((column & WidthMask) << HeightBits); + } + const uint8_t *GetPixels() { return Pixels; } + void Unload() {} +private: + uint8_t Pixels[512]; + Span DummySpan[2]; +}; + + +FTexture *CreateShaderTexture(bool vertical, bool reverse) +{ + return new FBarShader(vertical, reverse); +} diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index 1601660c7..2bd779865 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -977,6 +977,7 @@ void FTextureManager::SortTexturesByType(int start, int end) // //========================================================================== FTexture *GetBackdropTexture(); +FTexture *CreateShaderTexture(bool, bool); void FTextureManager::Init() { @@ -988,7 +989,12 @@ void FTextureManager::Init() // Texture 0 is a dummy texture used to indicate "no texture" AddTexture (new FDummyTexture); + // some special textures used in the game. AddTexture(GetBackdropTexture()); + AddTexture(CreateShaderTexture(false, false)); + AddTexture(CreateShaderTexture(false, true)); + AddTexture(CreateShaderTexture(true, false)); + AddTexture(CreateShaderTexture(true, true)); int wadcnt = Wads.GetNumWads(); for(int i = 0; i< wadcnt; i++) diff --git a/src/v_draw.cpp b/src/v_draw.cpp index d06628d43..a45cbddac 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -137,6 +137,8 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawTexture) PARAM_FLOAT(x); PARAM_FLOAT(y); + if (!screen->IsLocked()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + FTexture *tex = animate ? TexMan(FSetTextureID(texid)) : TexMan[FSetTextureID(texid)]; VMVa_List args = { param + 4, 0, numparam - 4 }; screen->DrawTexture(tex, x, y, args); @@ -155,6 +157,22 @@ void DCanvas::DrawTextureParms(FTexture *img, DrawParms &parms) } } +void DCanvas::SetClipRect(int x, int y, int w, int h) +{ + clipleft = clamp(x, 0, GetWidth()); + clipwidth = clamp(w, 0, GetWidth() - x); + cliptop = clamp(y, 0, GetHeight()); + clipwidth = clamp(w, 0, GetHeight() - y); +} + +void DCanvas::GetClipRect(int *x, int *y, int *w, int *h) +{ + if (x) *x = clipleft; + if (y) *y = cliptop; + if (w) *w = clipwidth; + if (h) *h = clipheight; +} + bool DCanvas::SetTextureParms(DrawParms *parms, FTexture *img, double xx, double yy) const { if (img != NULL) @@ -692,6 +710,15 @@ bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, uint32_t t parms->remap = nullptr; } + // intersect with the canvas's clipping rectangle. + if (clipwidth >= 0 && clipheight >= 0) + { + if (parms->lclip < clipleft) parms->lclip = clipleft; + if (parms->rclip > clipleft + clipwidth) parms->rclip = clipleft + clipwidth; + if (parms->uclip < cliptop) parms->uclip = cliptop; + if (parms->dclip < cliptop + clipheight) parms->uclip = cliptop + clipheight; + } + if (parms->uclip >= parms->dclip || parms->lclip >= parms->rclip) { return false; @@ -800,22 +827,6 @@ DEFINE_ACTION_FUNCTION(_Screen, VirtualToRealCoords) return MIN(numret, 2); } -void DCanvas::VirtualToRealCoordsFixed(fixed_t &x, fixed_t &y, fixed_t &w, fixed_t &h, - int vwidth, int vheight, bool vbottom, bool handleaspect) const -{ - double dx, dy, dw, dh; - - dx = FIXED2DBL(x); - dy = FIXED2DBL(y); - dw = FIXED2DBL(w); - dh = FIXED2DBL(h); - VirtualToRealCoords(dx, dy, dw, dh, vwidth, vheight, vbottom, handleaspect); - x = FLOAT2FIXED(dx); - y = FLOAT2FIXED(dy); - w = FLOAT2FIXED(dw); - h = FLOAT2FIXED(dh); -} - void DCanvas::VirtualToRealCoordsInt(int &x, int &y, int &w, int &h, int vwidth, int vheight, bool vbottom, bool handleaspect) const { @@ -900,7 +911,7 @@ void DCanvas::DrawPixel(int x, int y, int palColor, uint32_t realcolor) // //========================================================================== -void DCanvas::Clear (int left, int top, int right, int bottom, int palcolor, uint32_t color) +void DCanvas::DoClear (int left, int top, int right, int bottom, int palcolor, uint32_t color) { #ifndef NO_SWRENDER if (palcolor < 0 && APART(color) != 255) @@ -914,6 +925,33 @@ void DCanvas::Clear (int left, int top, int right, int bottom, int palcolor, uin #endif } +void DCanvas::Clear(int left, int top, int right, int bottom, int palcolor, uint32_t color) +{ + if (clipwidth >= 0 && clipheight >= 0) + { + int w = right - left; + int h = bottom - top; + if (left < clipleft) + { + w -= (clipleft - left); + left = clipleft; + } + if (w > clipwidth) w = clipwidth; + if (w <= 0) return; + + if (top < cliptop) + { + h -= (cliptop - top); + top = cliptop; + } + if (h > clipheight) w = clipheight; + if (h <= 0) return; + right = left + w; + bottom = top + h; + } + DoClear(left, top, right, bottom, palcolor, color); +} + DEFINE_ACTION_FUNCTION(_Screen, Clear) { PARAM_PROLOGUE; @@ -923,6 +961,7 @@ DEFINE_ACTION_FUNCTION(_Screen, Clear) PARAM_INT(y2); PARAM_INT(color); PARAM_INT_DEF(palcol); + if (!screen->IsLocked()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); screen->Clear(x1, y1, x2, y2, palcol, color); return 0; } @@ -935,13 +974,50 @@ DEFINE_ACTION_FUNCTION(_Screen, Clear) // //========================================================================== -void DCanvas::Dim(PalEntry color, float damount, int x1, int y1, int w, int h) +void DCanvas::DoDim(PalEntry color, float damount, int x1, int y1, int w, int h) { #ifndef NO_SWRENDER SWCanvas::Dim(this, color, damount, x1, y1, w, h); #endif } +void DCanvas::Dim(PalEntry color, float damount, int x1, int y1, int w, int h) +{ + if (clipwidth >= 0 && clipheight >= 0) + { + if (x1 < clipleft) + { + w -= (clipleft - x1); + x1 = clipleft; + } + if (w > clipwidth) w = clipwidth; + if (w <= 0) return; + + if (y1 < cliptop) + { + h -= (cliptop - y1); + y1 = cliptop; + } + if (h > clipheight) w = clipheight; + if (h <= 0) return; + } + DoDim(color, damount, x1, y1, w, h); +} + +DEFINE_ACTION_FUNCTION(_Screen, Dim) +{ + PARAM_PROLOGUE; + PARAM_INT(color); + PARAM_FLOAT(amount); + PARAM_INT(x1); + PARAM_INT(y1); + PARAM_INT(w); + PARAM_INT(h); + if (!screen->IsLocked()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + screen->Dim(color, float(amount), x1, y1, w, h); + return 0; +} + //========================================================================== // // DCanvas :: FillSimplePoly diff --git a/src/v_text.cpp b/src/v_text.cpp index ca445913f..fa04da365 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -116,6 +116,7 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawChar) PARAM_FLOAT(y); PARAM_INT(chr); + if (!screen->IsLocked()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); VMVa_List args = { param + 5, 0, numparam - 5 }; screen->DrawChar(font, cr, x, y, chr, args); return 0; @@ -241,6 +242,7 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawText) PARAM_FLOAT(y); PARAM_STRING(chr); + if (!screen->IsLocked()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); VMVa_List args = { param + 5, 0, numparam - 5 }; const char *txt = chr[0] == '$' ? GStrings(&chr[1]) : chr.GetChars(); screen->DrawText(font, cr, x, y, txt, args); diff --git a/src/v_video.cpp b/src/v_video.cpp index a6482a90c..3dea831be 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -204,8 +204,6 @@ void V_MarkRect (int x, int y, int width, int height) { } -DCanvas *DCanvas::CanvasChain = NULL; - //========================================================================== // // DCanvas Constructor @@ -220,10 +218,6 @@ DCanvas::DCanvas (int _width, int _height, bool _bgra) Width = _width; Height = _height; Bgra = _bgra; - - // Add to list of active canvases - Next = CanvasChain; - CanvasChain = this; } //========================================================================== @@ -234,22 +228,6 @@ DCanvas::DCanvas (int _width, int _height, bool _bgra) DCanvas::~DCanvas () { - // Remove from list of active canvases - DCanvas *probe = CanvasChain, **prev; - - prev = &CanvasChain; - probe = CanvasChain; - - while (probe != NULL) - { - if (probe == this) - { - *prev = probe->Next; - break; - } - prev = &probe->Next; - probe = probe->Next; - } } //========================================================================== @@ -336,20 +314,6 @@ void DCanvas::Dim (PalEntry color) Dim (dimmer, amount, 0, 0, Width, Height); } -DEFINE_ACTION_FUNCTION(_Screen, Dim) -{ - PARAM_PROLOGUE; - PARAM_INT(color); - PARAM_FLOAT(amount); - PARAM_INT(x1); - PARAM_INT(y1); - PARAM_INT(w); - PARAM_INT(h); - screen->Dim(color, float(amount), x1, y1, w, h); - return 0; -} - - //========================================================================== // // DCanvas :: GetScreenshotBuffer @@ -1168,6 +1132,7 @@ void DFrameBuffer::SetBlendingRect (int x1, int y1, int x2, int y2) bool DFrameBuffer::Begin2D (bool copy3d) { + ClearClipRect(); return false; } diff --git a/src/v_video.h b/src/v_video.h index 444e80f04..56041a228 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -225,7 +225,8 @@ public: virtual void Dim (PalEntry color = 0); // Dim part of the canvas - virtual void Dim (PalEntry color, float amount, int x1, int y1, int w, int h); + virtual void Dim (PalEntry color, float amount, int x1, int y1, int w, int h) final; + virtual void DoDim(PalEntry color, float amount, int x1, int y1, int w, int h); // Fill an area with a texture virtual void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin=false); @@ -236,7 +237,8 @@ public: const FColormap &colormap, PalEntry flatcolor, int lightlevel, int bottomclip); // Set an area to a specified color - virtual void Clear (int left, int top, int right, int bottom, int palcolor, uint32_t color); + virtual void Clear (int left, int top, int right, int bottom, int palcolor, uint32_t color) final; + virtual void DoClear(int left, int top, int right, int bottom, int palcolor, uint32_t color); // Draws a line virtual void DrawLine(int x0, int y0, int x1, int y1, int palColor, uint32_t realcolor); @@ -259,6 +261,10 @@ public: // Text drawing functions ----------------------------------------------- // 2D Texture drawing + void ClearClipRect() { clipleft = cliptop = 0; clipwidth = clipheight = -1; } + void SetClipRect(int x, int y, int w, int h); + void GetClipRect(int *x, int *y, int *w, int *h); + bool SetTextureParms(DrawParms *parms, FTexture *img, double x, double y) const; void DrawTexture (FTexture *img, double x, double y, int tags, ...); void DrawTexture(FTexture *img, double x, double y, VMVa_List &); @@ -266,7 +272,6 @@ public: void VirtualToRealCoords(double &x, double &y, double &w, double &h, double vwidth, double vheight, bool vbottom=false, bool handleaspect=true) const; // Code that uses these (i.e. SBARINFO) should probably be evaluated for using doubles all around instead. - void VirtualToRealCoordsFixed(fixed_t &x, fixed_t &y, fixed_t &w, fixed_t &h, int vwidth, int vheight, bool vbottom=false, bool handleaspect=true) const; void VirtualToRealCoordsInt(int &x, int &y, int &w, int &h, int vwidth, int vheight, bool vbottom=false, bool handleaspect=true) const; #ifdef DrawText @@ -285,6 +290,7 @@ protected: int Pitch; int LockCount; bool Bgra; + int clipleft = 0, cliptop = 0, clipwidth = -1, clipheight = -1; void DrawTextCommon(FFont *font, int normalcolor, double x, double y, const char *string, DrawParms &parms); diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 9e2fc7ed7..f9a49eb0d 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -730,6 +730,7 @@ void WI_Drawer() { VMValue self = WI_Screen; GlobalVMStack.Call(func, &self, 1, nullptr, 0); + screen->ClearClipRect(); // make sure the scripts don't leave a valid clipping rect behind. // The internal handling here is somewhat poor. After being set to 'LeavingIntermission' // the screen is needed for one more draw operation so we cannot delete it right away but only here. diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 3c07b9c14..4fd198a1b 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -2557,6 +2557,7 @@ bool D3DPal::Update() bool D3DFB::Begin2D(bool copy3d) { + ClearClipRect(); if (!Accel2D) { return false; @@ -2635,11 +2636,11 @@ FNativePalette *D3DFB::CreatePalette(FRemapTable *remap) // //========================================================================== -void D3DFB::Clear (int left, int top, int right, int bottom, int palcolor, uint32_t color) +void D3DFB::DoClear (int left, int top, int right, int bottom, int palcolor, uint32_t color) { if (In2D < 2) { - Super::Clear(left, top, right, bottom, palcolor, color); + //Super::Clear(left, top, right, bottom, palcolor, color); return; } if (!InScene) @@ -2664,7 +2665,7 @@ void D3DFB::Clear (int left, int top, int right, int bottom, int palcolor, uint3 // //========================================================================== -void D3DFB::Dim (PalEntry color, float amount, int x1, int y1, int w, int h) +void D3DFB::DoDim (PalEntry color, float amount, int x1, int y1, int w, int h) { if (amount <= 0) { diff --git a/src/win32/win32gliface.cpp b/src/win32/win32gliface.cpp index b8e8cc53a..2074a17d8 100644 --- a/src/win32/win32gliface.cpp +++ b/src/win32/win32gliface.cpp @@ -1153,7 +1153,7 @@ void Win32GLFrameBuffer::Unlock () bool Win32GLFrameBuffer::IsLocked () { - return m_Lock>0;// true; + return m_Lock > 0; } //========================================================================== diff --git a/src/win32/win32swiface.h b/src/win32/win32swiface.h index ecd5a49df..5c0a456e4 100644 --- a/src/win32/win32swiface.h +++ b/src/win32/win32swiface.h @@ -132,8 +132,8 @@ public: FNativeTexture *CreateTexture (FTexture *gametex, bool wrapping); FNativePalette *CreatePalette (FRemapTable *remap); void DrawTextureParms (FTexture *img, DrawParms &parms); - void Clear (int left, int top, int right, int bottom, int palcolor, uint32_t color); - void Dim (PalEntry color, float amount, int x1, int y1, int w, int h); + void DoClear (int left, int top, int right, int bottom, int palcolor, uint32_t color); + void DoDim (PalEntry color, float amount, int x1, int y1, int w, int h); void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin); void DrawLine(int x0, int y0, int x1, int y1, int palColor, uint32_t realcolor); void DrawPixel(int x, int y, int palcolor, uint32_t rgbcolor); diff --git a/wadsrc/static/animdefs.txt b/wadsrc/static/animdefs.txt index a2f844417..e202c5d42 100644 --- a/wadsrc/static/animdefs.txt +++ b/wadsrc/static/animdefs.txt @@ -183,6 +183,14 @@ texture optional FBULB0 // The Wings of Wrath are not included, because they stop spinning when // you stop flying, so they can't be a simple animation. +texture optional INVGEML1 + pic INVGEML1 tics 4 + pic INVGEML2 tics 4 + +texture optional INVGEMR1 + pic INVGEMR1 tics 4 + pic INVGEMR2 tics 4 + switch doom 1 SW1BRCOM on pic SW2BRCOM tics 0 switch doom 1 SW1BRN1 on pic SW2BRN1 tics 0 switch doom 1 SW1BRN2 on pic SW2BRN2 tics 0 diff --git a/wadsrc/static/mapinfo/doomcommon.txt b/wadsrc/static/mapinfo/doomcommon.txt index 08cef5fd2..8dd21dbad 100644 --- a/wadsrc/static/mapinfo/doomcommon.txt +++ b/wadsrc/static/mapinfo/doomcommon.txt @@ -26,8 +26,8 @@ gameinfo defaultbloodparticlecolor = "ff 00 00" backpacktype = "Backpack" armoricons = "ARM1A0", 0.5, "ARM2A0" - statusbar = "sbarinfo/doom.txt" - //statusbarclass = "DoomStatusBar" + //statusbar = "sbarinfo/doom.txt" + statusbarclass = "DoomStatusBar" intermissionmusic = "$MUSIC_DM2INT" intermissioncounter = true weaponslot = 1, "Fist", "Chainsaw" diff --git a/wadsrc/static/mapinfo/heretic.txt b/wadsrc/static/mapinfo/heretic.txt index f87bd0f02..241853793 100644 --- a/wadsrc/static/mapinfo/heretic.txt +++ b/wadsrc/static/mapinfo/heretic.txt @@ -25,7 +25,8 @@ gameinfo defaultbloodparticlecolor = "ff 00 00" backpacktype = "BagOfHolding" armoricons = "SHLDA0", 0.75, "SHD2A0" - statusbar = "sbarinfo/heretic.txt" + //statusbar = "sbarinfo/heretic.txt" + statusbarclass = "HereticStatusBar" intermissionmusic = "mus_intr" intermissioncounter = false weaponslot = 1, "Staff", "Gauntlets" diff --git a/wadsrc/static/mapinfo/hexen.txt b/wadsrc/static/mapinfo/hexen.txt index a52105a07..09d325464 100644 --- a/wadsrc/static/mapinfo/hexen.txt +++ b/wadsrc/static/mapinfo/hexen.txt @@ -27,7 +27,8 @@ gameinfo defaultbloodcolor = "68 00 00" defaultbloodparticlecolor = "ff 00 00" backpacktype = "BagOfHolding" // Hexen doesn't have a backpack so use Heretic's. - statusbar = "sbarinfo/hexen.txt" + //statusbar = "sbarinfo/hexen.txt" + statusbarclass = "HexenStatusBar" intermissionmusic = "hub" intermissioncounter = false weaponslot = 1, "FWeapFist", "CWeapMace", "MWeapWand" diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 82987b55f..99627676d 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -33,6 +33,9 @@ version "2.5" #include "zscript/statscreen/statscreen_coop.txt" #include "zscript/statusbar/statusbar.txt" +#include "zscript/statusbar/doom_sbar.txt" +#include "zscript/statusbar/heretic_sbar.txt" +#include "zscript/statusbar/hexen_sbar.txt" #include "zscript/statusbar/strife_sbar.txt" #include "zscript/statusbar/sbarinfowrapper.txt" diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 71b4a7915..daac2f23d 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -501,6 +501,8 @@ class Actor : Thinker native native static int FindUniqueTid(int start = 0, int limit = 0); native void SetShade(color col); native clearscope int GetRenderStyle() const; + native clearscope bool CheckKeys(int locknum, bool remote, bool quiet = false); + native clearscope Inventory FirstInv() const; native clearscope string GetTag(string defstr = "") const; native void SetTag(string defstr = ""); @@ -669,6 +671,7 @@ class Actor : Thinker native native clearscope int GetSpawnHealth() const; native double GetCrouchFactor(int ptr = AAPTR_PLAYER1); native double GetCVar(string cvar); + native double GetCVarString(string cvar); native int GetPlayerInput(int inputnum, int ptr = AAPTR_DEFAULT); native int CountProximity(class classname, double distance, int flags = 0, int ptr = AAPTR_DEFAULT); native double GetSpriteAngle(int ptr = AAPTR_DEFAULT); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 6b6922ad3..379e660ce 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -14,6 +14,7 @@ struct _ native // These are the global variables, the struct is only here to av native play @PlayerInfo players[MAXPLAYERS]; native readonly bool playeringame[MAXPLAYERS]; + native readonly bool automapactive; native play uint gameaction; native readonly int gamestate; native readonly TextureID skyflatnum; @@ -169,7 +170,7 @@ struct Screen native // This is a leftover of the abandoned Inventory.DrawPowerup method. deprecated("2.5") static ui void DrawHUDTexture(TextureID tex, double x, double y) { - statusBar.DrawTexture(tex, (x, y), true, 1., BaseStatusBar.ALIGN_TOP|BaseStatusBar.ALIGN_RIGHT, (32, 32), BaseStatusBar.ALIGN_CENTER_BOTTOM); + statusBar.DrawTexture(tex, (x, y), BaseStatusBar.DI_SCREEN_RIGHT_TOP, 1., (32, 32)); } } diff --git a/wadsrc/static/zscript/menu/listmenuitems.txt b/wadsrc/static/zscript/menu/listmenuitems.txt index ee9be6044..5b4a4e549 100644 --- a/wadsrc/static/zscript/menu/listmenuitems.txt +++ b/wadsrc/static/zscript/menu/listmenuitems.txt @@ -35,7 +35,7 @@ class ListMenuItem : MenuItemBase { - void DrawSelector(double xofs, double yofs, TextureID tex) + virtual void DrawSelector(double xofs, double yofs, TextureID tex) { if (tex.isNull()) { diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 8851242b0..67414c542 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -360,6 +360,7 @@ usercmd_t original_cmd; native void SetLogText (String text); native void DropWeapon(); native void BringUpWeapon(); + native bool Resurrect(); native String GetUserName() const; native Color GetColor() const; @@ -373,6 +374,28 @@ usercmd_t original_cmd; native float GetAutoaim() const; native bool GetNoAutostartMap() const; native void SetFOV(float fov); + native clearscope bool HasWeaponsInSlot(int slot) const; + + clearscope int fragSum () const + { + int i; + int allfrags = 0; + int playernum = mo.PlayerNumber(); + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] + && i!=playernum) + { + allfrags += frags[i]; + } + } + + // JDC hack - negative frags. + allfrags -= frags[playernum]; + return allfrags; + } + } struct PlayerClass native diff --git a/wadsrc/static/zscript/statusbar/doom_sbar.txt b/wadsrc/static/zscript/statusbar/doom_sbar.txt new file mode 100644 index 000000000..67ea2c620 --- /dev/null +++ b/wadsrc/static/zscript/statusbar/doom_sbar.txt @@ -0,0 +1,195 @@ +class DoomStatusBar : BaseStatusBar +{ + HUDFont mHUDFont; + HUDFont mIndexFont; + HUDFont mAmountFont; + InventoryBarState diparms; + + + override void Init() + { + Super.Init(); + SetSize(32, 320, 200); + + // Create the font used for the fullscreen HUD + Font fnt = "HUDFONT_DOOM"; + mHUDFont = HUDFont.Create(fnt, fnt.GetCharWidth("0"), true, 1, 1); + fnt = "INDEXFONT_DOOM"; + mIndexFont = HUDFont.Create(fnt, fnt.GetCharWidth("0"), true); + mAmountFont = HUDFont.Create("INDEXFONT"); + diparms = InventoryBarState.Create(); + } + + override void Draw (int state, double TicFrac) + { + Super.Draw (state, TicFrac); + + if (state == HUD_StatusBar) + { + BeginStatusBar(320, 200, 32); + DrawMainBar (TicFrac); + } + else if (state == HUD_Fullscreen) + { + BeginHUD(320, 200, 1., false); + DrawFullScreenStuff (); + } + } + + protected void DrawMainBar (double TicFrac) + { + DrawImage("STBAR", (0, 168), DI_ITEM_OFFSETS); + DrawImage("STTPRCNT", (90, 171), DI_ITEM_OFFSETS); + DrawImage("STTPRCNT", (221, 171), DI_ITEM_OFFSETS); + + Inventory a1, a2; + int amt1; + [a1, a2, amt1] = GetCurrentAmmo(); + DrawString(mHUDFont, FormatNumber(amt1, 3), (44, 171), DI_TEXT_ALIGN_RIGHT|DI_NOSHADOW); + DrawString(mHUDFont, FormatNumber(CPlayer.health, 3), (90, 171), DI_TEXT_ALIGN_RIGHT|DI_NOSHADOW); + DrawString(mHUDFont, FormatNumber(GetArmorAmount(), 3), (221, 171), DI_TEXT_ALIGN_RIGHT|DI_NOSHADOW); + + bool locks[6]; + String image; + for(int i = 0; i < 6; i++) locks[i] = CPlayer.mo.CheckKeys(i + 1, false, true); + // key 1 + if (locks[1] && locks[4]) image = "STKEYS6"; + else if (locks[1]) image = "STKEYS0"; + else if (locks[4]) image = "STKEYS3"; + DrawImage(image, (239, 171), DI_ITEM_OFFSETS); + // key 2 + if (locks[2] && locks[5]) image = "STKEYS7"; + else if (locks[2]) image = "STKEYS1"; + else if (locks[5]) image = "STKEYS4"; + else image = ""; + DrawImage(image, (239, 181), DI_ITEM_OFFSETS); + // key 3 + if (locks[0] && locks[3]) image = "STKEYS8"; + else if (locks[0]) image = "STKEYS2"; + else if (locks[3]) image = "STKEYS5"; + else image = ""; + DrawImage(image, (239, 191), DI_ITEM_OFFSETS); + + int maxamt; + [amt1, maxamt] = GetAmount("Clip"); + DrawString(mIndexFont, FormatNumber(amt1, 3), (288, 173), DI_TEXT_ALIGN_RIGHT); + DrawString(mIndexFont, FormatNumber(maxamt, 3), (314, 173), DI_TEXT_ALIGN_RIGHT); + + [amt1, maxamt] = GetAmount("Shell"); + DrawString(mIndexFont, FormatNumber(amt1, 3), (288, 179), DI_TEXT_ALIGN_RIGHT); + DrawString(mIndexFont, FormatNumber(maxamt, 3), (314, 179), DI_TEXT_ALIGN_RIGHT); + + [amt1, maxamt] = GetAmount("RocketAmmo"); + DrawString(mIndexFont, FormatNumber(amt1, 3), (288, 185), DI_TEXT_ALIGN_RIGHT); + DrawString(mIndexFont, FormatNumber(maxamt, 3), (314, 185), DI_TEXT_ALIGN_RIGHT); + + [amt1, maxamt] = GetAmount("Cell"); + DrawString(mIndexFont, FormatNumber(amt1, 3), (288, 191), DI_TEXT_ALIGN_RIGHT); + DrawString(mIndexFont, FormatNumber(maxamt, 3), (314, 191), DI_TEXT_ALIGN_RIGHT); + + if (deathmatch || teamplay) + { + DrawString(mHUDFont, FormatNumber(CPlayer.FragCount, 3), (138, 171), DI_TEXT_ALIGN_RIGHT); + } + else + { + DrawImage("STARMS", (104, 168), DI_ITEM_OFFSETS); + DrawImage(CPlayer.HasWeaponsInSlot(2)? "STYSNUM2" : "STGNUM2", (111, 171), DI_ITEM_OFFSETS); + DrawImage(CPlayer.HasWeaponsInSlot(3)? "STYSNUM3" : "STGNUM3", (123, 171), DI_ITEM_OFFSETS); + DrawImage(CPlayer.HasWeaponsInSlot(4)? "STYSNUM4" : "STGNUM4", (135, 171), DI_ITEM_OFFSETS); + DrawImage(CPlayer.HasWeaponsInSlot(5)? "STYSNUM5" : "STGNUM5", (111, 181), DI_ITEM_OFFSETS); + DrawImage(CPlayer.HasWeaponsInSlot(6)? "STYSNUM6" : "STGNUM6", (123, 181), DI_ITEM_OFFSETS); + DrawImage(CPlayer.HasWeaponsInSlot(7)? "STYSNUM7" : "STGNUM7", (135, 181), DI_ITEM_OFFSETS); + } + + if (multiplayer) + { + DrawImage("STFBANY", (143, 168), DI_ITEM_OFFSETS|DI_TRANSLATABLE); + } + + if (CPlayer.mo.InvSel != null && !level.NoInventoryBar) + { + DrawInventoryIcon(CPlayer.mo.InvSel, (160, 198)); + if (CPlayer.mo.InvSel.Amount > 0) + { + DrawString(mAmountFont, FormatNumber(CPlayer.mo.InvSel.Amount), (175, 198-mIndexFont.mFont.GetHeight()), DI_TEXT_ALIGN_RIGHT, Font.CR_GOLD); + } + } + else + { + DrawTexture(GetMugShot(5), (143, 168), DI_ITEM_OFFSETS); + } + if (isInventoryBarVisible()) + { + DrawInventoryBar(diparms, (48, 169), 7, DI_ITEM_LEFT_TOP); + } + + } + + protected void DrawFullScreenStuff () + { + Vector2 iconbox = (40, 20); + // Draw health + let berserk = CPlayer.mo.FindInventory("PowerStrength"); + DrawImage(berserk? "PSTRA0" : "MEDIA0", (20, -2)); + DrawString(mHUDFont, FormatNumber(CPlayer.health, 3), (44, -20)); + + let armor = CPlayer.mo.FindInventory("BasicArmor"); + if (armor != null) + { + DrawInventoryIcon(armor, (20, -22)); + DrawString(mHUDFont, FormatNumber(armor.Amount, 3), (44, -40)); + } + Inventory ammotype1, ammotype2; + [ammotype1, ammotype2] = GetCurrentAmmo(); + int invY = -20; + if (ammotype1 != null) + { + DrawInventoryIcon(ammotype1, (-14, -4)); + DrawString(mHUDFont, FormatNumber(ammotype1.Amount, 3), (-30, -20), DI_TEXT_ALIGN_RIGHT); + invY -= 20; + } + if (ammotype2 != null && ammotype2 != ammotype1) + { + DrawInventoryIcon(ammotype2, (-14, invY + 17)); + DrawString(mHUDFont, FormatNumber(ammotype2.Amount, 3), (-30, invY), DI_TEXT_ALIGN_RIGHT); + invY -= 20; + } + if (!isInventoryBarVisible() && !level.NoInventoryBar && CPlayer.mo.InvSel != null) + { + DrawInventoryIcon(CPlayer.mo.InvSel, (-14, invY + 17)); + DrawString(mHUDFont, FormatNumber(CPlayer.mo.InvSel.Amount, 3), (-30, invY), DI_TEXT_ALIGN_RIGHT); + } + if (deathmatch) + { + DrawString(mHUDFont, FormatNumber(CPlayer.FragCount, 3), (-3, 1), DI_TEXT_ALIGN_RIGHT, Font.CR_GOLD); + } + + // Draw the keys. This does not use a special draw function like SBARINFO because the specifics will be different for each mod + // so it's easier to copy or reimplement the following piece of code instead of trying to write a complicated all-encompassing solution. + Vector2 keypos = (-10, 2); + int rowc = 0; + double roww = 0; + for(let i = CPlayer.mo.Inv; i != null; i = i.Inv) + { + if (i is "Key" && i.Icon.IsValid()) + { + DrawTexture(i.Icon, keypos, DI_SCREEN_RIGHT_TOP|DI_ITEM_LEFT_TOP); + Vector2 size = TexMan.GetScaledSize(i.Icon); + keypos.Y += size.Y + 2; + roww = max(roww, size.X); + if (++rowc == 3) + { + keypos.Y = 2; + keypos.X -= roww + 2; + roww = 0; + rowc = 0; + } + } + } + if (isInventoryBarVisible()) + { + DrawInventoryBar(diparms, (0, 0), 7, DI_SCREEN_CENTER_BOTTOM, HX_SHADOW); + } + } +} diff --git a/wadsrc/static/zscript/statusbar/heretic_sbar.txt b/wadsrc/static/zscript/statusbar/heretic_sbar.txt new file mode 100644 index 000000000..1273ad4ce --- /dev/null +++ b/wadsrc/static/zscript/statusbar/heretic_sbar.txt @@ -0,0 +1,208 @@ +class HereticStatusBar : BaseStatusBar +{ + DynamicValueInterpolator mHealthInterpolator; + HUDFont mHUDFont; + HUDFont mIndexFont; + HUDFont mBigFont; + InventoryBarState diparms; + InventoryBarState diparms_sbar; + + + override void Init() + { + Super.Init(); + SetSize(42, 320, 200); + + // Create the font used for the fullscreen HUD + Font fnt = "HUDFONT_RAVEN"; + mHUDFont = HUDFont.Create(fnt, fnt.GetCharWidth("0") + 1, true, 1, 1); + fnt = "INDEXFONT_RAVEN"; + mIndexFont = HUDFont.Create(fnt, fnt.GetCharWidth("0"), true); + fnt = "BIGFONT"; + mBigFont = HUDFont.Create(fnt, fnt.GetCharWidth("0"), true, 2, 2); + diparms = InventoryBarState.Create(mIndexFont); + diparms_sbar = InventoryBarState.CreateNoBox(mIndexFont, boxsize:(31, 31), arrowoffs:(0,-10)); + mHealthInterpolator = DynamicValueInterpolator.Create(0, 0.25, 1, 8); + } + + override void NewGame () + { + Super.NewGame(); + mHealthInterpolator.Reset (0); + } + + override void Tick() + { + Super.Tick(); + mHealthInterpolator.Update(CPlayer.health); + } + + override void Draw (int state, double TicFrac) + { + Super.Draw (state, TicFrac); + + if (state == HUD_StatusBar) + { + BeginStatusBar(320, 200, 42); + DrawMainBar (TicFrac); + } + else if (state == HUD_Fullscreen) + { + BeginHUD(320, 200, 1., false); + DrawFullScreenStuff (); + } + } + + protected void DrawMainBar (double TicFrac) + { + DrawImage("BARBACK", (0, 158), DI_ITEM_OFFSETS); + DrawImage("LTFCTOP", (0, 148), DI_ITEM_OFFSETS); + DrawImage("RTFCTOP", (290, 148), DI_ITEM_OFFSETS); + if (isInvulnerable()) + { + //god mode + DrawImage("GOD1", (16, 167), DI_ITEM_OFFSETS); + DrawImage("GOD2", (287, 167), DI_ITEM_OFFSETS); + } + //health + DrawImage("CHAINCAC", (0, 190), DI_ITEM_OFFSETS); + // wiggle the chain if it moves + int inthealth = mHealthInterpolator.GetValue(); + int wiggle = (inthealth != CPlayer.health) && Random[ChainWiggle](0, 1); + DrawGem("CHAIN", "LIFEGEM2",inthealth, CPlayer.mo.GetMaxHealth(true), (2, 191 + wiggle), 15, 25, 16, (multiplayer? DI_TRANSLATABLE : 0) | DI_ITEM_LEFT_TOP); + DrawImage("LTFACE", (0, 190), DI_ITEM_OFFSETS); + DrawImage("RTFACE", (276, 190), DI_ITEM_OFFSETS); + DrawShader(SHADER_HORZ, (19, 190), (16, 10)); + DrawShader(SHADER_HORZ|SHADER_REVERSE, (278, 190), (16, 10)); + + if (!isInventoryBarVisible()) + { + //statbar + if (!deathmatch) + { + DrawImage("LIFEBAR", (34, 160), DI_ITEM_OFFSETS); + DrawImage("ARMCLEAR", (57, 171), DI_ITEM_OFFSETS); + DrawString(mHUDFont, FormatNumber(mHealthInterpolator.GetValue(), 3), (88, 170), DI_TEXT_ALIGN_RIGHT); + } + else + { + DrawImage("STATBAR", (34, 160), DI_ITEM_OFFSETS); + DrawImage("ARMCLEAR", (57, 171), DI_ITEM_OFFSETS); + DrawString(mHUDFont, FormatNumber(CPlayer.FragCount, 3), (88, 170), DI_TEXT_ALIGN_RIGHT); + } + DrawString(mHUDFont, FormatNumber(GetArmorAmount(), 3), (255, 170), DI_TEXT_ALIGN_RIGHT); + + //ammo + Ammo ammo1, ammo2; + [ammo1, ammo2] = GetCurrentAmmo(); + if (ammo1 != null && ammo2 == null) + { + DrawString(mHUDFont, FormatNumber(ammo1.Amount, 3), (136, 162), DI_TEXT_ALIGN_RIGHT); + DrawTexture(ammo1.icon, (123, 180), DI_ITEM_CENTER); + } + else if (ammo2 != null) + { + DrawString(mIndexFont, FormatNumber(ammo1.Amount, 3), (137, 165), DI_TEXT_ALIGN_RIGHT); + DrawString(mIndexFont, FormatNumber(ammo2.Amount, 3), (137, 177), DI_TEXT_ALIGN_RIGHT); + DrawTexture(ammo1.icon, (115, 169), DI_ITEM_CENTER); + DrawTexture(ammo2.icon, (115, 180), DI_ITEM_CENTER); + } + + //keys + if (CPlayer.mo.CheckKeys(3, false, true)) DrawImage("YKEYICON", (153, 164), DI_ITEM_OFFSETS); + if (CPlayer.mo.CheckKeys(1, false, true)) DrawImage("GKEYICON", (153, 172), DI_ITEM_OFFSETS); + if (CPlayer.mo.CheckKeys(2, false, true)) DrawImage("BKEYICON", (153, 180), DI_ITEM_OFFSETS); + + //inventory box + if (CPlayer.mo.InvSel != null) + { + DrawInventoryIcon(CPlayer.mo.InvSel, (194, 175), DI_ARTIFLASH|DI_ITEM_CENTER, boxsize:(28, 28)); + if (CPlayer.mo.InvSel.Amount > 1) + { + DrawString(mIndexFont, FormatNumber(CPlayer.mo.InvSel.Amount, 3), (209, 182), DI_TEXT_ALIGN_RIGHT); + } + } + } + else + { + DrawImage("INVBAR", (34, 160), DI_ITEM_OFFSETS); + DrawInventoryBar(diparms_sbar, (49, 160), 7, DI_ITEM_LEFT_TOP, HX_SHADOW); + } + } + + protected void DrawFullScreenStuff () + { + //health + DrawImage("PTN1A0", (51, -3)); + DrawString(mBigFont, FormatNumber(mHealthInterpolator.GetValue()), (41, -21), DI_TEXT_ALIGN_RIGHT); + + //armor + let armor = CPlayer.mo.FindInventory("BasicArmor"); + if (armor != null) + { + DrawInventoryIcon(armor, (58, -24)); + DrawString(mBigFont, FormatNumber(armor.Amount, 3), (41, -43), DI_TEXT_ALIGN_RIGHT); + } + //frags/keys + if (deathmatch) + { + DrawString(mHUDFont, FormatNumber(CPlayer.FragCount, 3), (70, -16)); + } + else + { + Vector2 keypos = (60, -1); + int rowc = 0; + double roww = 0; + for(let i = CPlayer.mo.Inv; i != null; i = i.Inv) + { + if (i is "Key" && i.Icon.IsValid()) + { + DrawTexture(i.Icon, keypos, DI_ITEM_LEFT_BOTTOM); + Vector2 size = TexMan.GetScaledSize(i.Icon); + keypos.Y -= size.Y + 2; + roww = max(roww, size.X); + if (++rowc == 3) + { + keypos.Y = -1; + keypos.X += roww + 2; + roww = 0; + rowc = 0; + } + } + } + } + + //ammo + Ammo ammo1, ammo2; + [ammo1, ammo2] = GetCurrentAmmo(); + int y = -22; + if (ammo1 != null) + { + DrawTexture(ammo1.Icon, (-17, y)); + DrawString(mHUDFont, FormatNumber(ammo1.Amount, 3), (-3, y+7), DI_TEXT_ALIGN_RIGHT); + y -= 40; + } + if (ammo2 != null) + { + DrawTexture(ammo2.Icon, (-14, y)); + DrawString(mHUDFont, FormatNumber(ammo2.Amount, 3), (-3, y+7), DI_TEXT_ALIGN_RIGHT); + y -= 40; + } + + if (!isInventoryBarVisible() && !level.NoInventoryBar && CPlayer.mo.InvSel != null) + { + // This code was changed to always fit the item into the box, regardless of alignment or sprite size. + // Heretic's ARTIBOX is 30x30 pixels. + DrawImage("ARTIBOX", (-46, -1), 0, HX_SHADOW); + DrawInventoryIcon(CPlayer.mo.InvSel, (-46, -15), DI_ARTIFLASH|DI_ITEM_CENTER, boxsize:(28, 28)); + if (CPlayer.mo.InvSel.Amount > 1) + { + DrawString(mIndexFont, FormatNumber(CPlayer.mo.InvSel.Amount, 3), (-32, -2 - mIndexFont.mFont.GetHeight()), DI_TEXT_ALIGN_RIGHT); + } + } + if (isInventoryBarVisible()) + { + DrawInventoryBar(diparms, (0, 0), 7, DI_SCREEN_CENTER_BOTTOM, HX_SHADOW); + } + } +} diff --git a/wadsrc/static/zscript/statusbar/hexen_sbar.txt b/wadsrc/static/zscript/statusbar/hexen_sbar.txt new file mode 100644 index 000000000..f1ff81693 --- /dev/null +++ b/wadsrc/static/zscript/statusbar/hexen_sbar.txt @@ -0,0 +1,258 @@ +class HexenStatusBar : BaseStatusBar +{ + DynamicValueInterpolator mHealthInterpolator; + DynamicValueInterpolator mHealthInterpolator2; + HUDFont mHUDFont; + HUDFont mIndexFont; + HUDFont mBigFont; + InventoryBarState diparms; + InventoryBarState diparms_sbar; + + + override void Init() + { + Super.Init(); + SetSize(38, 320, 200); + + // Create the font used for the fullscreen HUD + Font fnt = "HUDFONT_RAVEN"; + mHUDFont = HUDFont.Create(fnt, fnt.GetCharWidth("0") + 1, true, 1, 1); + fnt = "INDEXFONT_RAVEN"; + mIndexFont = HUDFont.Create(fnt, fnt.GetCharWidth("0"), true); + fnt = "BIGFONT"; + mBigFont = HUDFont.Create(fnt, fnt.GetCharWidth("0"), true, 2, 2); + diparms = InventoryBarState.Create(mIndexFont); + diparms_sbar = InventoryBarState.CreateNoBox(mIndexFont, boxsize:(31, 31), arrowoffs:(0,-10)); + mHealthInterpolator = DynamicValueInterpolator.Create(0, 0.25, 1, 8); + mHealthInterpolator2 = DynamicValueInterpolator.Create(0, 0.25, 1, 6); // the chain uses a maximum of 6, not 8. + } + + override void NewGame () + { + Super.NewGame(); + mHealthInterpolator.Reset (0); + mHealthInterpolator2.Reset (0); + } + + override void Tick() + { + Super.Tick(); + mHealthInterpolator.Update(CPlayer.health); + mHealthInterpolator2.Update(CPlayer.health); + } + + override void Draw (int state, double TicFrac) + { + Super.Draw (state, TicFrac); + + if (state == HUD_StatusBar) + { + BeginStatusBar(320, 200, 38); + DrawMainBar (TicFrac); + } + else if (state == HUD_Fullscreen) + { + BeginHUD(320, 200, 1., false); + DrawFullScreenStuff (); + } + } + + protected void DrawFullScreenStuff () + { + //health + DrawImage("PTN1A0", (51, -3)); + DrawString(mBigFont, FormatNumber(mHealthInterpolator.GetValue()), (41, -21), DI_TEXT_ALIGN_RIGHT); + + //frags/keys + if (deathmatch) + { + DrawString(mHUDFont, FormatNumber(CPlayer.FragCount, 3), (70, -16)); + } + + if (!isInventoryBarVisible() && !level.NoInventoryBar && CPlayer.mo.InvSel != null) + { + // This code was changed to always fit the item into the box, regardless of alignment or sprite size. + // Heretic's ARTIBOX is 30x30 pixels. + DrawImage("ARTIBOX", (-66, -1), 0, HX_SHADOW); + DrawInventoryIcon(CPlayer.mo.InvSel, (-66, -15), DI_ARTIFLASH|DI_ITEM_CENTER, boxsize:(28, 28)); + if (CPlayer.mo.InvSel.Amount > 1) + { + DrawString(mIndexFont, FormatNumber(CPlayer.mo.InvSel.Amount, 3), (-52, -2 - mIndexFont.mFont.GetHeight()), DI_TEXT_ALIGN_RIGHT); + } + } + + Ammo ammo1, ammo2; + [ammo1, ammo2] = GetCurrentAmmo(); + if ((ammo1 is "Mana1") || (ammo2 is "Mana1")) DrawImage("MANABRT1", (-17, -30), DI_ITEM_OFFSETS); + else DrawImage("MANADIM1", (-17, -30), DI_ITEM_OFFSETS); + if ((ammo1 is "Mana2") || (ammo2 is "Mana2")) DrawImage("MANABRT2", (-17, -15), DI_ITEM_OFFSETS); + else DrawImage("MANADIM2", (-17, -15), DI_ITEM_OFFSETS); + DrawString(mHUDFont, FormatNumber(GetAmount("Mana1"), 3), (-21, -30), DI_TEXT_ALIGN_RIGHT); + DrawString(mHUDFont, FormatNumber(GetAmount("Mana2"), 3), (-21, -15), DI_TEXT_ALIGN_RIGHT); + + if (isInventoryBarVisible()) + { + DrawInventoryBar(diparms, (0, 0), 7, DI_SCREEN_CENTER_BOTTOM, HX_SHADOW); + } + } + + protected void DrawMainBar (double TicFrac) + { + DrawImage("H2BAR", (0, 134), DI_ITEM_OFFSETS); + if (!automapactive) + { + if (isInventoryBarVisible()) + { + DrawImage("INVBAR", (38, 162), DI_ITEM_OFFSETS); + DrawInventoryBar(diparms_sbar, (52, 163), 7, DI_ITEM_LEFT_TOP, HX_SHADOW); + return; + } + else + { + DrawImage("STATBAR", (38, 162), DI_ITEM_OFFSETS); + + //inventory box + if (CPlayer.mo.InvSel != null) + { + DrawInventoryIcon(CPlayer.mo.InvSel, (159.5, 177), DI_ARTIFLASH|DI_ITEM_CENTER, boxsize:(28, 28)); + if (CPlayer.mo.InvSel.Amount > 1) + { + DrawString(mIndexFont, FormatNumber(CPlayer.mo.InvSel.Amount, 3), (174, 184), DI_TEXT_ALIGN_RIGHT); + } + } + + if (deathmatch || teamplay) + { + DrawImage("KILLS", (38, 163), DI_ITEM_OFFSETS); + DrawString(mHUDFont, FormatNumber(CPlayer.FragCount, 3), (66, 176), DI_TEXT_ALIGN_RIGHT); + } + else + { + DrawImage("ARMCLS", (41, 178), DI_ITEM_OFFSETS); + // Note that this has been changed to use red only if the REAL health is below 25, not when an interpolated value is below 25! + DrawString(mHUDFont, FormatNumber(mHealthInterpolator.GetValue(), 3), (66, 176), DI_TEXT_ALIGN_RIGHT, CPlayer.Health < 25? Font.CR_RED : Font.CR_UNTRANSLATED); + } + + //armor + DrawImage("ARMCLS", (255, 178), DI_ITEM_OFFSETS); + DrawString(mHUDFont, FormatNumber(GetArmorSavePercent() / 5, 2), (276, 176), DI_TEXT_ALIGN_RIGHT); + + Ammo ammo1, ammo2; + [ammo1, ammo2] = GetCurrentAmmo(); + + if (ammo1 != null && !(ammo1 is "Mana1") && !(ammo1 is "Mana2")) + { + DrawImage("HAMOBACK", (77, 164), DI_ITEM_OFFSETS); + if (ammo2 != null) + { + DrawTexture(ammo1.icon, (89, 172), DI_ITEM_CENTER); + DrawTexture(ammo2.icon, (113, 172), DI_ITEM_CENTER); + DrawString(mIndexFont, FormatNumber(ammo1.amount, 3), ( 98, 182), DI_TEXT_ALIGN_RIGHT); + DrawString(mIndexFont, FormatNumber(ammo2.amount, 3), (122, 182), DI_TEXT_ALIGN_RIGHT); + } + else + { + DrawTexture(ammo1.icon, (100, 172), DI_ITEM_CENTER); + DrawString(mIndexFont, FormatNumber(ammo1.amount, 3), (109, 182), DI_TEXT_ALIGN_RIGHT); + } + } + else + { + int amt1, maxamt1, amt2, maxamt2; + [amt1, maxamt1] = GetAmount("Mana1"); + [amt2, maxamt2] = GetAmount("Mana2"); + if ((ammo1 is "Mana1") || (ammo2 is "Mana1")) + { + DrawImage("MANABRT1", (77, 164), DI_ITEM_OFFSETS); + DrawBar("MANAVL1", "", amt1, maxamt1, (94, 164), 1, SHADER_VERT, DI_ITEM_OFFSETS); + } + else + { + DrawImage("MANADIM1", (77, 164), DI_ITEM_OFFSETS); + DrawBar("MANAVL1D", "", amt1, maxamt1, (94, 164), 1, SHADER_VERT, DI_ITEM_OFFSETS); + } + if ((ammo1 is "Mana2") || (ammo2 is "Mana2")) + { + DrawImage("MANABRT2", (110, 164), DI_ITEM_OFFSETS); + DrawBar("MANAVL2", "", amt2, maxamt2, (102, 164), 1, SHADER_VERT, DI_ITEM_OFFSETS); + } + else + { + DrawImage("MANADIM2", (110, 164), DI_ITEM_OFFSETS); + DrawBar("MANAVL2D", "", amt2, maxamt2, (102, 164), 1, SHADER_VERT, DI_ITEM_OFFSETS); + } + DrawString(mIndexFont, FormatNumber(amt1, 3), ( 92, 181), DI_TEXT_ALIGN_RIGHT); + DrawString(mIndexFont, FormatNumber(amt2, 3), (124, 181), DI_TEXT_ALIGN_RIGHT); + } + if (CPlayer.mo is "ClericPlayer") + { + DrawImage("WPSLOT1", (190, 162), DI_ITEM_OFFSETS); + if (CheckInventory("CWeapWraithverge")) DrawImage("WPFULL1", (190, 162), DI_ITEM_OFFSETS); + else + { + int pieces = GetWeaponPieceMask("CWeapWraithverge"); + if (pieces & 1) DrawImage("WPIECEC1", (190, 162), DI_ITEM_OFFSETS); + if (pieces & 2) DrawImage("WPIECEC2", (212, 162), DI_ITEM_OFFSETS); + if (pieces & 4) DrawImage("WPIECEC3", (225, 162), DI_ITEM_OFFSETS); + } + } + else if (CPlayer.mo is "MagePlayer") + { + DrawImage("WPSLOT2", (190, 162), DI_ITEM_OFFSETS); + if (CheckInventory("MWeapBloodscourge")) DrawImage("WPFULL2", (190, 162), DI_ITEM_OFFSETS); + else + { + int pieces = GetWeaponPieceMask("MWeapBloodscourge"); + if (pieces & 1) DrawImage("WPIECEM1", (190, 162), DI_ITEM_OFFSETS); + if (pieces & 2) DrawImage("WPIECEM2", (205, 162), DI_ITEM_OFFSETS); + if (pieces & 4) DrawImage("WPIECEM3", (224, 162), DI_ITEM_OFFSETS); + } + } + else + { + DrawImage("WPSLOT0", (190, 162), DI_ITEM_OFFSETS); + if (CheckInventory("FWeapQuietus")) DrawImage("WPFULL0", (190, 162), DI_ITEM_OFFSETS); + else + { + int pieces = GetWeaponPieceMask("FWeapQuietus"); + if (pieces & 1) DrawImage("WPIECEF1", (190, 162), DI_ITEM_OFFSETS); + if (pieces & 2) DrawImage("WPIECEF2", (225, 162), DI_ITEM_OFFSETS); + if (pieces & 4) DrawImage("WPIECEF3", (234, 162), DI_ITEM_OFFSETS); + } + } + } + } + else // automap + { + DrawImage("H2BAR", (0, 134), DI_ITEM_OFFSETS); + DrawImage("KEYBAR", (38, 162), DI_ITEM_OFFSETS); + int cnt = 0; + Vector2 keypos = (46, 164); + for(let i = CPlayer.mo.Inv; i != null; i = i.Inv) + { + if (i is "Key" && i.Icon.IsValid()) + { + DrawTexture(i.Icon, keypos, DI_ITEM_OFFSETS); + keypos.X += 20; + if (++cnt >= 5) break; + } + } + DrawHexenArmor(HEXENARMOR_ARMOR, "ARMSLOT1", (150, 164), DI_ITEM_OFFSETS); + DrawHexenArmor(HEXENARMOR_SHIELD, "ARMSLOT2", (181, 164), DI_ITEM_OFFSETS); + DrawHexenArmor(HEXENARMOR_HELM, "ARMSLOT3", (212, 164), DI_ITEM_OFFSETS); + DrawHexenArmor(HEXENARMOR_AMULET, "ARMSLOT4", (243, 164), DI_ITEM_OFFSETS); + } + + String Gem; + if (CPlayer.mo is "ClericPlayer") Gem = "LIFEGMC2"; + else if (CPlayer.mo is "MagePlayer") Gem = "LIFEGMM2"; + else Gem = "LIFEGMF2"; + + int inthealth = mHealthInterpolator2.GetValue(); + DrawGem("CHAIN", "LIFEGMF2", inthealth, CPlayer.mo.GetMaxHealth(true), (30, 193), -23, 49, 15, (multiplayer? DI_TRANSLATABLE : 0) | DI_ITEM_LEFT_TOP); + + DrawImage("LFEDGE", (0, 193), DI_ITEM_OFFSETS); + DrawImage("RTEDGE", (277, 193), DI_ITEM_OFFSETS); + } +} + diff --git a/wadsrc/static/zscript/statusbar/sbarinfowrapper.txt b/wadsrc/static/zscript/statusbar/sbarinfowrapper.txt index d58e175d1..8c8c6bf53 100644 --- a/wadsrc/static/zscript/statusbar/sbarinfowrapper.txt +++ b/wadsrc/static/zscript/statusbar/sbarinfowrapper.txt @@ -8,7 +8,6 @@ struct SBarInfo native ui native void NewGame(); native bool MustDrawLog(int state); native void Tick(); - native void FlashItem(class itemtype); native void ShowPop(int popnum); } @@ -49,7 +48,6 @@ class SBarInfoWrapper : BaseStatusBar Super.NewGame(); if (CPlayer != NULL) { - AttachToPlayer(CPlayer); core.NewGame(); } } @@ -65,11 +63,6 @@ class SBarInfoWrapper : BaseStatusBar core.Tick(); } - override void FlashItem(class itemtype) - { - core.FlashItem(itemtype); - } - override void ShowPop(int popnum) { Super.ShowPop(popnum); diff --git a/wadsrc/static/zscript/statusbar/statusbar.txt b/wadsrc/static/zscript/statusbar/statusbar.txt index 97a153e4b..01fbcc7ae 100644 --- a/wadsrc/static/zscript/statusbar/statusbar.txt +++ b/wadsrc/static/zscript/statusbar/statusbar.txt @@ -15,6 +15,92 @@ struct MugShot } } +class HUDFont native ui +{ + native Font mFont; + native static HUDFont Create(Font fnt, int spacing = 0, bool monospaced = false, int shadowx = 0, int shadowy = 0); +} + +class InventoryBarState ui +{ + TextureID box; + TextureID selector; + Vector2 boxsize; + Vector2 boxofs; + Vector2 selectofs; + Vector2 innersize; + + TextureID left; + TextureID right; + Vector2 arrowoffset; + + double itemalpha; + + HUDFont amountfont; + int cr; + int flags; + + private static void Init(InventoryBarState me, HUDFont indexfont, int cr, double itemalpha, Vector2 innersize, String leftgfx, String rightgfx, Vector2 arrowoffs, int flags) + { + me.itemalpha = itemalpha; + if (innersize == (0, 0)) + { + me.boxofs = (2, 2); + me.innersize = me.boxsize - (4, 4); // Default is based on Heretic's and Hexens icons. + } + else + { + me.innersize = innersize; + me.boxofs = (me.boxsize - me.innersize) / 2; + } + if (me.selector.IsValid()) + { + Vector2 sel = TexMan.GetScaledSize(me.selector); + me.selectofs = (me.boxsize - sel) / 2; + } + me.left = TexMan.CheckForTexture(leftgfx, TexMan.TYPE_MiscPatch); + me.right = TexMan.CheckForTexture(rightgfx, TexMan.TYPE_MiscPatch); + me.arrowoffset = arrowoffs; + me.arrowoffset.Y += me.boxsize.Y/2; // default is centered to the side of the box. + if (indexfont == null) + { + me.amountfont = HUDFont.Create("INDEXFONT"); + if (cr == Font.CR_UNTRANSLATED) cr = Font.CR_GOLD; + } + else me.amountfont = indexfont; + me.cr = cr; + me.flags = flags; + } + + // The default settings here are what SBARINFO is using. + static InventoryBarState Create(HUDFont indexfont = null, int cr = Font.CR_UNTRANSLATED, double itemalpha = 1., + String boxgfx = "ARTIBOX", String selgfx = "SELECTBO", Vector2 innersize = (0, 0), + String leftgfx = "INVGEML1", String rightgfx = "INVGEMR1", Vector2 arrowoffs = (0, 0), int flags = 0) + { + let me = new ("InventoryBarState"); + me.box = TexMan.CheckForTexture(boxgfx, TexMan.TYPE_MiscPatch); + me.selector = TexMan.CheckForTexture(selgfx, TexMan.TYPE_MiscPatch); + if (me.box.IsValid() || me.selector.IsValid()) me.boxsize = TexMan.GetScaledSize(me.box.IsValid()? me.box : me.selector); + else me.boxsize = (32., 32.); + Init(me, indexfont, cr, itemalpha, innersize, leftgfx, rightgfx, arrowoffs, flags); + return me; + } + + // The default settings here are what SBARINFO is using. + static InventoryBarState CreateNoBox(HUDFont indexfont = null, int cr = Font.CR_UNTRANSLATED, double itemalpha = 1., + Vector2 boxsize = (32, 32), String selgfx = "SELECTBO", Vector2 innersize = (0, 0), + String leftgfx = "INVGEML1", String rightgfx = "INVGEMR1", Vector2 arrowoffs = (0, 0), int flags = 0) + { + let me = new ("InventoryBarState"); + me.box.SetInvalid(); + me.selector = TexMan.CheckForTexture(selgfx, TexMan.TYPE_MiscPatch); + me.boxsize = boxsize; + Init(me, indexfont, cr, itemalpha, innersize, leftgfx, rightgfx, arrowoffs, flags); + return me; + } + +} + class BaseStatusBar native ui { @@ -65,8 +151,73 @@ class BaseStatusBar native ui DI_TRANSLATABLE = 0x20, DI_FORCESCALE = 0x40, DI_DIM = 0x80, - }; + DI_DRAWCURSORFIRST = 0x100, // only for DrawInventoryBar. + DI_ALWAYSSHOWCOUNT = 0x200, // only for DrawInventoryBar. + DI_DIMDEPLETED = 0x400, + DI_DONTANIMATE = 0x800, // do not animate the texture + + DI_SCREEN_AUTO = 0, // decide based on given offsets. + DI_SCREEN_MANUAL_ALIGN = 0x4000, // If this is on, the following flags will have an effect + + DI_SCREEN_TOP = DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_VCENTER = 0x8000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_BOTTOM = 0x10000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_VOFFSET = 0x18000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_VMASK = 0x18000 | DI_SCREEN_MANUAL_ALIGN, + + DI_SCREEN_LEFT = DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_HCENTER = 0x20000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_RIGHT = 0x40000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_HOFFSET = 0x60000 | DI_SCREEN_MANUAL_ALIGN, + DI_SCREEN_HMASK = 0x60000 | DI_SCREEN_MANUAL_ALIGN, + + DI_SCREEN_LEFT_TOP = DI_SCREEN_TOP|DI_SCREEN_LEFT, + DI_SCREEN_RIGHT_TOP = DI_SCREEN_TOP|DI_SCREEN_RIGHT, + DI_SCREEN_LEFT_BOTTOM = DI_SCREEN_BOTTOM|DI_SCREEN_LEFT, + DI_SCREEN_RIGHT_BOTTOM = DI_SCREEN_BOTTOM|DI_SCREEN_RIGHT, + DI_SCREEN_CENTER = DI_SCREEN_VCENTER|DI_SCREEN_HCENTER, + DI_SCREEN_CENTER_BOTTOM = DI_SCREEN_BOTTOM|DI_SCREEN_HCENTER, + DI_SCREEN_OFFSETS = DI_SCREEN_HOFFSET|DI_SCREEN_VOFFSET, + + DI_ITEM_AUTO = 0, // equivalent with bottom center, which is the default alignment. + + DI_ITEM_TOP = 0x80000, + DI_ITEM_VCENTER = 0x100000, + DI_ITEM_BOTTOM = 0, // this is the default vertical alignment + DI_ITEM_VOFFSET = 0x180000, + DI_ITEM_VMASK = 0x180000, + + DI_ITEM_LEFT = 0x200000, + DI_ITEM_HCENTER = 0, // this is the deafault horizontal alignment + DI_ITEM_RIGHT = 0x400000, + DI_ITEM_HOFFSET = 0x600000, + DI_ITEM_HMASK = 0x600000, + + DI_ITEM_LEFT_TOP = DI_ITEM_TOP|DI_ITEM_LEFT, + DI_ITEM_RIGHT_TOP = DI_ITEM_TOP|DI_ITEM_RIGHT, + DI_ITEM_LEFT_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_LEFT, + DI_ITEM_RIGHT_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_RIGHT, + DI_ITEM_CENTER = DI_ITEM_VCENTER|DI_ITEM_HCENTER, + DI_ITEM_CENTER_BOTTOM = DI_ITEM_BOTTOM|DI_ITEM_HCENTER, + DI_ITEM_OFFSETS = DI_ITEM_HOFFSET|DI_ITEM_VOFFSET, + + DI_TEXT_ALIGN_LEFT = 0, + DI_TEXT_ALIGN_RIGHT = 0x800000, + DI_TEXT_ALIGN_CENTER = 0x1000000, + DI_TEXT_ALIGN = 0x1800000, + DI_ALPHAMAPPED = 0x2000000, + DI_NOSHADOW = 0x4000000, + DI_ALWAYSSHOWCOUNTERS = 0x8000000, + DI_ARTIFLASH = 0x10000000, + DI_FORCEFILL = 0x20000000, + + // These 2 flags are only used by SBARINFO so these duplicate other flags not used by SBARINFO + DI_DRAWINBOX = DI_TEXT_ALIGN_RIGHT, + DI_ALTERNATEONFAIL = DI_TEXT_ALIGN_CENTER, + + }; + enum IconType { ITYPE_PLAYERICON = 1000, @@ -87,40 +238,6 @@ class BaseStatusBar native ui HEXENARMOR_AMULET, }; - enum EAlign - { - ALIGN_TOP = 0, - ALIGN_VCENTER = 1, - ALIGN_BOTTOM = 2, - ALIGN_VOFFSET = 3, - ALIGN_VMASK = 3, - - ALIGN_LEFT = 0, - ALIGN_HCENTER = 4, - ALIGN_RIGHT = 8, - ALIGN_HOFFSET = 12, - ALIGN_HMASK = 12, - - ALIGN_CENTER = ALIGN_VCENTER|ALIGN_HCENTER, - ALIGN_CENTER_BOTTOM = ALIGN_BOTTOM|ALIGN_HCENTER, - ALIGN_OFFSETS = ALIGN_HOFFSET|ALIGN_VOFFSET - }; - - enum ETextAlign - { - TEXT_LEFT = 0, - TEXT_CENTER = 1, - TEXT_RIGHT = 2 - }; - - enum SBGameModes - { - GAMEMODE_SINGLEPLAYER = 0x1, - GAMEMODE_COOPERATIVE = 0x2, - GAMEMODE_DEATHMATCH = 0x4, - GAMEMODE_TEAMGAME = 0x8 - }; - enum AmmoModes { AMMO_PRIMARY, @@ -141,6 +258,13 @@ class BaseStatusBar native ui FNF_WHENNOTZERO, } + enum EShade + { + SHADER_HORZ = 0, + SHADER_VERT = 2, + SHADER_REVERSE = 1 + } + const XHAIRSHRINKSIZE =(1./18); const XHAIRPICKUPSIZE = (2+XHAIRSHRINKSIZE); const POWERUPICONSIZE = 32; @@ -158,6 +282,8 @@ class BaseStatusBar native ui native PlayerInfo CPlayer; native bool ShowLog; native Vector2 defaultScale; // factor for fully scaled fullscreen display. + native int artiflashTick; + native double itemflashFade; // These are block properties for the drawers. A child class can set them to have a block of items use the same settings. native double Alpha; @@ -180,22 +306,24 @@ class BaseStatusBar native ui native virtual clearscope void ReceivedWeapon (Weapon weapn); native virtual clearscope void SetMugShotState (String state_name, bool wait_till_done=false, bool reset=false); - virtual void FlashItem (class itemtype) {} + virtual void FlashItem (class itemtype) { artiflashTick = 4; itemflashFade = 0.75; } virtual void AttachToPlayer (PlayerInfo player) { CPlayer = player; } virtual void FlashCrosshair () { CrosshairSize = XHAIRPICKUPSIZE; } - virtual void NewGame () {} + virtual void NewGame () { if (CPlayer != null) AttachToPlayer(CPlayer); } virtual void ShowPop (int popnum) { ShowLog = (popnum == POP_Log && !ShowLog); } virtual bool MustDrawLog(int state) { return true; } native void RefreshBackground () const; - native TextureID GetMugshot(PlayerInfo player, String default_face, int accuracy, int stateflags=MugShot.STANDARD); + native TextureID GetMugshot(int accuracy, int stateflags=MugShot.STANDARD, String default_face = "STF"); // These functions are kept native solely for performance reasons. They get called repeatedly and can drag down performance easily if they get too slow. native Inventory ValidateInvFirst (int numVisible) const; native static TextureID, bool GetInventoryIcon(Inventory item, int flags); - native void DrawGraphic(TextureID texture, bool animate, Vector2 pos, double Alpha, bool translatable, bool dim, int imgAlign, int screenalign, bool alphamap, Vector2 box); - native void DrawString(Font font, String string, Vector2 pos , double Alpha, int translation, int align, int screenalign, int spacing=0, bool monospaced = false, int shadowX=0, int shadowY=0, int wrapwidth = -1, int linespacing = 4); - native static String FormatNumber(int number, int minsize, int maxsize, int format, String prefix = ""); + native void DrawTexture(TextureID texture, Vector2 pos, int flags = 0, double Alpha = 1., Vector2 box = (-1, -1), Vector2 scale = (1, 1)); + native void DrawImage(String texture, Vector2 pos, int flags = 0, double Alpha = 1., Vector2 box = (-1, -1), Vector2 scale = (1, 1)); + native void DrawString(HUDFont font, String string, Vector2 pos, int flags = 0, int translation = Font.CR_UNTRANSLATED, double Alpha = 1., int wrapwidth = -1, int linespacing = 4); + native void Fill(Color col, double x, double y, double w, double h, int flags = 0); + native static String FormatNumber(int number, int minsize = 0, int maxsize = 0, int format = 0, String prefix = ""); //============================================================================ @@ -207,7 +335,7 @@ class BaseStatusBar native ui // //============================================================================ - Inventory, Inventory, int, int GetCurrentAmmo () const + Ammo, Ammo, int, int GetCurrentAmmo () const { Ammo ammo1, ammo2; if (CPlayer.ReadyWeapon != NULL) @@ -235,7 +363,7 @@ class BaseStatusBar native ui // //============================================================================ - TextureID, Vector2 GetIcon(Inventory item, int flags, bool showdepleted = false) + TextureID, Vector2 GetIcon(Inventory item, int flags, bool showdepleted = true) { TextureID icon; Vector2 scale = (1,1); @@ -245,12 +373,12 @@ class BaseStatusBar native ui bool applyscale; [icon, applyscale] = GetInventoryIcon(item, flags); - if (item.Amount == 0 && !showdepleted) return icon; + if (item.Amount == 0 && !showdepleted) return icon, scale; if (applyscale) scale = item.Scale; } - return icon; + return icon, scale; } //============================================================================ @@ -299,6 +427,14 @@ class BaseStatusBar native ui return armor? armor.Amount : 0; } + int, int GetAmount(class item) + { + let it = CPlayer.mo.FindInventory(item); + int ret1 = it? it.Amount : GetDefaultByType(item).Amount; + int ret2 = it? it.MaxAmount : GetDefaultByType(item).MaxAmount; + return ret1, ret2; + } + int GetMaxAmount(class item) { let it = CPlayer.mo.FindInventory(item); @@ -354,20 +490,6 @@ class BaseStatusBar native ui // //============================================================================ - //============================================================================ - // - // checks current game mode against a flag mask - // - //============================================================================ - - bool CheckGameMode(int ValidModes) - { - return (!multiplayer && (ValidModes & GAMEMODE_SINGLEPLAYER)) || - (deathmatch && (ValidModes & GAMEMODE_DEATHMATCH)) || - (multiplayer && !deathmatch && (ValidModes & GAMEMODE_COOPERATIVE)) || - (teamplay && (ValidModes & GAMEMODE_TEAMGAME)); - } - //============================================================================ // // checks ammo use of current weapon @@ -398,7 +520,7 @@ class BaseStatusBar native ui bool isInventoryBarVisible() { if (CPlayer == null) return false; - return (CPlayer.inventorytics <= 0 || level.NoInventoryBar); + return (CPlayer.inventorytics > 0 && !level.NoInventoryBar); } //============================================================================ @@ -448,7 +570,7 @@ class BaseStatusBar native ui // //============================================================================ - bool CheckWeaponPiece(class weap, int piecenum) + int CheckWeaponPiece(class weap, int piecenum) { if (CPlayer == null) return false; for(let inv = CPlayer.mo.Inv; inv != NULL; inv = inv.Inv) @@ -468,6 +590,26 @@ class BaseStatusBar native ui // //============================================================================ + int GetWeaponPieceMask(class weap) + { + if (CPlayer == null) return false; + for(let inv = CPlayer.mo.Inv; inv != NULL; inv = inv.Inv) + { + let wh = WeaponHolder(inv); + if (wh != null && wh.PieceWeapon == weap) + { + return wh.PieceMask; + } + } + return 0; + } + + //============================================================================ + // + // checks if player has the given weapon piece + // + //============================================================================ + bool WeaponUsesAmmoType(class ammotype) { if (CPlayer == null) return false; @@ -535,7 +677,7 @@ class BaseStatusBar native ui if (icon.IsValid()) { // Each icon gets a 32x32 block. - DrawTexture(icon, pos, true, 1.0, ALIGN_TOP|ALIGN_RIGHT, (POWERUPICONSIZE, POWERUPICONSIZE), ALIGN_CENTER_BOTTOM); + DrawTexture(icon, pos, DI_SCREEN_RIGHT_TOP, 1.0, (POWERUPICONSIZE, POWERUPICONSIZE)); pos.x -= POWERUPICONSIZE; if (pos.x < -maxpos) { @@ -560,113 +702,13 @@ class BaseStatusBar native ui return Translation.MakeID(TRANSLATION_Players, CPlayer.mo.PlayerNumber()); } - //============================================================================ - // - // draw stuff - // - //============================================================================ - - void DrawTexture(TextureID texture, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = ALIGN_TOP|ALIGN_LEFT, Vector2 boxsize = (-1, -1), int itemAlign = ALIGN_TOP|ALIGN_LEFT, int flags = 0, Vector2 scale = (1., 1.) ) - { - if (!texture.IsValid()) return; // nothing to draw - - alpha *= self.alpha; - if (alpha <= 0) return; // invisible - - Vector2 texsize = TexMan.GetScaledSize(texture); - texsize.X *= scale.X; - texsize.Y *= scale.Y; - if (boxsize.X > 0 || boxsize.Y > 0) - { - double scale1 = 1., scale2 = 1.; - - if (boxsize.X != -1 && (boxsize.X < texsize.X || (flags & DI_FORCESCALE))) - { - scale1 = boxsize.X / texsize.X; - } - if (boxsize.Y != -1 && (boxsize.Y < texsize.Y || (flags & DI_FORCESCALE))) - { - scale2 = boxsize.Y / texsize.Y; - } - - if (flags & DI_FORCESCALE) - { - if (boxsize.X == -1 || (boxsize.Y != -1 && scale2 < scale1)) - scale1 = scale2; - } - else scale1 = min(scale1, scale2); - - boxsize = texsize * scale1; - } - else - { - boxsize = texsize; - } - DrawGraphic(texture, animated, pos, Alpha, !!(flags & DI_TRANSLATABLE), !!(flags & DI_DIM), itemAlign, screenAlign, false, boxsize); - } - //============================================================================ // // // //============================================================================ - void DrawImage(String imagename, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = ALIGN_TOP|ALIGN_LEFT, Vector2 boxsize = (-1, -1), int itemAlign = ALIGN_TOP|ALIGN_LEFT, int flags = 0, Vector2 scale = (1., 1.) ) - { - let tex = TexMan.CheckForTexture(imagename, TexMan.TYPE_MiscPatch); - DrawTexture(tex, pos, animated, screenalign, alpha, boxsize, itemAlign, flags, scale); - } - - //============================================================================ - // - // - // - //============================================================================ - - void DrawIcon(int icontype, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = ALIGN_TOP|ALIGN_LEFT, Vector2 boxsize = (-1, -1), int itemAlign = ALIGN_TOP|ALIGN_LEFT, int flags = 0) - { - TextureID texture; - Vector2 applyscale = (1, 1); - Inventory atype1, atype2; - switch (icontype) - { - case ITYPE_PLAYERICON: - texture = CPlayer.mo.ScoreIcon; - break; - - case ITYPE_AMMO1: - case ITYPE_AMMO2: - [atype1, atype2] = GetCurrentAmmo(); - [texture, applyscale] = GetIcon(icontype == ITYPE_AMMO1? atype1 : atype2, flags, true); - break; - - case ITYPE_ARMOR: - [texture, applyscale] = GetIcon(CPlayer.mo.FindInventory("BasicArmor"), flags, false); - break; - - case ITYPE_WEAPON: - [texture, applyscale] = GetIcon(CPlayer.ReadyWeapon, flags, false); - break; - - case ITYPE_SIGIL: - [texture, applyscale] = GetIcon(CPlayer.mo.FindInventory("Sigil"), flags, false); - break; - - case ITYPE_SELECTEDINVENTORY: - if (CPlayer.mo.InvSel != NULL) - texture = CPlayer.mo.InvSel.Icon; - break; - } - DrawTexture(texture, pos, animated, screenalign, alpha, boxsize, itemAlign, flags, applyscale); - } - - //============================================================================ - // - // - // - //============================================================================ - - void DrawHexenArmor(int armortype, String image, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = ALIGN_TOP|ALIGN_LEFT, Vector2 boxsize = (-1, -1), int itemAlign = ALIGN_TOP|ALIGN_LEFT, int flags = 0) + void DrawHexenArmor(int armortype, String image, Vector2 pos, int flags = 0, double alpha = 1.0, Vector2 boxsize = (-1, -1), Vector2 scale = (1.,1.)) { let harmor = HexenArmor(statusBar.CPlayer.mo.FindInventory("HexenArmor")); if (harmor != NULL) @@ -681,7 +723,7 @@ class BaseStatusBar native ui } else return; } - DrawImage(image, pos, animated, screenalign, alpha, boxsize, itemAlign, flags); + DrawImage(image, pos, flags, alpha, boxsize, scale); } //============================================================================ @@ -690,15 +732,212 @@ class BaseStatusBar native ui // //============================================================================ - void DrawInventoryIcon(class item, String image, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = ALIGN_TOP|ALIGN_LEFT, Vector2 boxsize = (-1, -1), int itemAlign = ALIGN_TOP|ALIGN_LEFT, int flags = 0) + void DrawInventoryIcon(Inventory item, Vector2 pos, int flags = 0, double alpha = 1.0, Vector2 boxsize = (-1, -1), Vector2 scale = (1.,1.)) { - let texture = GetDefaultByType(item).Icon; - if (texture.IsValid()) + static const String flashimgs[]= { "USEARTID", "USEARTIC", "USEARTIB", "USEARTIA" }; + TextureID texture; + Vector2 applyscale; + [texture, applyscale] = GetIcon(item, flags, false); + + if((flags & DI_ARTIFLASH) && artiflashTick > 0) { - DrawTexture(texture, pos, animated, screenalign, alpha, boxsize, itemAlign, flags); + DrawImage(flashimgs[artiflashTick-1], pos, flags | DI_TRANSLATABLE, alpha, boxsize); + } + else if (texture.IsValid()) + { + if ((flags & DI_DIMDEPLETED) && item.Amount <= 0) flags |= DI_DIM; + applyscale.X *= scale.X; + applyscale.Y *= scale.Y; + DrawTexture(texture, pos, flags, alpha, boxsize, applyscale); } } + //============================================================================ + // + // + // + //============================================================================ + + void DrawShader(int which, Vector2 pos, Vector2 size, int flags = 0, double alpha = 1.) + { + static const String texnames[] = {"BarShaderHF", "BarShaderHR", "BarShaderVF", "BarShaderVR" }; + DrawImage(texnames[which], pos, DI_ITEM_LEFT_TOP|DI_ALPHAMAPPED|DI_FORCEFILL | (flags & ~(DI_ITEM_HMASK|DI_ITEM_VMASK)), alpha, size); + } + + //============================================================================ + // + // + // + //============================================================================ + + Vector2, int AdjustPosition(Vector2 position, int flags, double width, double height) + { + // This must be done here, before altered coordinates get sent to the draw functions. + if (!(flags & DI_SCREEN_MANUAL_ALIGN)) + { + if (position.x < 0) flags |= DI_SCREEN_RIGHT; + else flags |= DI_SCREEN_LEFT; + if (position.y < 0) flags |= DI_SCREEN_BOTTOM; + else flags |= DI_SCREEN_TOP; + } + + // placement by offset is not supported because the inventory bar is a composite. + switch (flags & DI_ITEM_HMASK) + { + case DI_ITEM_HCENTER: position.x -= width / 2; break; + case DI_ITEM_RIGHT: position.x -= width; break; + } + + switch (flags & DI_ITEM_VMASK) + { + case DI_ITEM_VCENTER: position.y -= height / 2; break; + case DI_ITEM_BOTTOM: position.y -= height; break; + } + + // clear all alignment flags so that the following code only passes on the rest + flags &= ~(DI_ITEM_VMASK|DI_ITEM_HMASK); + return position, flags; + } + + //============================================================================ + // + // note that this does not implement chain wiggling, this is because + // it would severely complicate the parameter list. The calling code is + // normally in a better position to do the needed calculations anyway. + // + //============================================================================ + + void DrawGem(String chain, String gem, int displayvalue, int maxrange, Vector2 pos, int leftpadding, int rightpadding, int chainmod, int flags = 0) + { + TextureID chaintex = TexMan.CheckForTexture(chain, TexMan.TYPE_MiscPatch); + if (!chaintex.IsValid()) return; + Vector2 chainsize = TexMan.GetScaledSize(chaintex); + [pos, flags] = AdjustPosition(pos, flags, chainsize.X, chainsize.Y); + + displayvalue = clamp(displayvalue, 0, maxrange); + int offset = int(double(chainsize.X - leftpadding - rightpadding) * displayvalue / maxrange); + + DrawTexture(chaintex, pos + (offset % chainmod, 0), flags | DI_ITEM_LEFT_TOP); + DrawImage(gem, pos + (offset + leftPadding, 0), flags | DI_ITEM_LEFT_TOP); + } + + //============================================================================ + // + // DrawBar + // + //============================================================================ + + void DrawBar(String ongfx, String offgfx, double curval, double maxval, Vector2 position, int border, int vertical, int flags = 0, double alpha = 1.) + { + let ontex = TexMan.CheckForTexture(ongfx, TexMan.TYPE_MiscPatch); + if (!ontex.IsValid()) return; + let offtex = TexMan.CheckForTexture(offgfx, TexMan.TYPE_MiscPatch); + + Vector2 texsize = TexMan.GetScaledSize(ontex); + [position, flags] = AdjustPosition(position, flags, texsize.X, texsize.Y); + + double value = clamp(curval / maxval, 0, 1); + if(border != 0) value = 1. - value; //invert since the new drawing method requires drawing the bg on the fg. + + + // {cx, cb, cr, cy} + double Clip[4]; + Clip[0] = Clip[1] = Clip[2] = Clip[3] = 0; + + bool horizontal = !(vertical & SHADER_VERT); + bool reverse = !!(vertical & SHADER_REVERSE); + double sizeOfImage = (horizontal ? texsize.X - border*2 : texsize.Y - border*2); + Clip[(!horizontal) | ((!reverse)<<1)] = sizeOfImage - sizeOfImage *value; + + if(border != 0) + { + for(int i = 0; i < 4; i++) Clip[i] += border; + + //Draw the whole foreground + DrawTexture(ontex, position, flags | DI_ITEM_LEFT_TOP); + // SetClip + } + + if (offtex.IsValid() && TexMan.GetScaledSize(offtex) == texsize) DrawTexture(offtex, position, flags | DI_ITEM_LEFT_TOP); + else Fill(color(255,0,0,0), position.X + Clip[0], position.Y + Clip[1], texsize.X - Clip[0] - Clip[2], texsize.Y - Clip[1] - Clip[3]); + + if (border == 0) + { + // SetClip + DrawTexture(ontex, position, flags | DI_ITEM_LEFT_TOP); + } + // UnsetClip + } + + //============================================================================ + // + // DrawInventoryBar + // + // This function needs too many parameters, so most have been offloaded to + // a struct to keep code readable and allow initialization somewhere outside + // the actual drawing code. + // + //============================================================================ + + // Except for the placement information this gets all info from the struct that gets passed in. + void DrawInventoryBar(InventoryBarState parms, Vector2 position, int numfields, int flags = 0, double bgalpha = 1.) + { + double width = parms.boxsize.X * numfields; + [position, flags] = AdjustPosition(position, flags, width, parms.boxsize.Y); + + CPlayer.mo.InvFirst = ValidateInvFirst(numfields); + if (CPlayer.mo.InvFirst == null) return; // Player has no listed inventory items. + + Vector2 boxsize = parms.boxsize; + // First draw all the boxes + for(int i = 0; i < numfields; i++) + { + DrawTexture(parms.box, position + (boxsize.X * i, 0), flags | DI_ITEM_LEFT_TOP, bgalpha); + } + + // now the items and the rest + + Vector2 itempos = position + boxsize / 2; + Vector2 textpos = position + boxsize - (1, 1 + parms.amountfont.mFont.GetHeight()); + + int i = 0; + Inventory item; + for(item = CPlayer.mo.InvFirst; item != NULL && i < numfields; item = item.NextInv()) + { + for(int j = 0; j < 2; j++) + { + if (j ^ !!(parms.flags & DI_DRAWCURSORFIRST)) + { + if (item == CPlayer.mo.InvSel) + { + double flashAlpha = bgalpha; + if (flags & DI_ARTIFLASH) flashAlpha *= itemflashFade; + DrawTexture(parms.selector, position + parms.selectofs + (boxsize.X * i, 0), flags | DI_ITEM_LEFT_TOP, flashAlpha); + } + } + else + { + DrawInventoryIcon(item, itempos + (boxsize.X * i, 0), flags | DI_ITEM_CENTER ); + } + } + + if (parms.amountfont != null && (item.Amount > 1 || (parms.flags & DI_ALWAYSSHOWCOUNTERS))) + { + DrawString(parms.amountfont, FormatNumber(item.Amount, 0, 5), textpos + (boxsize.X * i, 0), flags | DI_TEXT_ALIGN_RIGHT, parms.cr, parms.itemalpha); + } + i++; + } + // Is there something to the left? + if (CPlayer.mo.FirstInv() != CPlayer.mo.InvFirst) + { + DrawTexture(parms.left, position + (-parms.arrowoffset.X, parms.arrowoffset.Y), flags | DI_ITEM_RIGHT|DI_ITEM_VCENTER); + } + // Is there something to the right? + if (item != NULL) + { + DrawTexture(parms.right, position + parms.arrowoffset + (width, 0), flags | DI_ITEM_LEFT|DI_ITEM_VCENTER); + } + } } //============================================================================ @@ -721,6 +960,11 @@ class LinearValueInterpolator : Object return v; } + void Reset(int value) + { + mCurrentValue = value; + } + // This must be called peroiodically in the status bar's Tick function. // Do not call this in the Draw function because that may skip some frames! void Update(int destvalue) @@ -746,23 +990,30 @@ class DynamicValueInterpolator : Object { int mCurrentValue; int mMinChange; + int mMaxChange; double mChangeFactor; - static DynamicValueInterpolator Create(int startval, double changefactor, int minchange) + static DynamicValueInterpolator Create(int startval, double changefactor, int minchange, int maxchange) { let v = new("DynamicValueInterpolator"); v.mCurrentValue = startval; v.mMinChange = minchange; + v.mMaxChange = maxchange; v.mChangeFactor = changefactor; return v; } + void Reset(int value) + { + mCurrentValue = value; + } + // This must be called peroiodically in the status bar's Tick function. // Do not call this in the Draw function because that may skip some frames! void Update(int destvalue) { - int diff = int(max(abs(destvalue - mCurrentValue) * mChangeFactor, mMinChange)); + int diff = int(clamp(abs(destvalue - mCurrentValue) * mChangeFactor, mMinChange, mMaxChange)); if (mCurrentValue > destvalue) { mCurrentValue = max(destvalue, mCurrentValue - diff); diff --git a/wadsrc/static/zscript/statusbar/strife_sbar.txt b/wadsrc/static/zscript/statusbar/strife_sbar.txt index cb2ef8a5c..fc1862698 100644 --- a/wadsrc/static/zscript/statusbar/strife_sbar.txt +++ b/wadsrc/static/zscript/statusbar/strife_sbar.txt @@ -15,23 +15,10 @@ class StrifeStatusBar : BaseStatusBar { imgINVCURS, imgCURSOR01, - imgINVBACK, - imgINVTOP, imgINVPOP, imgINVPOP2, imgINVPBAK, imgINVPBAK2, - imgFONG0, - imgFONG1, - imgFONG2, - imgFONG3, - imgFONG4, - imgFONG5, - imgFONG6, - imgFONG7, - imgFONG8, - imgFONG9, - imgFONG_PERCENT, imgFONY0, imgFONY1, imgFONY2, @@ -43,10 +30,6 @@ class StrifeStatusBar : BaseStatusBar imgFONY8, imgFONY9, imgFONY_PERCENT, - imgCOMM, - imgMEDI, - imgARM1, - imgARM2, imgNEGATIVE, }; @@ -54,22 +37,41 @@ class StrifeStatusBar : BaseStatusBar int CursorImage; int CurrentPop, PendingPop, PopHeight, PopHeightChange; int KeyPopPos, KeyPopScroll; - double ItemFlash; + + HUDFont mYelFont, mGrnFont, mBigFont; override void Init() { + static const Name strifeLumpNames[] = + { + "INVCURS", "CURSOR01", "INVPOP", "INVPOP2", + "INVPBAK", "INVPBAK2", + "INVFONY0", "INVFONY1", "INVFONY2", "INVFONY3", "INVFONY4", + "INVFONY5", "INVFONY6", "INVFONY7", "INVFONY8", "INVFONY9", + "INVFONY%", "" + + }; + Super.Init(); SetSize(32, 320, 200); - DoCommonInit(); + Reset(); + + for(int i = 0; i <= imgNEGATIVE; i++) + { + Images[i] = TexMan.CheckForTexture(strifeLumpNames[i], TexMan.TYPE_MiscPatch); + } + + CursorImage = Images[imgINVCURS].IsValid() ? imgINVCURS : imgCURSOR01; + + mYelFont = HUDFont.Create("Indexfont_Strife_Yellow", 7, true, 1, 1); + mGrnFont = HUDFont.Create("Indexfont_Strife_Green", 7, true, 1, 1); + mBigFont = HUDFont.Create("BigFont", 0, false, 2, 2); } override void NewGame () { - DoCommonInit (); - if (CPlayer != NULL) - { - AttachToPlayer (CPlayer); - } + Super.NewGame(); + Reset (); } override void Draw (int state, double TicFrac) @@ -78,21 +80,22 @@ class StrifeStatusBar : BaseStatusBar if (state == HUD_StatusBar) { - fullscreenoffsets = false; + BeginStatusBar(320, 200, 32); DrawMainBar (TicFrac); } else { if (state == HUD_Fullscreen) { - fullscreenoffsets = true; + BeginHUD(320, 200, 1., false); DrawFullScreenStuff (); } // Draw pop screen (log, keys, and status) if (CurrentPop != POP_None && PopHeight < 0) { - fullscreenoffsets = false; + // This uses direct low level draw commands and would otherwise require calling + // BeginStatusBar(320, 200, false, true); DrawPopScreen (screen.GetHeight(), TicFrac); } } @@ -141,50 +144,19 @@ class StrifeStatusBar : BaseStatusBar return false; } - void DoCommonInit () + void Reset () { - static const String strifeLumpNames[] = - { - "INVCURS", "CURSOR01", "INVBACK", "INVTOP", "INVPOP", "INVPOP2", - "INVPBAK", "INVPBAK2", - "INVFONG0", "INVFONG1", "INVFONG2", "INVFONG3", "INVFONG4", - "INVFONG5", "INVFONG6", "INVFONG7", "INVFONG8", "INVFONG9", - "INVFONG%", - "INVFONY0", "INVFONY1", "INVFONY2", "INVFONY3", "INVFONY4", - "INVFONY5", "INVFONY6", "INVFONY7", "INVFONY8", "INVFONY9", - "INVFONY%", - "I_COMM", "I_MDKT", "I_ARM1", "I_ARM2", "" - - }; - - for(int i = 0; i <= imgNEGATIVE; i++) - { - Images[i] = TexMan.CheckForTexture(strifeLumpNames[i], TexMan.TYPE_MiscPatch); - } - - CursorImage = Images[imgINVCURS].IsValid() ? imgINVCURS : imgCURSOR01; - CurrentPop = POP_None; PendingPop = POP_NoChange; PopHeight = 0; KeyPopPos = 0; KeyPopScroll = 0; - ItemFlash = 0; } override void Tick () { Super.Tick (); - if (ItemFlash > 0) - { - ItemFlash -= 1/14.; - if (ItemFlash < 0) - { - ItemFlash = 0; - } - } - PopHeightChange = 0; if (PendingPop != POP_NoChange) { @@ -228,11 +200,6 @@ class StrifeStatusBar : BaseStatusBar } } - override void FlashItem (Class itemtype) - { - ItemFlash = 0.75; - } - private void FillBar(double x, double y, double start, double stopp, Color color1, Color color2) { Vector2 virt = Scaled? (320., 200.) : (screen.GetWidth(), screen.GetHeight()); @@ -304,11 +271,11 @@ class StrifeStatusBar : BaseStatusBar DrawPopScreen (Scaled ? (ST_Y - 8) * screen.GetHeight() / 200 : ST_Y - 8, TicFrac); } - DrawTexture(Images[imgINVBACK], (0, 0), true, 1.0, itemAlign:ALIGN_OFFSETS); - DrawTexture(Images[imgINVTOP], (0, -8), true, 1.0, itemAlign:ALIGN_OFFSETS); + DrawImage("INVBACK", (0, 168), DI_ITEM_OFFSETS); + DrawImage("INVTOP", (0, 160), DI_ITEM_OFFSETS); // Health - DrawString("Indexfont_Strife_Green", FormatNumber(CPlayer.health, 3, 5, 0), (86, -6), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, 0, 7, true, 1, 1); + DrawString(mGrnFont, FormatNumber(CPlayer.health, 3, 5), (79, 162), DI_TEXT_ALIGN_RIGHT); int points; if (CPlayer.cheats & CF_GODMODE) { @@ -318,33 +285,30 @@ class StrifeStatusBar : BaseStatusBar { points = min(CPlayer.health, 200); } - DrawHealthBar (points, 49, 4); - DrawHealthBar (points, 49, 7); + DrawHealthBar (points, 49, 172); + DrawHealthBar (points, 49, 175); // Armor item = CPlayer.mo.FindInventory('BasicArmor'); if (item != NULL && item.Amount > 0) { - DrawTexture(item.Icon, (2, 9), true, 1.0, itemAlign:ALIGN_OFFSETS); - DrawString("Indexfont_Strife_Yellow", FormatNumber(item.Amount, 3, 5, 0), (34, 23), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, 0, 7, true, 1, 1); + DrawInventoryIcon(item, (2, 177), DI_ITEM_OFFSETS); + DrawString(mYelFont, FormatNumber(item.Amount, 3, 5), (27, 191), DI_TEXT_ALIGN_RIGHT); } // Ammo - Inventory ammo1, ammo2; - int ammocount1, ammocount2; - - [ammo1, ammo2, ammocount1, ammocount2] = GetCurrentAmmo (); + Inventory ammo1 = GetCurrentAmmo (); if (ammo1 != NULL) { - DrawString("Indexfont_Strife_Green", FormatNumber(ammo1.Amount, 3, 5, 0), (318, -6), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, 0, 7, true, 1, 1); - DrawTexture (ammo1.Icon, (290, 13), true, 1.0, itemAlign:ALIGN_OFFSETS); + DrawString(mGrnFont, FormatNumber(ammo1.Amount, 3, 5), (311, 162), DI_TEXT_ALIGN_RIGHT); + DrawInventoryIcon (ammo1, (290, 181), DI_ITEM_OFFSETS); } // Sigil item = CPlayer.mo.FindInventory('Sigil'); if (item != NULL) { - DrawTexture (item.Icon, (253, 7), true, 1.0, itemAlign:ALIGN_OFFSETS); + DrawInventoryIcon (item, (253, 175), DI_ITEM_OFFSETS); } // Inventory @@ -353,32 +317,29 @@ class StrifeStatusBar : BaseStatusBar i = 0; for (item = CPlayer.mo.InvFirst; item != NULL && i < 6; item = item.NextInv()) { + int flags = item.Amount <= 0? DI_ITEM_OFFSETS|DI_DIM : DI_ITEM_OFFSETS; if (item == CPlayer.mo.InvSel) { - DrawTexture (item.Icon, (42 + 35*i, 12), true, 1. - ItemFlash, itemAlign:ALIGN_OFFSETS, item.Amount <= 0? DI_DIM : 0); + DrawTexture (Images[CursorImage], (42 + 35*i, 180), flags, 1. - itemflashFade); } - if (item.Icon.isValid()) - { - DrawTexture (item.Icon, (48 + 35*i, 14), true, 1.0, itemAlign:ALIGN_OFFSETS, item.Amount <= 0? DI_DIM : 0); - } - DrawString("Indexfont_Strife_Yellow", FormatNumber(item.Amount, 3, 5, 0), (81 + 35*i, 23), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, 0, 7, true, 1, 1); + DrawInventoryIcon (item, (48 + 35*i, 182), flags); + DrawString(mYelFont, FormatNumber(item.Amount, 3, 5), (75 + 35*i, 191), DI_TEXT_ALIGN_RIGHT); i++; } } protected void DrawFullScreenStuff () { - // Draw health - - DrawString("Indexfont_Strife_Green", FormatNumber(CPlayer.health, 3, 0, 0), (4, -10), 1., (CPlayer.health < CPlayer.mo.RunHealth)? Font.CR_BRICK : Font.CR_UNTRANSLATED, TEXT_LEFT, ALIGN_LEFT|ALIGN_BOTTOM, 7, true, 1, 1); - DrawTexture(Images[imgMEDI], (14, -17), false, 1.0, ALIGN_BOTTOM|ALIGN_LEFT, itemalign: ALIGN_BOTTOM|ALIGN_HCENTER); + // Draw health (use red color if health is below the run health threashold.) + DrawString(mGrnFont, FormatNumber(CPlayer.health, 3), (4, -10), DI_TEXT_ALIGN_LEFT, (CPlayer.health < CPlayer.mo.RunHealth)? Font.CR_BRICK : Font.CR_UNTRANSLATED); + DrawImage("I_MDKT", (14, -17)); // Draw armor let armor = CPlayer.mo.FindInventory('BasicArmor'); if (armor != NULL && armor.Amount != 0) { - DrawString("Indexfont_Strife_Yellow", FormatNumber(armor.Amount, 3, 0, 0), (35, -10), 1., Font.CR_UNTRANSLATED, TEXT_LEFT, ALIGN_LEFT|ALIGN_BOTTOM, 7, true, 1, 1); - DrawTexture(armor.Icon, (45, -17), false, 1.0, ALIGN_BOTTOM|ALIGN_LEFT, itemalign: ALIGN_BOTTOM|ALIGN_HCENTER); + DrawString(mYelFont, FormatNumber(armor.Amount, 3), (35, -10)); + DrawInventoryIcon(armor, (45, -17)); } // Draw ammo @@ -389,19 +350,19 @@ class StrifeStatusBar : BaseStatusBar if (ammo1 != NULL) { // Draw primary ammo in the bottom-right corner - DrawString("Indexfont_Strife_Green", FormatNumber(ammo1.Amount, 3, 0, 0), (-23, -10), 1., Font.CR_UNTRANSLATED, TEXT_LEFT, ALIGN_RIGHT|ALIGN_BOTTOM, 7, true, 1, 1); - DrawTexture(ammo1.Icon, (-14, -17), false, 1.0, ALIGN_BOTTOM|ALIGN_RIGHT, itemalign: ALIGN_BOTTOM|ALIGN_HCENTER); + DrawString(mGrnFont, FormatNumber(ammo1.Amount, 3), (-23, -10)); + DrawInventoryIcon(ammo1, (-14, -17)); if (ammo2 != NULL && ammo1!=ammo2) { // Draw secondary ammo just above the primary ammo - DrawString("Indexfont_Strife_Green", FormatNumber(ammo1.Amount, 3, 0, 0), (-23, -48), 1., Font.CR_UNTRANSLATED, TEXT_LEFT, ALIGN_RIGHT|ALIGN_BOTTOM, 7, true, 1, 1); - DrawTexture(ammo1.Icon, (-14, -55), false, 1.0, ALIGN_BOTTOM|ALIGN_RIGHT, itemalign: ALIGN_BOTTOM|ALIGN_HCENTER); + DrawString(mGrnFont, FormatNumber(ammo1.Amount, 3), (-23, -48)); + DrawInventoryIcon(ammo1, (-14, -55)); } } if (deathmatch) { // Draw frags (in DM) - DrawString("BigFont", FormatNumber(CPlayer.FragCount, 3, 0, 0), (-44, 1), 1., Font.CR_UNTRANSLATED, TEXT_LEFT, ALIGN_RIGHT|ALIGN_TOP, 0, false, 2, 2); + DrawString(mBigFont, FormatNumber(CPlayer.FragCount, 3), (4, 1)); } // Draw inventory @@ -409,12 +370,12 @@ class StrifeStatusBar : BaseStatusBar { if (CPlayer.mo.InvSel != null) { - if (ItemFlash > 0) + if (itemflashFade > 0) { - DrawTexture(Images[CursorImage], (-28, -15), true, 1.0, ALIGN_BOTTOM|ALIGN_RIGHT, ItemAlign:ALIGN_BOTTOM|ALIGN_RIGHT); + DrawTexture(Images[CursorImage], (-42, -15)); } - DrawString("Indexfont_Strife_Yellow", FormatNumber(CPlayer.mo.InvSel.Amount, 3, 5, 0), (-23, -10), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, ALIGN_BOTTOM|ALIGN_RIGHT, 7, true, 1, 1); - DrawTexture(CPlayer.mo.InvSel.Icon, (-42, -17), true, 1.0, ALIGN_BOTTOM|ALIGN_RIGHT, ItemAlign:ALIGN_BOTTOM|ALIGN_HCENTER, CPlayer.mo.InvSel.Amount > 0 ? 0 : DI_DIM); + DrawString(mYelFont, FormatNumber(CPlayer.mo.InvSel.Amount, 3, 5), (-30, -10), DI_TEXT_ALIGN_RIGHT); + DrawInventoryIcon(CPlayer.mo.InvSel, (-42, -17), DI_DIMDEPLETED); } } else @@ -429,18 +390,17 @@ class StrifeStatusBar : BaseStatusBar { if (item == CPlayer.mo.InvSel) { - DrawTexture(Images[CursorImage], (-90+i*35, -3), true, 0.75, ALIGN_CENTER_BOTTOM, ItemAlign:ALIGN_CENTER_BOTTOM); + DrawTexture(Images[CursorImage], (-90+i*35, -3), DI_SCREEN_CENTER_BOTTOM, 0.75); } if (item.Icon.isValid()) { - DrawTexture(item.Icon, (-90+i*35, -5), true, 0.75, ALIGN_CENTER_BOTTOM, box, ALIGN_CENTER_BOTTOM, CPlayer.mo.InvSel.Amount > 0 ? 0 : DI_DIM); + DrawInventoryIcon(item, (-90+i*35, -5), DI_SCREEN_CENTER_BOTTOM|DI_DIMDEPLETED, 0.75); } - DrawString("Indexfont_Strife_Yellow", FormatNumber(item.Amount, 3, 5, 0), (-65 + i*35, -8), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, ALIGN_CENTER_BOTTOM, 7, true, 1, 1); + DrawString(mYelFont, FormatNumber(item.Amount, 3, 5), (-72 + i*35, -8), DI_TEXT_ALIGN_RIGHT|DI_SCREEN_CENTER_BOTTOM); ++i; } } } - fullscreenoffsets = false; } protected void DrawPopScreen (int bottom, double TicFrac)