From 6760e01a0d6f9bca3961c084dc2b2d2f9583e0d9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 24 Mar 2017 20:07:22 +0100 Subject: [PATCH 1/5] - implemented the status bar's DrawString function and ported the fullscreen HUD part of the Strife status bar to use the new functionality. --- src/g_statusbar/shared_sbar.cpp | 172 +++++++++++- src/gl/textures/gl_material.cpp | 2 +- wadsrc/static/fontdefs.txt | 29 ++ wadsrc/static/zscript/statusbar/statusbar.txt | 254 ++++++++++++++---- .../static/zscript/statusbar/strife_sbar.txt | 196 ++------------ 5 files changed, 424 insertions(+), 229 deletions(-) diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index dfbd22ffb..092a49710 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -1517,8 +1517,135 @@ void DBaseStatusBar::DrawString(FFont *font, const FString &cstring, double x, d x -= static_cast ((spacing)* cstring.Len()) / 2; break; } + + const uint8_t* str = (const uint8_t*)cstring.GetChars(); + const EColorRange boldTranslation = EColorRange(translation ? translation - 1 : NumTextColors - 1); + int fontcolor = translation; + double orgx = 0, orgy = 0; + + if (fullscreenOffsets) + { + if (hud_scale) + { + shadowX *= (int)cleanScale.X; + shadowY *= (int)cleanScale.Y; + } + + switch (screenalign & HMASK) + { + default: orgx = 0; break; + case HCENTER: orgx = screen->GetWidth() / 2; break; + case RIGHT: orgx = screen->GetWidth(); break; + } + + switch (screenalign & VMASK) + { + default: orgy = 0; break; + case VCENTER: orgy = screen->GetHeight() / 2; break; + case BOTTOM: orgy = screen->GetHeight(); break; + } + + if (screenalign == (RIGHT | TOP) && vid_fps) orgy += 10; + } + int ch; + while (ch = *str++, ch != '\0') + { + if (ch == ' ') + { + x += monospaced ? spacing : font->GetSpaceWidth() + spacing; + continue; + } + else if (ch == TEXTCOLOR_ESCAPE) + { + EColorRange newColor = V_ParseFontColor(str, translation, boldTranslation); + if (newColor != CR_UNDEFINED) + fontcolor = newColor; + continue; + } + + int width; + FTexture* c = font->GetChar((unsigned char)ch, &width); + if (c == NULL) //missing character. + { + continue; + } + + if (!monospaced) //If we are monospaced lets use the offset + x += (c->LeftOffset + 1); //ignore x offsets since we adapt to character size + + double rx, ry, rw, rh; + rx = x + drawOffset.X; + ry = y + drawOffset.Y; + 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 - (Scaled ? VerticalResolution : 200) + RelTop; + if (Scaled) + screen->VirtualToRealCoords(rx, ry, rw, rh, HorizontalResolution, VerticalResolution, true); + else + { + ry += (200 - VerticalResolution); + } + } + else + { + if (hud_scale) + { + rx *= cleanScale.X; + ry *= cleanScale.Y; + rw *= cleanScale.X; + rh *= cleanScale.Y; + } + rx += orgx; + ry += orgy; + } + // 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) + { + screen->DrawChar(font, CR_UNTRANSLATED, rx + shadowX, ry + shadowY, ch, + DTA_DestWidthF, rw, + DTA_DestHeightF, rh, + DTA_Alpha, (Alpha * HR_SHADOW), + DTA_FillColor, 0, + TAG_DONE); + } + screen->DrawChar(font, fontcolor, rx, ry, ch, + DTA_DestWidthF, rw, + DTA_DestHeightF, rh, + DTA_Alpha, Alpha, + TAG_DONE); + + if (!monospaced) + x += width + spacing - (c->LeftOffset + 1); + else + x += spacing; + } + } + + DEFINE_ACTION_FUNCTION(DBaseStatusBar, DrawString) { PARAM_SELF_PROLOGUE(DBaseStatusBar); @@ -1527,7 +1654,7 @@ DEFINE_ACTION_FUNCTION(DBaseStatusBar, DrawString) PARAM_FLOAT(x); PARAM_FLOAT(y); PARAM_FLOAT(alpha); - PARAM_BOOL(trans); + PARAM_INT(trans); PARAM_INT(ialign); PARAM_INT(salign); PARAM_INT_DEF(spacing); @@ -1636,3 +1763,46 @@ DEFINE_ACTION_FUNCTION(DBaseStatusBar, GetGlobalACSArrayString) PARAM_INT(index); ACTION_RETURN_STRING(FBehavior::StaticLookupString(ACS_GlobalArrays[arrayno][index])); } + +DEFINE_ACTION_FUNCTION(DBaseStatusBar, GetGlobalACSValue) +{ + PARAM_PROLOGUE; + PARAM_INT(index); + ACTION_RETURN_INT(ACS_GlobalVars[index]); +} + +DEFINE_ACTION_FUNCTION(DBaseStatusBar, GetGlobalACSArrayValue) +{ + PARAM_PROLOGUE; + PARAM_INT(arrayno); + PARAM_INT(index); + ACTION_RETURN_INT(ACS_GlobalArrays[arrayno][index]); +} + +enum ENumFlags +{ + FNF_FILLZEROS, + FNF_WHENNOTZERO, +}; + +DEFINE_ACTION_FUNCTION(DBaseStatusBar, FormatNumber) +{ + PARAM_PROLOGUE; + PARAM_INT(number); + PARAM_INT(minsize); + PARAM_INT(maxsize); + PARAM_INT(flags); + PARAM_STRING_DEF(prefix); + static int maxvals[] = { 1, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999 }; + + if (number == 0 && (flags & FNF_WHENNOTZERO)) ACTION_RETURN_STRING(""); + if (maxsize > 0 && maxsize < 10) + { + number = clamp(number, -maxvals[maxsize - 1], maxvals[maxsize]); + } + FString fmt; + if (minsize <= 1) fmt.Format("%s%d", prefix.GetChars(), number); + else if (flags & FNF_FILLZEROS) fmt.Format("%s%0*d", prefix.GetChars(), minsize, number); + else fmt.Format("%s%*d", prefix.GetChars(), minsize, number); + ACTION_RETURN_STRING(fmt); +} diff --git a/src/gl/textures/gl_material.cpp b/src/gl/textures/gl_material.cpp index b4a13af7c..b981b4ecf 100644 --- a/src/gl/textures/gl_material.cpp +++ b/src/gl/textures/gl_material.cpp @@ -490,7 +490,7 @@ FMaterial::FMaterial(FTexture * tx, bool expanded) mSpriteU[1] = mSpriteV[1] = 1.f; FTexture *basetex = (tx->bWarped && gl.legacyMode)? tx : tx->GetRedirect(false); - // allow the redirect only if the textute is not expanded or the scale matches. + // allow the redirect only if the texture is not expanded or the scale matches. if (!expanded || (tx->Scale.X == basetex->Scale.X && tx->Scale.Y == basetex->Scale.Y)) { mBaseLayer = ValidateSysTexture(basetex, expanded); diff --git a/wadsrc/static/fontdefs.txt b/wadsrc/static/fontdefs.txt index 3858ef742..c70c8024d 100644 --- a/wadsrc/static/fontdefs.txt +++ b/wadsrc/static/fontdefs.txt @@ -61,6 +61,35 @@ INDEXFONT_DOOM 9 STYSNUM9 } +INDEXFONT_STRIFE_YELLOW +{ + % INVFONY% + 0 INVFONY0 + 1 INVFONY1 + 2 INVFONY2 + 3 INVFONY3 + 4 INVFONY4 + 5 INVFONY5 + 6 INVFONY6 + 7 INVFONY7 + 8 INVFONY8 + 9 INVFONY9 +} + +INDEXFONT_STRIFE_GREEN +{ + % INVFONG% + 0 INVFONG0 + 1 INVFONG1 + 2 INVFONG2 + 3 INVFONG3 + 4 INVFONG4 + 5 INVFONG5 + 6 INVFONG6 + 7 INVFONG7 + 8 INVFONG8 + 9 INVFONG9 +} // Doom and Chex intermissions use special text glyphs. The Raven and Strife // games just use the standard big font. diff --git a/wadsrc/static/zscript/statusbar/statusbar.txt b/wadsrc/static/zscript/statusbar/statusbar.txt index 742d0995b..22bfe6222 100644 --- a/wadsrc/static/zscript/statusbar/statusbar.txt +++ b/wadsrc/static/zscript/statusbar/statusbar.txt @@ -46,19 +46,24 @@ class BaseStatusBar native ui DI_SKIPREADY = 0x8, DI_ALTICONFIRST = 0x10, DI_TRANSLATABLE = 0x20, - DI_FORCESCALE = 0x40 + DI_FORCESCALE = 0x40, + DI_DIM = 0x80, }; enum IconType { - PLAYERICON = 1000, - AMMO1, - AMMO2, - ARMOR, - WEAPONICON, - SIGIL, - WEAPONSLOT, - SELECTEDINVENTORYICON, + ITYPE_PLAYERICON = 1000, + ITYPE_AMMO1, + ITYPE_AMMO2, + ITYPE_ARMOR, + ITYPE_WEAPON, + ITYPE_SIGIL, + ITYPE_WEAPONSLOT, + ITYPE_SELECTEDINVENTORY, + } + + enum HexArmorType + { HEXENARMOR_ARMOR, HEXENARMOR_SHIELD, HEXENARMOR_HELM, @@ -67,35 +72,36 @@ class BaseStatusBar native ui enum EAlign { - TOP = 0, - VCENTER = 1, - BOTTOM = 2, - VOFFSET = 3, - VMASK = 3, + ALIGN_TOP = 0, + ALIGN_VCENTER = 1, + ALIGN_BOTTOM = 2, + ALIGN_VOFFSET = 3, + ALIGN_VMASK = 3, - LEFT = 0, - HCENTER = 4, - RIGHT = 8, - HOFFSET = 12, - HMASK = 12, + ALIGN_LEFT = 0, + ALIGN_HCENTER = 4, + ALIGN_RIGHT = 8, + ALIGN_HOFFSET = 12, + ALIGN_HMASK = 12, - CENTER = VCENTER|HCENTER, - CENTER_BOTTOM = BOTTOM|HCENTER + ALIGN_CENTER = ALIGN_VCENTER|ALIGN_HCENTER, + ALIGN_CENTER_BOTTOM = ALIGN_BOTTOM|ALIGN_HCENTER, + ALIGN_OFFSETS = ALIGN_HOFFSET|ALIGN_VOFFSET }; enum ETextAlign { - ALIGN_LEFT = 0, - ALIGN_CENTER = 1, - ALIGN_RIGHT = 2 + TEXT_LEFT = 0, + TEXT_CENTER = 1, + TEXT_RIGHT = 2 }; enum SBGameModes { - SINGLEPLAYER = 0x1, - COOPERATIVE = 0x2, - DEATHMATCH = 0x4, - TEAMGAME = 0x8 + GAMEMODE_SINGLEPLAYER = 0x1, + GAMEMODE_COOPERATIVE = 0x2, + GAMEMODE_DEATHMATCH = 0x4, + GAMEMODE_TEAMGAME = 0x8 }; enum AmmoModes @@ -112,6 +118,12 @@ class BaseStatusBar native ui HUD_HorizCenter } + enum ENumFlags + { + FNF_FILLZEROS, + FNF_WHENNOTZERO, + } + const XHAIRSHRINKSIZE =(1./18); const XHAIRPICKUPSIZE = (2+XHAIRSHRINKSIZE); @@ -154,11 +166,13 @@ class BaseStatusBar native ui virtual void SetMugShotState (String state_name, bool wait_till_done=false, bool reset=false) {} native void RefreshBackground () const; + + // 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 = ""); //============================================================================ @@ -243,10 +257,74 @@ class BaseStatusBar native ui if (w == null) return ""; return w.GetTag(); } - + // These cannot be done in ZScript. native String GetGlobalACSString(int index); native String GetGlobalACSArrayString(int arrayno, int index); + native int GetGlobalACSValue(int index); + native int GetGlobalACSArrayValue(int arrayno, int index); + + //============================================================================ + // + // Convenience functions to retrieve some numbers + // + //============================================================================ + + int GetArmorAmount() + { + let armor = CPlayer.mo.FindInventory("BasicArmor"); + return armor? armor.Amount : 0; + } + + int GetMaxAmount(class item) + { + let it = CPlayer.mo.FindInventory(item); + return it? it.MaxAmount : GetDefaultByType(item).MaxAmount; + } + + int GetArmorSavePercent() + { + double add = 0; + let harmor = HexenArmor(CPlayer.mo.FindInventory("HexenArmor")); + if(harmor != NULL) + { + add = harmor.Slots[0] + harmor.Slots[1] + harmor.Slots[2] + harmor.Slots[3] + harmor.Slots[4]; + } + //Hexen counts basic armor also so we should too. + let armor = BasicArmor(CPlayer.mo.FindInventory("BasicArmor")); + if(armor != NULL) + { + add += armor.SavePercent * 100; + } + return int(add); + } + + // Note that this retrieves the value in tics, not seconds like the equivalent SBARINFO function. + // The idea is to let the caller decide what to do with it instead of destroying accuracy here. + int GetAirTime() + { + if(CPlayer.mo.waterlevel < 3) + return level.airsupply; + else + return max(CPlayer.air_finished - level.time, 0); + } + + int GetSelectedInventoryAmount() + { + if(CPlayer.mo.InvSel != NULL) return CPlayer.mo.InvSel.Amount; + return 0; + } + + int GetKeyCount() + { + int num = 0; + for(Inventory item = CPlayer.mo.Inv;item != NULL;item = item.Inv) + { + if(item is "Key") num++; + } + return num; + } + //============================================================================ // // various checker functions, based on SBARINFOs condition nodes. @@ -261,10 +339,10 @@ class BaseStatusBar native ui bool CheckGameMode(int ValidModes) { - return (!multiplayer && (ValidModes & SINGLEPLAYER)) || - (deathmatch && (ValidModes & DEATHMATCH)) || - (multiplayer && !deathmatch && (ValidModes & COOPERATIVE)) || - (teamplay && (ValidModes & TEAMGAME)); + return (!multiplayer && (ValidModes & GAMEMODE_SINGLEPLAYER)) || + (deathmatch && (ValidModes & GAMEMODE_DEATHMATCH)) || + (multiplayer && !deathmatch && (ValidModes & GAMEMODE_COOPERATIVE)) || + (teamplay && (ValidModes & GAMEMODE_TEAMGAME)); } //============================================================================ @@ -436,7 +514,7 @@ class BaseStatusBar native ui // //============================================================================ - void DrawTexture(TextureID texture, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = TOP|LEFT, Vector2 boxsize = (-1, -1), int itemAlign = TOP|LEFT, int flags = 0, Vector2 scale = (1., 1.) ) + 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 @@ -467,13 +545,12 @@ class BaseStatusBar native ui else scale1 = min(scale1, scale2); boxsize = texsize * scale1; - screenAlign = TOP|LEFT; // anything else makes no sense here. } else { boxsize = texsize; } - DrawGraphic(texture, animated, pos, Alpha, !!(flags & DI_TRANSLATABLE), false, itemAlign, screenAlign, false, boxsize); + DrawGraphic(texture, animated, pos, Alpha, !!(flags & DI_TRANSLATABLE), !!(flags & DI_DIM), itemAlign, screenAlign, false, boxsize); } //============================================================================ @@ -482,7 +559,7 @@ class BaseStatusBar native ui // //============================================================================ - void DrawImage(String imagename, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = TOP|LEFT, Vector2 boxsize = (-1, -1), int itemAlign = TOP|LEFT, int flags = 0, Vector2 scale = (1., 1.) ) + 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); @@ -494,36 +571,36 @@ class BaseStatusBar native ui // //============================================================================ - void DrawIcon(int icontype, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = TOP|LEFT, Vector2 boxsize = (-1, -1), int itemAlign = TOP|LEFT, int flags = 0) + 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 PLAYERICON: + case ITYPE_PLAYERICON: texture = CPlayer.mo.ScoreIcon; break; - case AMMO1: - case AMMO2: + case ITYPE_AMMO1: + case ITYPE_AMMO2: [atype1, atype2] = GetCurrentAmmo(); - [texture, applyscale] = GetIcon(icontype == AMMO1? atype1 : atype2, flags, true); + [texture, applyscale] = GetIcon(icontype == ITYPE_AMMO1? atype1 : atype2, flags, true); break; - case ARMOR: + case ITYPE_ARMOR: [texture, applyscale] = GetIcon(CPlayer.mo.FindInventory("BasicArmor"), flags, false); break; - case WEAPONICON: + case ITYPE_WEAPON: [texture, applyscale] = GetIcon(CPlayer.ReadyWeapon, flags, false); break; - case SIGIL: + case ITYPE_SIGIL: [texture, applyscale] = GetIcon(CPlayer.mo.FindInventory("Sigil"), flags, false); break; - case SELECTEDINVENTORYICON: + case ITYPE_SELECTEDINVENTORY: if (CPlayer.mo.InvSel != NULL) texture = CPlayer.mo.InvSel.Icon; break; @@ -537,7 +614,7 @@ class BaseStatusBar native ui // //============================================================================ - void DrawHexenArmor(int armortype, String image, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = TOP|LEFT, Vector2 boxsize = (-1, -1), int itemAlign = TOP|LEFT, int flags = 0) + 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) { let harmor = HexenArmor(statusBar.CPlayer.mo.FindInventory("HexenArmor")); if (harmor != NULL) @@ -561,7 +638,7 @@ class BaseStatusBar native ui // //============================================================================ - void DrawInventoryIcon(class item, String image, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = TOP|LEFT, Vector2 boxsize = (-1, -1), int itemAlign = TOP|LEFT, int flags = 0) + 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) { let texture = GetDefaultByType(item).Icon; if (texture.IsValid()) @@ -570,3 +647,82 @@ class BaseStatusBar native ui } } } + +//============================================================================ +// +// a generic value interpolator for status bar elements that can change +// gradually to their new value. +// +//============================================================================ + +class LinearValueInterpolator : Object +{ + int mCurrentValue; + int mMaxChange; + + static LinearValueInterpolator Create(int startval, int maxchange) + { + let v = new("LinearValueInterpolator"); + v.mCurrentValue = startval; + v.mMaxChange = maxchange; + return v; + } + + // 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) + { + if (mCurrentValue > destvalue) + { + mCurrentValue = max(destvalue, mCurrentValue - mMaxChange); + } + else + { + mCurrentValue = min(destvalue, mCurrentValue + mMaxChange); + } + } + + // This must be called in the draw function to retrieve the value for output. + int GetValue() + { + return mCurrentValue; + } +} + +class DynamicValueInterpolator : Object +{ + int mCurrentValue; + int mMinChange; + double mChangeFactor; + + + static DynamicValueInterpolator Create(int startval, double changefactor, int minchange) + { + let v = new("DynamicValueInterpolator"); + v.mCurrentValue = startval; + v.mMinChange = minchange; + v.mChangeFactor = changefactor; + return v; + } + + // 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)); + if (mCurrentValue > destvalue) + { + mCurrentValue = max(destvalue, mCurrentValue - diff); + } + else + { + mCurrentValue = min(destvalue, mCurrentValue + diff); + } + } + + // This must be called in the draw function to retrieve the value for output. + int GetValue() + { + return mCurrentValue; + } +} diff --git a/wadsrc/static/zscript/statusbar/strife_sbar.txt b/wadsrc/static/zscript/statusbar/strife_sbar.txt index f75bfffb5..80aedb105 100644 --- a/wadsrc/static/zscript/statusbar/strife_sbar.txt +++ b/wadsrc/static/zscript/statusbar/strife_sbar.txt @@ -371,15 +371,16 @@ class StrifeStatusBar : BaseStatusBar { fullscreenoffsets = true; // Draw health - DrINumberOuter (CPlayer.health, 4, -10, false, 7); - DrawTexture(Images[imgMEDI], (14, -17), false, 1.0, BOTTOM|LEFT, itemalign: BOTTOM|HCENTER); + + 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 armor let armor = CPlayer.mo.FindInventory('BasicArmor'); if (armor != NULL && armor.Amount != 0) { - DrINumberOuter (armor.Amount, 35, -10, false, 7); - DrawTexture(armor.Icon, (45, -17), false, 1.0, BOTTOM|LEFT, itemalign: BOTTOM|HCENTER); + 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); } // Draw ammo @@ -390,19 +391,19 @@ class StrifeStatusBar : BaseStatusBar if (ammo1 != NULL) { // Draw primary ammo in the bottom-right corner - DrINumberOuter (ammo1.Amount, -23, -10, false, 7); - DrawTexture(ammo1.Icon, (-14, -17), false, 1.0, BOTTOM|RIGHT, itemalign: BOTTOM|HCENTER); + 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); if (ammo2 != NULL && ammo1!=ammo2) { // Draw secondary ammo just above the primary ammo - DrINumberOuter (ammo2.Amount, -23, -48, false, 7); - DrawTexture(ammo1.Icon, (-14, -55), false, 1.0, BOTTOM|RIGHT, itemalign: BOTTOM|HCENTER); + 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); } } if (deathmatch) { // Draw frags (in DM) - DrBNumberOuterFont (CPlayer.fragcount, -44, 1); + DrawString("BigFont", FormatNumber(CPlayer.FragCount, 3, 0, 0), (-44, 1), 1., Font.CR_UNTRANSLATED, TEXT_LEFT, ALIGN_RIGHT|ALIGN_TOP, 0, false, 2, 2); } // Draw inventory @@ -412,18 +413,10 @@ class StrifeStatusBar : BaseStatusBar { if (ItemFlash > 0) { - vector2 size = TexMan.GetScaledSize(Images[CursorImage]); - screen.DrawTexture (Images[CursorImage], true, -28, -15, - DTA_HUDRules, HUD_Normal, - DTA_LeftOffsetF, size.X, - DTA_TopOffsetF, size.Y, - DTA_Alpha, ItemFlash); + DrawTexture(Images[CursorImage], (-28, -15), true, 1.0, ALIGN_BOTTOM|ALIGN_RIGHT, ItemAlign:ALIGN_BOTTOM|ALIGN_RIGHT); } - DrINumberOuter (CPlayer.mo.InvSel.Amount, -51, -10, false, 7); - screen.DrawTexture (CPlayer.mo.InvSel.Icon, true, -42, -17, - DTA_HUDRules, HUD_Normal, - DTA_CenterBottomOffset, true, - DTA_ColorOverlay, CPlayer.mo.InvSel.Amount > 0 ? 0 : Color(170, 0, 0, 0)); + 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); } } else @@ -431,23 +424,20 @@ class StrifeStatusBar : BaseStatusBar CPlayer.mo.InvFirst = ValidateInvFirst (6); int i = 0; Inventory item; + Vector2 box = TexMan.GetScaledSize(Images[CursorImage]) - (4, 4); // Fit oversized icons into the box. if (CPlayer.mo.InvFirst != NULL) { for (item = CPlayer.mo.InvFirst; item != NULL && i < 6; item = item.NextInv()) { if (item == CPlayer.mo.InvSel) { - screen.DrawTexture (Images[CursorImage], true, -100+i*35, -21, - DTA_HUDRules, HUD_HorizCenter, - DTA_Alpha, 0.75); + DrawTexture(Images[CursorImage], (-90+i*35, -3), true, 0.75, ALIGN_CENTER_BOTTOM, ItemAlign:ALIGN_CENTER_BOTTOM); } if (item.Icon.isValid()) { - screen.DrawTexture (item.Icon, true, -94 + i*35, -19, - DTA_HUDRules, HUD_HorizCenter, - DTA_ColorOverlay, CPlayer.mo.InvSel.Amount > 0 ? 0 : Color(170, 0, 0, 0)); + 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); } - DrINumberOuter (item.Amount, -89 + i*35, -10, true, 7); + 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); ++i; } } @@ -480,14 +470,8 @@ class StrifeStatusBar : BaseStatusBar { case POP_Log: { - int seconds = Thinker.Tics2Seconds(level.time); // Draw the latest log message. - buff = String.Format("%02d:%02d:%02d", - seconds / 3600, - (seconds % 3600) / 60, - (seconds) % 60); - - screen.DrawText(SmallFont2, Font.CR_UNTRANSLATED, left + 210 * xscale, top + 8 * yscale, buff, + screen.DrawText(SmallFont2, Font.CR_UNTRANSLATED, left + 210 * xscale, top + 8 * yscale, Level.TimeFormatted(), DTA_CleanNoMove, true); if (CPlayer.LogText.Length() > 0) @@ -679,150 +663,6 @@ class StrifeStatusBar : BaseStatusBar } - //--------------------------------------------------------------------------- - // - // PROC DrINumberOuter - // - // Draws a number outside the status bar, possibly scaled. - // - //--------------------------------------------------------------------------- - - void DrINumberOuter(int val, int x, int y, bool center, int w) const - { - bool negative = false; - - x += w * 2; - if (val < 0) - { - negative = true; - val = -val; - } - else if (val == 0) - { - screen.DrawTexture(Images[imgINumbers], true, x + 1, y + 1, - DTA_FillColor, 0, DTA_Alpha, HR_SHADOW, - DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal); - screen.DrawTexture(Images[imgINumbers], true, x, y, - DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal); - return; - } - - int oval = val; - int ox = x; - - // First the shadow - while (val != 0) - { - screen.DrawTexture(Images[imgINumbers + val % 10], true, x + 1, y + 1, - DTA_FillColor, 0, DTA_Alpha, HR_SHADOW, - DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal); - x -= w; - val /= 10; - } - if (negative) - { - screen.DrawTexture(Images[imgNEGATIVE], true, x + 1, y + 1, - DTA_FillColor, 0, DTA_Alpha, HR_SHADOW, - DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal); - } - - // Then the real deal - val = oval; - x = ox; - while (val != 0) - { - screen.DrawTexture(Images[imgINumbers + val % 10], true, x, y, - DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal); - x -= w; - val /= 10; - } - if (negative) - { - screen.DrawTexture(Images[imgNEGATIVE], true, x, y, - DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal); - } - } - - - //--------------------------------------------------------------------------- - // - // PROC DrBNumberOuter - // - // Draws a three digit number using the real big font outside the status bar. - // - //--------------------------------------------------------------------------- - - void DrBNumberOuterFont(int val, int x, int y, int size = 3) const - { - int v; - bool negative = false; - TextureID pic; - - int w = BigFont.GetCharWidth("0"); - int ww = w; - - if (w > 1) - { - w--; - } - int xpos = x + w / 2 + (size - 1)*w; - - if (val == 0) - { - screen.DrawChar(BigFont, Font.CR_UNTRANSLATED, xpos - v / 2 + 2, y + 2, "0", - DTA_HUDRules, HUD_Normal, - DTA_Alpha, HR_SHADOW, - DTA_FillColor, 0); - screen.DrawChar(BigFont, Font.CR_UNTRANSLATED, xpos - v / 2, y, "0", - DTA_HUDRules, HUD_Normal); - return; - } - else if (val < 0) - { - negative = true; - val = -val; - } - - int oval = val; - int oxpos = xpos; - - // First the shadow - while (val != 0) - { - v = BigFont.GetCharWidth(int("0") + val % 10); - screen.DrawChar(BigFont, Font.CR_UNTRANSLATED, xpos - v / 2 + 2, y + 2, - DTA_HUDRules, HUD_Normal, - DTA_Alpha, HR_SHADOW, - DTA_FillColor, 0); - val /= 10; - xpos -= w; - } - if (negative) - { - v = BigFont.GetCharWidth("-"); - screen.DrawChar(BigFont, Font.CR_UNTRANSLATED, xpos - v / 2 + 2, y + 2, "-", - DTA_HUDRules, HUD_Normal, - DTA_Alpha, HR_SHADOW, - DTA_FillColor, 0); - } - - // Then the foreground number - val = oval; - xpos = oxpos; - while (val != 0) - { - v = BigFont.GetCharWidth(int("0") + val % 10); - screen.DrawChar(BigFont, Font.CR_UNTRANSLATED, xpos - v / 2, y, "0", DTA_HUDRules, HUD_Normal); - val /= 10; - xpos -= w; - } - if (negative) - { - v = BigFont.GetCharWidth("-"); - screen.DrawChar(BigFont, Font.CR_UNTRANSLATED, xpos - v / 2, y, "-", DTA_HUDRules, HUD_Normal); - } - } - //--------------------------------------------------------------------------- // // PROC DrawImage From 321e2da979fa13775a05fc8c7be449b988a25738 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 24 Mar 2017 22:04:07 +0100 Subject: [PATCH 2/5] - initialize clipper with the view frustum for better performance - change translucent objects to be pointers for faster sorting --- src/polyrenderer/scene/poly_cull.cpp | 30 +++++++++++++++++++++++++++ src/polyrenderer/scene/poly_cull.h | 2 ++ src/polyrenderer/scene/poly_scene.cpp | 27 +++++++++++++----------- src/polyrenderer/scene/poly_scene.h | 2 +- src/polyrenderer/scene/poly_wall.cpp | 6 +++--- src/polyrenderer/scene/poly_wall.h | 4 ++-- 6 files changed, 53 insertions(+), 18 deletions(-) diff --git a/src/polyrenderer/scene/poly_cull.cpp b/src/polyrenderer/scene/poly_cull.cpp index 6fe591527..01f157a93 100644 --- a/src/polyrenderer/scene/poly_cull.cpp +++ b/src/polyrenderer/scene/poly_cull.cpp @@ -287,6 +287,23 @@ bool PolyCull::GetAnglesForLine(double x1, double y1, double x2, double y2, angl return !IsSegmentCulled(angle1, angle2); } +void PolyCull::MarkViewFrustum() +{ + // Clips things outside the viewing frustum. + auto &viewpoint = PolyRenderer::Instance()->Viewpoint; + auto &viewwindow = PolyRenderer::Instance()->Viewwindow; + double tilt = fabs(viewpoint.Angles.Pitch.Degrees); + if (tilt > 46.0) // If the pitch is larger than this you can look all around + return; + + double floatangle = 2.0 + (45.0 + ((tilt / 1.9)))*viewpoint.FieldOfView.Degrees*48.0 / AspectMultiplier(viewwindow.WidescreenRatio) / 90.0; + angle_t a1 = DAngle(floatangle).BAMs(); + if (a1 < ANGLE_180) + { + MarkSegmentCulled(AngleToPseudo(viewpoint.Angles.Yaw.BAMs() + a1), AngleToPseudo(viewpoint.Angles.Yaw.BAMs() - a1)); + } +} + //----------------------------------------------------------------------------- // // ! Returns the pseudoangle between the line p1 to (infinity, p1.y) and the @@ -320,3 +337,16 @@ angle_t PolyCull::PointToPseudoAngle(double x, double y) return xs_Fix<30>::ToFix(result); } } + +angle_t PolyCull::AngleToPseudo(angle_t ang) +{ + double vecx = cos(ang * M_PI / ANGLE_180); + double vecy = sin(ang * M_PI / ANGLE_180); + + double result = vecy / (fabs(vecx) + fabs(vecy)); + if (vecx < 0) + { + result = 2.f - result; + } + return xs_Fix<30>::ToFix(result); +} diff --git a/src/polyrenderer/scene/poly_cull.h b/src/polyrenderer/scene/poly_cull.h index d217de7ef..d0430501d 100644 --- a/src/polyrenderer/scene/poly_cull.h +++ b/src/polyrenderer/scene/poly_cull.h @@ -35,6 +35,7 @@ public: void MarkSegmentCulled(angle_t angle1, angle_t angle2); bool IsSegmentCulled(angle_t angle1, angle_t angle2) const; void InvertSegments(); + void MarkViewFrustum(); std::vector PvsSectors; double MaxCeilingHeight = 0.0; @@ -64,4 +65,5 @@ private: Vec4f PortalClipPlane; static angle_t PointToPseudoAngle(double x, double y); + static angle_t AngleToPseudo(angle_t ang); }; diff --git a/src/polyrenderer/scene/poly_scene.cpp b/src/polyrenderer/scene/poly_scene.cpp index 176341e97..f3a0b2887 100644 --- a/src/polyrenderer/scene/poly_scene.cpp +++ b/src/polyrenderer/scene/poly_scene.cpp @@ -73,6 +73,7 @@ void RenderPolyScene::Render(int portalDepth) ClearBuffers(); if (!PortalSegmentsAdded) Cull.ClearSolidSegments(); + Cull.MarkViewFrustum(); Cull.CullScene(WorldToClip, PortalPlane); Cull.ClearSolidSegments(); RenderSectors(); @@ -124,6 +125,8 @@ void RenderPolyScene::RenderSubsector(subsector_t *sub) } } + RenderMemory &memory = PolyRenderer::Instance()->FrameMemory; + bool mainBSP = ((unsigned int)(sub->Index()) < level.subsectors.Size()); if (mainBSP) { @@ -131,7 +134,7 @@ void RenderPolyScene::RenderSubsector(subsector_t *sub) for (int i = ParticlesInSubsec[subsectorIndex]; i != NO_PARTICLE; i = Particles[i].snext) { particle_t *particle = Particles + i; - TranslucentObjects.push_back({ particle, sub, subsectorDepth }); + TranslucentObjects.push_back(memory.NewObject(particle, sub, subsectorDepth)); } } @@ -146,7 +149,7 @@ void RenderPolyScene::RenderSprite(AActor *thing, double sortDistance, const DVe subsector_t *sub = &level.subsectors[0]; auto it = SubsectorDepths.find(sub); if (it != SubsectorDepths.end()) - TranslucentObjects.push_back({ thing, sub, it->second, sortDistance, 0.0f, 1.0f }); + TranslucentObjects.push_back(PolyRenderer::Instance()->FrameMemory.NewObject(thing, sub, it->second, sortDistance, 0.0f, 1.0f)); } else { @@ -187,7 +190,7 @@ void RenderPolyScene::RenderSprite(AActor *thing, double sortDistance, DVector2 auto it = SubsectorDepths.find(sub); if (it != SubsectorDepths.end()) - TranslucentObjects.push_back({ thing, sub, it->second, sortDistance, (float)t1, (float)t2 }); + TranslucentObjects.push_back(PolyRenderer::Instance()->FrameMemory.NewObject(thing, sub, it->second, sortDistance, (float)t1, (float)t2)); } void RenderPolyScene::RenderLine(subsector_t *sub, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth) @@ -347,29 +350,29 @@ void RenderPolyScene::RenderTranslucent(int portalDepth) } } - std::stable_sort(TranslucentObjects.begin(), TranslucentObjects.end()); + std::stable_sort(TranslucentObjects.begin(), TranslucentObjects.end(), [](auto a, auto b) { return *a < *b; }); for (auto it = TranslucentObjects.rbegin(); it != TranslucentObjects.rend(); ++it) { - auto &obj = *it; - if (obj.particle) + PolyTranslucentObject *obj = *it; + if (obj->particle) { RenderPolyParticle spr; - spr.Render(WorldToClip, PortalPlane, obj.particle, obj.sub, obj.subsectorDepth, StencilValue + 1); + spr.Render(WorldToClip, PortalPlane, obj->particle, obj->sub, obj->subsectorDepth, StencilValue + 1); } - else if (!obj.thing) + else if (!obj->thing) { - obj.wall.Render(WorldToClip, PortalPlane, Cull); + obj->wall.Render(WorldToClip, PortalPlane, Cull); } - else if ((obj.thing->renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE) + else if ((obj->thing->renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE) { RenderPolyWallSprite wallspr; - wallspr.Render(WorldToClip, PortalPlane, obj.thing, obj.sub, obj.subsectorDepth, StencilValue + 1); + wallspr.Render(WorldToClip, PortalPlane, obj->thing, obj->sub, obj->subsectorDepth, StencilValue + 1); } else { RenderPolySprite spr; - spr.Render(WorldToClip, PortalPlane, obj.thing, obj.sub, obj.subsectorDepth, StencilValue + 1, obj.SpriteLeft, obj.SpriteRight); + spr.Render(WorldToClip, PortalPlane, obj->thing, obj->sub, obj->subsectorDepth, StencilValue + 1, obj->SpriteLeft, obj->SpriteRight); } } } diff --git a/src/polyrenderer/scene/poly_scene.h b/src/polyrenderer/scene/poly_scene.h index ba6fd5eea..77c7925c0 100644 --- a/src/polyrenderer/scene/poly_scene.h +++ b/src/polyrenderer/scene/poly_scene.h @@ -97,7 +97,7 @@ private: uint32_t NextSubsectorDepth = 0; std::set SeenSectors; std::unordered_map SubsectorDepths; - std::vector TranslucentObjects; + std::vector TranslucentObjects; std::vector> SectorPortals; std::vector> LinePortals; diff --git a/src/polyrenderer/scene/poly_wall.cpp b/src/polyrenderer/scene/poly_wall.cpp index 078b10e0d..abbfd15f8 100644 --- a/src/polyrenderer/scene/poly_wall.cpp +++ b/src/polyrenderer/scene/poly_wall.cpp @@ -37,7 +37,7 @@ EXTERN_CVAR(Bool, r_drawmirrors) -bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector &translucentWallsOutput, std::vector> &linePortals) +bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector &translucentWallsOutput, std::vector> &linePortals) { PolyDrawLinePortal *polyportal = nullptr; if (line->backsector == nullptr && line->linedef && line->sidedef == line->linedef->sidedef[0] && (line->linedef->special == Line_Mirror && r_drawmirrors)) @@ -153,7 +153,7 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipP FTexture *midtex = TexMan(line->sidedef->GetTexture(side_t::mid), true); if (midtex && midtex->UseType != FTexture::TEX_Null) - translucentWallsOutput.push_back({ wall }); + translucentWallsOutput.push_back(PolyRenderer::Instance()->FrameMemory.NewObject(wall)); if (polyportal) { @@ -165,7 +165,7 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipP return polyportal != nullptr; } -void RenderPolyWall::Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector &translucentWallsOutput) +void RenderPolyWall::Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector &translucentWallsOutput) { double frontceilz1 = fakeFloor->top.plane->ZatPoint(line->v1); double frontfloorz1 = fakeFloor->bottom.plane->ZatPoint(line->v1); diff --git a/src/polyrenderer/scene/poly_wall.h b/src/polyrenderer/scene/poly_wall.h index 014110a40..a435201b2 100644 --- a/src/polyrenderer/scene/poly_wall.h +++ b/src/polyrenderer/scene/poly_wall.h @@ -32,8 +32,8 @@ class Vec4f; class RenderPolyWall { public: - static bool RenderLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector &translucentWallsOutput, std::vector> &linePortals); - static void Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector &translucentWallsOutput); + static bool RenderLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector &translucentWallsOutput, std::vector> &linePortals); + static void Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector &translucentWallsOutput); void SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2); void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull); From b17b8d32ad580e06196a21939b66b966af1694c8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 24 Mar 2017 22:57:44 +0100 Subject: [PATCH 3/5] completely redid the active powerup drawer for the HUD - replaced Inventory.DrawPowerup with a GetPowerupIcon method so that the calling code can handle the drawing and apply its own rules. This was a major design flaw of allowing the inventory items to handle the drawing themselves, because they were unable to adjust to different HUD frontends. Note that any mod that overrides DrawPowerup will not draw any icon that expects to be handled that way! - the alternative HUD now has its own, separate drawer that obeys the AltHUD's rules, and not the ones of the normal fullscreen HUD. - the standard drawer has been scriptified as a virtual function. - Both drawers now handle positioning of the icon inside its assigned box themselves instead of trusting the powerup item to do it correctly. - DTA_HUDRules and Screen.DrawHUDTexture are to be considered deprecated because both do not integrate into the redesigned HUD code. --- src/g_shared/shared_hud.cpp | 44 +++++++++++ src/g_statusbar/sbarinfo.cpp | 1 - src/g_statusbar/shared_sbar.cpp | 53 +++---------- src/v_draw.cpp | 12 +-- wadsrc/static/zscript/base.txt | 7 +- wadsrc/static/zscript/inventory/inventory.txt | 19 ++++- wadsrc/static/zscript/inventory/powerups.txt | 74 ++++++++----------- wadsrc/static/zscript/statusbar/statusbar.txt | 31 ++++++++ 8 files changed, 143 insertions(+), 98 deletions(-) diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index ab8255cdf..fa5b8a030 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -54,6 +54,7 @@ #include "r_utility.h" #include "cmdlib.h" #include "g_levellocals.h" +#include "virtual.h" #include @@ -1079,6 +1080,48 @@ bool ST_IsLatencyVisible() && (hud_showlag <= 2); } +//--------------------------------------------------------------------------- +// +// draw the overlay +// +//--------------------------------------------------------------------------- + +static void DrawPowerups(player_t *CPlayer) +{ + // Each icon gets a 32x32 block to draw itself in. + int x, y; + AInventory *item; + const int yshift = SmallFont->GetHeight(); + const int POWERUPICONSIZE = 32; + + x = hudwidth -20; + y = POWERUPICONSIZE * 5/4 + + (ST_IsTimeVisible() ? yshift : 0) + + (ST_IsLatencyVisible() ? yshift : 0); + + for (item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory) + { + IFVIRTUALPTR(item, AInventory, GetPowerupIcon) + { + VMValue param[] = { item }; + int rv; + VMReturn ret(&rv); + GlobalVMStack.Call(func, param, 1, &ret, 1); + auto tex = FSetTextureID(rv); + if (!tex.isValid()) continue; + auto texture = TexMan(tex); + + screen->DrawTexture(texture, x, y, DTA_KeepRatio, true, DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_CenterBottomOffset, true, TAG_DONE); + + x -= POWERUPICONSIZE; + if (x < -hudwidth / 2) + { + x = -20; + y += POWERUPICONSIZE * 3 / 2; + } + } + } +} //--------------------------------------------------------------------------- // @@ -1158,6 +1201,7 @@ void DrawHUD() DrawTime(); DrawLatency(); + DrawPowerups(CPlayer); } else { diff --git a/src/g_statusbar/sbarinfo.cpp b/src/g_statusbar/sbarinfo.cpp index 6548822fa..e747717cc 100644 --- a/src/g_statusbar/sbarinfo.cpp +++ b/src/g_statusbar/sbarinfo.cpp @@ -1317,7 +1317,6 @@ public: adjustRelCenter(x.RelCenter(), y.RelCenter(), dx, dy, rx, ry, xScale, yScale); - // We can't use DTA_HUDRules since it forces a width and height. // Translation: No high res. bool xright = *x < 0 && !x.RelCenter(); bool ybot = *y < 0 && !y.RelCenter(); diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index 092a49710..95f890fdd 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -1052,7 +1052,18 @@ void DBaseStatusBar::DrawTopStuff (EHudState state) DTA_CleanNoMove, true, TAG_DONE); } - DrawPowerups (); + if (state != HUD_AltHud) + { + auto saved = fullscreenOffsets; + fullscreenOffsets = true; + IFVIRTUAL(DBaseStatusBar, DrawPowerups) + { + VMValue params[] = { (DObject*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0); + } + fullscreenOffsets = saved; + } + if (automapactive && !viewactive) { DrawMessages (HUDMSGLayer_OverMap, (state == HUD_StatusBar) ? gST_Y : SCREENHEIGHT); @@ -1068,46 +1079,6 @@ void DBaseStatusBar::DrawTopStuff (EHudState state) } } -//--------------------------------------------------------------------------- -// -// DrawPowerups -// -//--------------------------------------------------------------------------- - -void DBaseStatusBar::DrawPowerups () -{ - // Each icon gets a 32x32 block to draw itself in. - int x, y; - AInventory *item; - const int yshift = SmallFont->GetHeight(); - - x = -20; - y = 17 - + (ST_IsTimeVisible() ? yshift : 0) - + (ST_IsLatencyVisible() ? yshift : 0); - for (item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory) - { - IFVIRTUALPTR(item, AInventory, DrawPowerup) - { - VMValue params[3] = { item, x, y }; - VMReturn ret; - int retv; - - ret.IntAt(&retv); - GlobalVMStack.Call(func, params, 3, &ret, 1); - if (retv) - { - x -= POWERUPICONSIZE; - if (x < -POWERUPICONSIZE * 5) - { - x = -20; - y += POWERUPICONSIZE * 2; - } - } - } - } -} - //--------------------------------------------------------------------------- // // BlendView diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 65aa1b7f6..f7e318472 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -144,16 +144,6 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawTexture) return 0; } -DEFINE_ACTION_FUNCTION(_Screen, DrawHUDTexture) -{ - PARAM_PROLOGUE; - PARAM_INT(texid); - PARAM_FLOAT(x); - PARAM_FLOAT(y); - screen->DrawTexture(TexMan(FSetTextureID(texid)), x, y, DTA_HUDRules, HUD_Normal, TAG_END); - return 0; -} - void DCanvas::DrawTextureParms(FTexture *img, DrawParms &parms) { #ifndef NO_SWRENDER @@ -220,6 +210,8 @@ bool DCanvas::SetTextureParms(DrawParms *parms, FTexture *img, double xx, double case DTA_HUDRules: case DTA_HUDRulesC: { + // Note that this has been deprecated because it cannot intelligently decide what scale + // actually needs to be used in conjunction with the active status bar. bool xright = parms->x < 0; bool ybot = parms->y < 0; diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 282310bac..6b6922ad3 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -159,13 +159,18 @@ struct Screen native native static void Clear(int left, int top, int right, int bottom, Color color, int palcolor = -1); native static void Dim(Color col, double amount, int x, int y, int w, int h); - native static void DrawHUDTexture(TextureID tex, double x, double y); native static vararg void DrawTexture(TextureID tex, bool animate, double x, double y, ...); native static vararg void DrawChar(Font font, int normalcolor, double x, double y, int character, ...); native static vararg void DrawText(Font font, int normalcolor, double x, double y, String text, ...); native static void DrawFrame(int x, int y, int w, int h); native static Vector2, Vector2 VirtualToRealCoords(Vector2 pos, Vector2 size, Vector2 vsize, bool vbottom=false, bool handleaspect=true); native static double GetAspectRatio(); + + // 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); + } } struct Font native diff --git a/wadsrc/static/zscript/inventory/inventory.txt b/wadsrc/static/zscript/inventory/inventory.txt index d5c15e0b2..c526939a1 100644 --- a/wadsrc/static/zscript/inventory/inventory.txt +++ b/wadsrc/static/zscript/inventory/inventory.txt @@ -820,13 +820,28 @@ class Inventory : Actor native // // AInventory :: DrawPowerup // - // Gives self item a chance to draw a special status indicator on the screen. - // Returns false if it didn't draw anything. + // This has been deprecated because it is not how this should be done + // Use GetPowerupIcon instead! // //=========================================================================== virtual ui version("2.4") bool DrawPowerup(int x, int y) { return false; } + //=========================================================================== + // + // AInventory :: GetPowerupIcon + // + // Returns the icon that should be drawn for an active powerup. + // + //=========================================================================== + + virtual clearscope version("2.5") TextureID GetPowerupIcon() const + { + TextureID id; + id.SetInvalid(); + return id; + } + //=========================================================================== // // AInventory :: AbsorbDamage diff --git a/wadsrc/static/zscript/inventory/powerups.txt b/wadsrc/static/zscript/inventory/powerups.txt index 3861f12a8..045331672 100644 --- a/wadsrc/static/zscript/inventory/powerups.txt +++ b/wadsrc/static/zscript/inventory/powerups.txt @@ -273,17 +273,9 @@ class Powerup : Inventory // //=========================================================================== - override bool DrawPowerup (int x, int y) + override TextureID GetPowerupIcon() { - if (!Icon.isValid()) - { - return false; - } - if (!isBlinking()) - { - screen.DrawHUDTexture(Icon, x, y); - } - return true; + return Icon; } //=========================================================================== @@ -292,7 +284,7 @@ class Powerup : Inventory // //=========================================================================== - virtual bool isBlinking() const + virtual clearscope bool isBlinking() const { return (EffectTics <= BLINKTHRESHOLD && (EffectTics & 8) && !bNoScreenBlink); } @@ -941,7 +933,7 @@ class PowerFlight : Powerup +INVENTORY.HUBPOWER } - ui bool HitCenterFrame; + clearscope bool HitCenterFrame; //=========================================================================== // @@ -1011,50 +1003,46 @@ class PowerFlight : Powerup // //=========================================================================== - override bool DrawPowerup (int x, int y) + override TextureID GetPowerupIcon () { // If this item got a valid icon use that instead of the default spinning wings. if (Icon.isValid()) { - return Super.DrawPowerup(x, y); + return Icon; } - if (EffectTics > BLINKTHRESHOLD || !(EffectTics & 16)) - { - TextureID picnum = TexMan.CheckForTexture ("SPFLY0", TexMan.Type_MiscPatch); - int frame = (level.time/3) & 15; + TextureID picnum = TexMan.CheckForTexture ("SPFLY0", TexMan.Type_MiscPatch); + int frame = (level.time/3) & 15; - if (!picnum.isValid()) + if (!picnum.isValid()) + { + return picnum; + } + if (Owner.bNoGravity) + { + if (HitCenterFrame && (frame != 15 && frame != 0)) { - return false; - } - if (Owner.bNoGravity) - { - if (HitCenterFrame && (frame != 15 && frame != 0)) - { - screen.DrawHUDTexture (picnum + 15, x, y); - } - else - { - screen.DrawHUDTexture (picnum + frame, x, y); - HitCenterFrame = false; - } + return picnum + 15; } else { - if (!HitCenterFrame && (frame != 15 && frame != 0)) - { - screen.DrawHUDTexture (picnum + frame, x, y); - HitCenterFrame = false; - } - else - { - screen.DrawHUDTexture (picnum+15, x, y); - HitCenterFrame = true; - } + HitCenterFrame = false; + return picnum + frame; + } + } + else + { + if (!HitCenterFrame && (frame != 15 && frame != 0)) + { + HitCenterFrame = false; + return picnum + frame; + } + else + { + HitCenterFrame = true; + return picnum+15; } } - return true; } diff --git a/wadsrc/static/zscript/statusbar/statusbar.txt b/wadsrc/static/zscript/statusbar/statusbar.txt index 22bfe6222..059c602fd 100644 --- a/wadsrc/static/zscript/statusbar/statusbar.txt +++ b/wadsrc/static/zscript/statusbar/statusbar.txt @@ -126,6 +126,7 @@ class BaseStatusBar native ui const XHAIRSHRINKSIZE =(1./18); const XHAIRPICKUPSIZE = (2+XHAIRSHRINKSIZE); + const POWERUPICONSIZE = 32; native int ST_X, ST_Y; @@ -494,6 +495,35 @@ class BaseStatusBar native ui } + //--------------------------------------------------------------------------- + // + // DrawPowerups + // + //--------------------------------------------------------------------------- + + virtual void DrawPowerups () + { + // The AltHUD specific adjustments have been removed here, because the AltHUD uses its own variant of this function + // that can obey AltHUD rules - which this cannot. + Vector2 pos = (-20, POWERUPICONSIZE * 5 / 4); + double maxpos = screen.GetWidth() / 2; + for (let item = CPlayer.mo.Inv; item != NULL; item = item.Inv) + { + let icon = item.GetPowerupIcon(); + if (icon.IsValid()) + { + // Each icon gets a 32x32 block. + DrawTexture(icon, pos, true, 1.0, ALIGN_TOP|ALIGN_RIGHT, (POWERUPICONSIZE, POWERUPICONSIZE), ALIGN_CENTER_BOTTOM); + pos.x -= POWERUPICONSIZE; + if (pos.x < -maxpos) + { + pos.x = -20; + pos.y += POWERUPICONSIZE * 3 / 2; + } + } + } + } + //============================================================================ // // draw stuff @@ -726,3 +756,4 @@ class DynamicValueInterpolator : Object return mCurrentValue; } } + From 2d17594f6fe1731cb5f900c900cdbc4fce78327b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Mar 2017 00:35:19 +0100 Subject: [PATCH 4/5] - converted the Strife status bar to use the new HUD specific draw functions so that it also can benefit from coming changes. Note that the pop screens are special because they are not subject to scaling - they will always be drawn with the current resolutions clean scale. As a result they cannot use the HUD drawers but instead continue to use the low level draw functions directly. --- src/g_statusbar/shared_sbar.cpp | 9 +- .../static/zscript/statusbar/strife_sbar.txt | 83 ++++--------------- 2 files changed, 18 insertions(+), 74 deletions(-) diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index 95f890fdd..c3925cb51 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -1397,7 +1397,6 @@ void DBaseStatusBar::DrawGraphic(FTextureID texture, bool animate, double x, dou // Todo: Allow other scaling values, too. if (Scaled) { - y += RelTop - VerticalResolution; screen->VirtualToRealCoords(x, y, width, height, HorizontalResolution, VerticalResolution, true, true); } } @@ -1570,12 +1569,12 @@ void DBaseStatusBar::DrawString(FFont *font, const FString &cstring, double x, d if (!fullscreenOffsets) { rx += ST_X; - ry += ST_Y - (Scaled ? VerticalResolution : 200) + RelTop; + ry += ST_Y; + + // Todo: Allow other scaling values, too. if (Scaled) - screen->VirtualToRealCoords(rx, ry, rw, rh, HorizontalResolution, VerticalResolution, true); - else { - ry += (200 - VerticalResolution); + screen->VirtualToRealCoords(rx, ry, rw, rh, HorizontalResolution, VerticalResolution, true); } } else diff --git a/wadsrc/static/zscript/statusbar/strife_sbar.txt b/wadsrc/static/zscript/statusbar/strife_sbar.txt index 80aedb105..cb2ef8a5c 100644 --- a/wadsrc/static/zscript/statusbar/strife_sbar.txt +++ b/wadsrc/static/zscript/statusbar/strife_sbar.txt @@ -48,7 +48,6 @@ class StrifeStatusBar : BaseStatusBar imgARM1, imgARM2, imgNEGATIVE, - imgINumbers = imgFONG0, }; TextureID Images[imgNEGATIVE + 1]; @@ -79,18 +78,21 @@ class StrifeStatusBar : BaseStatusBar if (state == HUD_StatusBar) { + fullscreenoffsets = false; DrawMainBar (TicFrac); } else { if (state == HUD_Fullscreen) { + fullscreenoffsets = true; DrawFullScreenStuff (); } // Draw pop screen (log, keys, and status) if (CurrentPop != POP_None && PopHeight < 0) { + fullscreenoffsets = false; DrawPopScreen (screen.GetHeight(), TicFrac); } } @@ -302,11 +304,11 @@ class StrifeStatusBar : BaseStatusBar DrawPopScreen (Scaled ? (ST_Y - 8) * screen.GetHeight() / 200 : ST_Y - 8, TicFrac); } - DrawImage (Images[imgINVBACK], 0, 0); - DrawImage (Images[imgINVTOP], 0, -8); + DrawTexture(Images[imgINVBACK], (0, 0), true, 1.0, itemAlign:ALIGN_OFFSETS); + DrawTexture(Images[imgINVTOP], (0, -8), true, 1.0, itemAlign:ALIGN_OFFSETS); // Health - DrINumber (CPlayer.health, 79, -6, imgFONG0); + DrawString("Indexfont_Strife_Green", FormatNumber(CPlayer.health, 3, 5, 0), (86, -6), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, 0, 7, true, 1, 1); int points; if (CPlayer.cheats & CF_GODMODE) { @@ -323,8 +325,8 @@ class StrifeStatusBar : BaseStatusBar item = CPlayer.mo.FindInventory('BasicArmor'); if (item != NULL && item.Amount > 0) { - DrawImage (item.Icon, 2, 9); - DrINumber (item.Amount, 27, 23, imgFONY0); + 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); } // Ammo @@ -334,15 +336,15 @@ class StrifeStatusBar : BaseStatusBar [ammo1, ammo2, ammocount1, ammocount2] = GetCurrentAmmo (); if (ammo1 != NULL) { - DrINumber (ammo1.Amount, 311, -6, imgFONG0); - DrawImage (ammo1.Icon, 290, 13); + 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); } // Sigil item = CPlayer.mo.FindInventory('Sigil'); if (item != NULL) { - DrawImage (item.Icon, 253, 7); + DrawTexture (item.Icon, (253, 7), true, 1.0, itemAlign:ALIGN_OFFSETS); } // Inventory @@ -353,23 +355,19 @@ class StrifeStatusBar : BaseStatusBar { if (item == CPlayer.mo.InvSel) { - screen.DrawTexture (Images[CursorImage], true, - 42 + 35*i + ST_X, 12 + ST_Y, - DTA_Bottom320x200, Scaled, - DTA_Alpha, 1. - ItemFlash); + DrawTexture (item.Icon, (42 + 35*i, 12), true, 1. - ItemFlash, itemAlign:ALIGN_OFFSETS, item.Amount <= 0? DI_DIM : 0); } if (item.Icon.isValid()) { - DrawDimImage (item.Icon, 48 + 35*i, 14, item.Amount <= 0); + DrawTexture (item.Icon, (48 + 35*i, 14), true, 1.0, itemAlign:ALIGN_OFFSETS, item.Amount <= 0? DI_DIM : 0); } - DrINumber (item.Amount, 74 + 35*i, 23, imgFONY0); + 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); i++; } } protected void DrawFullScreenStuff () { - fullscreenoffsets = true; // 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); @@ -624,25 +622,6 @@ class StrifeStatusBar : BaseStatusBar } } - void DrINumber (int val, int x, int y, int imgBase) const - { - x -= 7; - - if (val == 0) - { - DrawImage (Images[imgBase], x, y); - } - else - { - while (val != 0) - { - DrawImage (Images[imgBase+val%10], x, y); - val /= 10; - x -= 7; - } - } - } - void DrINumber2 (int val, int x, int y, int width, int imgBase) const { x -= width; @@ -661,39 +640,5 @@ class StrifeStatusBar : BaseStatusBar } } } - - - //--------------------------------------------------------------------------- - // - // PROC DrawImage - // - // Draws an image with the status bar's upper-left corner as the origin. - // - //--------------------------------------------------------------------------- - - void DrawImage(TextureID img, int x, int y) const - { - if (img.IsValid()) - { - screen.DrawTexture(img, true, x + ST_X, y + ST_Y, DTA_Bottom320x200, Scaled); - } - } - - //--------------------------------------------------------------------------- - // - // PROC DrawImage - // - // Draws an optionally dimmed image with the status bar's upper-left corner - // as the origin. - // - //--------------------------------------------------------------------------- - - void DrawDimImage(TextureID img, int x, int y, bool dimmed) const - { - if (img.IsValid()) - { - screen.DrawTexture(img, true, x + ST_X, y + ST_Y, DTA_ColorOverlay, dimmed ? Color(170, 0, 0, 0) : 0, DTA_Bottom320x200, Scaled); - } - } } From bdb9275f8c428c4635014de8c30453ba13297ba2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Mar 2017 01:22:42 +0100 Subject: [PATCH 5/5] - made the mugshot accessible to ZScript. Note that there is no direct access, all this exposes is a single function to get the current face's texture which then can be drawn using the existing functions. --- src/g_statusbar/sbar.h | 1 + src/g_statusbar/shared_sbar.cpp | 21 +++++++++++++++++++ wadsrc/static/zscript/statusbar/statusbar.txt | 21 ++++++++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/g_statusbar/sbar.h b/src/g_statusbar/sbar.h index 0b3f676ca..0079d5b71 100644 --- a/src/g_statusbar/sbar.h +++ b/src/g_statusbar/sbar.h @@ -443,6 +443,7 @@ public: double drawClip[4] = { 0,0,0,0 }; // defines a clipping rectangle (not used yet) bool fullscreenOffsets = false; // current screen is displayed with fullscreen behavior. DVector2 cleanScale; // factor for scaled fullscreen display. + FMugShot mugshot; private: bool RepositionCoords (int &x, int &y, int xo, int yo, const int w, const int h) const; diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index c3925cb51..51106914e 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -431,6 +431,7 @@ void DBaseStatusBar::CallTick() GlobalVMStack.Call(func, params, countof(params), nullptr, 0); } else Tick(); + mugshot.Tick(CPlayer); } //--------------------------------------------------------------------------- @@ -1023,6 +1024,7 @@ void DBaseStatusBar::SetMugShotState(const char *stateName, bool waitTillDone, b VMValue params[] = { (DObject*)this, &statestring, waitTillDone, reset }; GlobalVMStack.Call(func, params, countof(params), nullptr, 0); } + mugshot.SetState(stateName, waitTillDone, reset); } //--------------------------------------------------------------------------- @@ -1196,6 +1198,7 @@ void DBaseStatusBar::NewGame () VMValue params[] = { (DObject*)this }; GlobalVMStack.Call(func, params, countof(params), nullptr, 0); } + mugshot.Reset(); } void DBaseStatusBar::ShowPop(int pop) @@ -1776,3 +1779,21 @@ DEFINE_ACTION_FUNCTION(DBaseStatusBar, FormatNumber) else fmt.Format("%s%*d", prefix.GetChars(), minsize, number); ACTION_RETURN_STRING(fmt); } + +DEFINE_ACTION_FUNCTION(DBaseStatusBar, ReceivedWeapon) +{ + PARAM_SELF_PROLOGUE(DBaseStatusBar); + self->mugshot.Grin(); + return 0; +} + +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); + ACTION_RETURN_INT(tex ? tex->id.GetIndex() : -1); +} diff --git a/wadsrc/static/zscript/statusbar/statusbar.txt b/wadsrc/static/zscript/statusbar/statusbar.txt index 059c602fd..2a1b92492 100644 --- a/wadsrc/static/zscript/statusbar/statusbar.txt +++ b/wadsrc/static/zscript/statusbar/statusbar.txt @@ -1,4 +1,21 @@ +struct MugShot +{ + enum StateFlags + { + STANDARD = 0x0, + + XDEATHFACE = 0x1, + ANIMATEDGODMODE = 0x2, + DISABLEGRIN = 0x4, + DISABLEOUCH = 0x8, + DISABLEPAIN = 0x10, + DISABLERAMPAGE = 0x20, + CUSTOM = 0x40, + } +} + + class BaseStatusBar native ui { enum EPop @@ -156,17 +173,18 @@ class BaseStatusBar native ui native virtual void Tick (); native virtual void Draw (int state, double TicFrac); native virtual void ScreenSizeChanged (); + native virtual clearscope void ReceivedWeapon (Weapon weapn); virtual void FlashItem (class itemtype) {} virtual void AttachToPlayer (PlayerInfo player) { CPlayer = player; } virtual void FlashCrosshair () { CrosshairSize = XHAIRPICKUPSIZE; } virtual void NewGame () {} virtual void ShowPop (int popnum) { ShowLog = (popnum == POP_Log && !ShowLog); } - virtual clearscope void ReceivedWeapon (Weapon weapn) {} virtual bool MustDrawLog(int state) { return true; } virtual void SetMugShotState (String state_name, bool wait_till_done=false, bool reset=false) {} native void RefreshBackground () const; + native TextureID GetMugshot(PlayerInfo player, String default_face, int accuracy, int stateflags=MugShot.STANDARD); // 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; @@ -676,6 +694,7 @@ class BaseStatusBar native ui DrawTexture(texture, pos, animated, screenalign, alpha, boxsize, itemAlign, flags); } } + } //============================================================================