This commit is contained in:
Rachael Alexanderson 2017-03-28 16:29:07 -04:00
commit 9da596cd9c
82 changed files with 3514 additions and 1619 deletions

View file

@ -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

View file

@ -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;

View file

@ -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)

View file

@ -532,6 +532,8 @@ public:
// [Nash] set player FOV
void SetFOV(float fov);
bool HasWeaponsInSlot(int slot) const;
bool Resurrect();
};
// Bookkeeping on players - state.

View file

@ -234,8 +234,6 @@ FString shotfile;
AActor* bodyque[BODYQUESIZE];
int bodyqueslot;
void R_ExecuteSetViewSize (FViewWindow &viewwindow);
FString savename;
FString BackupSaveName;

View file

@ -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

View file

@ -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);

View file

@ -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);
}

View file

@ -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
{

View file

@ -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);
}

View file

@ -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. :(

View file

@ -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__ */

View file

@ -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<const char *> 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);

View file

@ -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());
}
}
}

View file

@ -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<int> (font->StringWidth(cstring) + (spacing * cstring.Len()));
else //monospaced, so just multiply the character size
x -= static_cast<int> ((spacing) * cstring.Len());
break;
case ALIGN_CENTER:
case DI_TEXT_ALIGN_CENTER:
if (!monospaced)
x -= static_cast<int> (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);
}

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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,

View file

@ -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)
{

View file

@ -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;

View file

@ -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();
}
}

View file

@ -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.
}
}

View file

@ -901,3 +901,4 @@ xx(Player5)
xx(Player6)
xx(Player7)
xx(Player8)
xx(PlayerChunk)

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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<DrawPolyTrianglesCommand>(*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<uint32_t>(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<DrawRectCommand>(*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);
}
}

View file

@ -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;
};

File diff suppressed because it is too large Load diff

View file

@ -24,255 +24,13 @@
#include "screen_triangle.h"
template<typename BlendT, typename SamplerT>
class TriScreenDrawer8
namespace TriScreenDrawerModes
{
public:
static void Execute(const TriDrawTriangleArgs *args, WorkerThreadData *thread)
template<typename SamplerT>
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<typename SamplerT>
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<typename BlendT>
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<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);
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<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);
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<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);
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<typename BlendT, typename SamplerT>
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<SamplerT>(posU, posV, texPixels, texWidth, texHeight, color, translation);
uint32_t fgshade = SampleShade8<SamplerT>(posU, posV, texPixels, texWidth, texHeight);
dest[x * 8 + ix] = ShadeAndBlend8<BlendT>(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<SamplerT>(posU, posV, texPixels, texWidth, texHeight, color, translation);
uint32_t fgshade = SampleShade8<SamplerT>(posU, posV, texPixels, texWidth, texHeight);
dest[x] = ShadeAndBlend8<BlendT>(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<SamplerT>(posU, posV, texPixels, texWidth, texHeight, color, translation);
uint32_t fgshade = SampleShade8<SamplerT>(posU, posV, texPixels, texWidth, texHeight);
dest[x] = ShadeAndBlend8<BlendT>(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<typename BlendT, typename SamplerT>
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<SamplerT>(posU, posV, texPixels, texWidth, texHeight, color, translation);
uint32_t fgshade = SampleShade8<SamplerT>(posU, posV, texPixels, texWidth, texHeight);
*dest = ShadeAndBlend8<BlendT>(fgcolor, bgcolor, fgshade, lightshade, colormaps, srcalpha, destalpha);
posU += stepU;
dest++;
}
}
}
};

View file

@ -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);
}

View file

@ -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;
};

View file

@ -922,87 +922,128 @@ void ScreenTriangle::SubsectorWrite(const TriDrawTriangleArgs *args, WorkerThrea
}
}
std::vector<void(*)(const TriDrawTriangleArgs *, WorkerThreadData *)> ScreenTriangle::TriDraw8 =
void(*ScreenTriangle::TriDrawers8[])(const TriDrawTriangleArgs *, WorkerThreadData *) =
{
&TriScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::TextureSampler>::Execute, // "Copy", "opaque", false
&TriScreenDrawer8<TriScreenDrawerModes::MaskedBlend, TriScreenDrawerModes::TextureSampler>::Execute, // "AlphaBlend", "masked", false
&TriScreenDrawer8<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // "AddSolid", "translucent", false
&TriScreenDrawer8<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // "Add", "add", false
&TriScreenDrawer8<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // "Sub", "sub", false
&TriScreenDrawer8<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // "RevSub", "revsub", false
&TriScreenDrawer8<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::ShadedSampler>::Execute, // "Stencil", "stencil", false
&TriScreenDrawer8<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::ShadedSampler>::Execute, // "Shaded", "shaded", false
&TriScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateCopy", "opaque", true
&TriScreenDrawer8<TriScreenDrawerModes::MaskedBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateAlphaBlend", "masked", true
&TriScreenDrawer8<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateAdd", "add", true
&TriScreenDrawer8<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateSub", "sub", true
&TriScreenDrawer8<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateRevSub", "revsub", true
&TriScreenDrawer8<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::TextureSampler>::Execute, // "AddSrcColorOneMinusSrcColor", "addsrccolor", false
&TriScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::SkycapSampler>::Execute // "Skycap", "skycap", false
};
std::vector<void(*)(const TriDrawTriangleArgs *, WorkerThreadData *)> ScreenTriangle::TriFill8 =
{
&TriScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::FillSampler>::Execute, // "Copy", "opaque", false
&TriScreenDrawer8<TriScreenDrawerModes::MaskedBlend, TriScreenDrawerModes::FillSampler>::Execute, // "AlphaBlend", "masked", false
&TriScreenDrawer8<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // "AddSolid", "translucent", false
&TriScreenDrawer8<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // "Add", "add", false
&TriScreenDrawer8<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // "Sub", "sub", false
&TriScreenDrawer8<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // "RevSub", "revsub", false
&TriScreenDrawer8<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::ShadedSampler>::Execute, // "Stencil", "stencil", false
&TriScreenDrawer8<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::ShadedSampler>::Execute, // "Shaded", "shaded", false
&TriScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateCopy", "opaque", true
&TriScreenDrawer8<TriScreenDrawerModes::MaskedBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateAlphaBlend", "masked", true
&TriScreenDrawer8<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateAdd", "add", true
&TriScreenDrawer8<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateSub", "sub", true
&TriScreenDrawer8<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateRevSub", "revsub", true
&TriScreenDrawer8<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::FillSampler>::Execute, // "AddSrcColorOneMinusSrcColor", "addsrccolor", false
&TriScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::FillSampler>::Execute // "Skycap", "skycap", false
&TriScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureOpaque
&TriScreenDrawer8<TriScreenDrawerModes::MaskedBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureMasked
&TriScreenDrawer8<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureAdd
&TriScreenDrawer8<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureSub
&TriScreenDrawer8<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureRevSub
&TriScreenDrawer8<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureAddSrcColor
&TriScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedOpaque
&TriScreenDrawer8<TriScreenDrawerModes::MaskedBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedMasked
&TriScreenDrawer8<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedAdd
&TriScreenDrawer8<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedSub
&TriScreenDrawer8<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedRevSub
&TriScreenDrawer8<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedAddSrcColor
&TriScreenDrawer8<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::ShadedSampler>::Execute, // Shaded
&TriScreenDrawer8<TriScreenDrawerModes::AddClampShadedBlend, TriScreenDrawerModes::ShadedSampler>::Execute, // AddShaded
&TriScreenDrawer8<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::StencilSampler>::Execute, // Stencil
&TriScreenDrawer8<TriScreenDrawerModes::AddClampShadedBlend, TriScreenDrawerModes::StencilSampler>::Execute, // AddStencil
&TriScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillOpaque
&TriScreenDrawer8<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillAdd
&TriScreenDrawer8<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillSub
&TriScreenDrawer8<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillRevSub
&TriScreenDrawer8<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillAddSrcColor
&TriScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::SkycapSampler>::Execute // Skycap
};
#ifdef NO_SSE
std::vector<void(*)(const TriDrawTriangleArgs *, WorkerThreadData *)> ScreenTriangle::TriDraw32;
std::vector<void(*)(const TriDrawTriangleArgs *, WorkerThreadData *)> ScreenTriangle::TriFill32;
void(*ScreenTriangle::TriDrawers32[])(const TriDrawTriangleArgs *, WorkerThreadData *) =
{
nullptr
};
#else
std::vector<void(*)(const TriDrawTriangleArgs *, WorkerThreadData *)> ScreenTriangle::TriDraw32 =
void(*ScreenTriangle::TriDrawers32[])(const TriDrawTriangleArgs *, WorkerThreadData *) =
{
&TriScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::TextureSampler>::Execute, // "Copy", "opaque", false
&TriScreenDrawer32<TriScreenDrawerModes::MaskedBlend, TriScreenDrawerModes::TextureSampler>::Execute, // "AlphaBlend", "masked", false
&TriScreenDrawer32<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // "AddSolid", "translucent", false
&TriScreenDrawer32<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // "Add", "add", false
&TriScreenDrawer32<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // "Sub", "sub", false
&TriScreenDrawer32<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // "RevSub", "revsub", false
&TriScreenDrawer32<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::ShadedSampler>::Execute, // "Stencil", "stencil", false
&TriScreenDrawer32<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::ShadedSampler>::Execute, // "Shaded", "shaded", false
&TriScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateCopy", "opaque", true
&TriScreenDrawer32<TriScreenDrawerModes::MaskedBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateAlphaBlend", "masked", true
&TriScreenDrawer32<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateAdd", "add", true
&TriScreenDrawer32<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateSub", "sub", true
&TriScreenDrawer32<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateRevSub", "revsub", true
&TriScreenDrawer32<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::TextureSampler>::Execute, // "AddSrcColorOneMinusSrcColor", "addsrccolor", false
&TriScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::SkycapSampler>::Execute // "Skycap", "skycap", false
};
std::vector<void(*)(const TriDrawTriangleArgs *, WorkerThreadData *)> ScreenTriangle::TriFill32 =
{
&TriScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::FillSampler>::Execute, // "Copy", "opaque", false
&TriScreenDrawer32<TriScreenDrawerModes::MaskedBlend, TriScreenDrawerModes::FillSampler>::Execute, // "AlphaBlend", "masked", false
&TriScreenDrawer32<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // "AddSolid", "translucent", false
&TriScreenDrawer32<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // "Add", "add", false
&TriScreenDrawer32<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // "Sub", "sub", false
&TriScreenDrawer32<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // "RevSub", "revsub", false
&TriScreenDrawer32<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::ShadedSampler>::Execute, // "Stencil", "stencil", false
&TriScreenDrawer32<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::ShadedSampler>::Execute, // "Shaded", "shaded", false
&TriScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateCopy", "opaque", true
&TriScreenDrawer32<TriScreenDrawerModes::MaskedBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateAlphaBlend", "masked", true
&TriScreenDrawer32<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateAdd", "add", true
&TriScreenDrawer32<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateSub", "sub", true
&TriScreenDrawer32<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // "TranslateRevSub", "revsub", true
&TriScreenDrawer32<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::FillSampler>::Execute, // "AddSrcColorOneMinusSrcColor", "addsrccolor", false
&TriScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::FillSampler>::Execute // "Skycap", "skycap", false
&TriScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureOpaque
&TriScreenDrawer32<TriScreenDrawerModes::MaskedBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureMasked
&TriScreenDrawer32<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureAdd
&TriScreenDrawer32<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureSub
&TriScreenDrawer32<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureRevSub
&TriScreenDrawer32<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureAddSrcColor
&TriScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedOpaque
&TriScreenDrawer32<TriScreenDrawerModes::MaskedBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedMasked
&TriScreenDrawer32<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedAdd
&TriScreenDrawer32<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedSub
&TriScreenDrawer32<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedRevSub
&TriScreenDrawer32<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedAddSrcColor
&TriScreenDrawer32<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::ShadedSampler>::Execute, // Shaded
&TriScreenDrawer32<TriScreenDrawerModes::AddClampShadedBlend, TriScreenDrawerModes::ShadedSampler>::Execute, // AddShaded
&TriScreenDrawer32<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::StencilSampler>::Execute, // Stencil
&TriScreenDrawer32<TriScreenDrawerModes::AddClampShadedBlend, TriScreenDrawerModes::StencilSampler>::Execute, // AddStencil
&TriScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillOpaque
&TriScreenDrawer32<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillAdd
&TriScreenDrawer32<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillSub
&TriScreenDrawer32<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillRevSub
&TriScreenDrawer32<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillAddSrcColor
&TriScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::SkycapSampler>::Execute // Skycap
};
#endif
void(*ScreenTriangle::RectDrawers8[])(const void *, int, int, int, const RectDrawArgs *, WorkerThreadData *) =
{
&RectScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureOpaque
&RectScreenDrawer8<TriScreenDrawerModes::MaskedBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureMasked
&RectScreenDrawer8<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureAdd
&RectScreenDrawer8<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureSub
&RectScreenDrawer8<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureRevSub
&RectScreenDrawer8<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureAddSrcColor
&RectScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedOpaque
&RectScreenDrawer8<TriScreenDrawerModes::MaskedBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedMasked
&RectScreenDrawer8<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedAdd
&RectScreenDrawer8<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedSub
&RectScreenDrawer8<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedRevSub
&RectScreenDrawer8<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedAddSrcColor
&RectScreenDrawer8<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::ShadedSampler>::Execute, // Shaded
&RectScreenDrawer8<TriScreenDrawerModes::AddClampShadedBlend, TriScreenDrawerModes::ShadedSampler>::Execute, // AddShaded
&RectScreenDrawer8<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::StencilSampler>::Execute, // Stencil
&RectScreenDrawer8<TriScreenDrawerModes::AddClampShadedBlend, TriScreenDrawerModes::StencilSampler>::Execute, // AddStencil
&RectScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillOpaque
&RectScreenDrawer8<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillAdd
&RectScreenDrawer8<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillSub
&RectScreenDrawer8<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillRevSub
&RectScreenDrawer8<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillAddSrcColor
&RectScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::SkycapSampler>::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 *) =
{
&RectScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureOpaque
&RectScreenDrawer32<TriScreenDrawerModes::MaskedBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureMasked
&RectScreenDrawer32<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureAdd
&RectScreenDrawer32<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureSub
&RectScreenDrawer32<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureRevSub
&RectScreenDrawer32<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureAddSrcColor
&RectScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedOpaque
&RectScreenDrawer32<TriScreenDrawerModes::MaskedBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedMasked
&RectScreenDrawer32<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedAdd
&RectScreenDrawer32<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedSub
&RectScreenDrawer32<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedRevSub
&RectScreenDrawer32<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::TranslatedSampler>::Execute, // TranslatedAddSrcColor
&RectScreenDrawer32<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::ShadedSampler>::Execute, // Shaded
&RectScreenDrawer32<TriScreenDrawerModes::AddClampShadedBlend, TriScreenDrawerModes::ShadedSampler>::Execute, // AddShaded
&RectScreenDrawer32<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::StencilSampler>::Execute, // Stencil
&RectScreenDrawer32<TriScreenDrawerModes::AddClampShadedBlend, TriScreenDrawerModes::StencilSampler>::Execute, // AddStencil
&RectScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillOpaque
&RectScreenDrawer32<TriScreenDrawerModes::AddClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillAdd
&RectScreenDrawer32<TriScreenDrawerModes::SubClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillSub
&RectScreenDrawer32<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillRevSub
&RectScreenDrawer32<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillAddSrcColor
&RectScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::SkycapSampler>::Execute // Skycap
};
#endif

View file

@ -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<void(*)(const TriDrawTriangleArgs *, WorkerThreadData *)> TriDraw8;
static std::vector<void(*)(const TriDrawTriangleArgs *, WorkerThreadData *)> TriDraw32;
static std::vector<void(*)(const TriDrawTriangleArgs *, WorkerThreadData *)> TriFill8;
static std::vector<void(*)(const TriDrawTriangleArgs *, WorkerThreadData *)> 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; };
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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<double>(1.7f - dist2 * 1.7f, 0.0f, 1.0f);
double smooth_alpha = clamp<double>(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<int>(gl_particles_style, NumParticleTextures)];
}

View file

@ -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
};
};

View file

@ -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;
}

View file

@ -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<FDynamicColormap*>(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);
}
/////////////////////////////////////////////////////////////////////////////

View file

@ -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)
{

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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()

View file

@ -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);
}

View file

@ -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);

View file

@ -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);

View file

@ -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[] =

View file

@ -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<double>(1.1f - dist2 * 1.1f, 0.0f, 1.0f);
double round_alpha = clamp<double>(1.7f - dist2 * 1.7f, 0.0f, 1.0f);
double smooth_alpha = clamp<double>(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);
}
}
}

View file

@ -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
{

View file

@ -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<int>(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;

View file

@ -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<int>(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;

View file

@ -13,6 +13,7 @@
#include <stdlib.h>
#include <stddef.h>
#include <cmath>
#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;

View file

@ -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());

View file

@ -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);
}

View file

@ -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++)

View file

@ -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

View file

@ -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);

View file

@ -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;
}

View file

@ -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);

View file

@ -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.

View file

@ -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)
{

View file

@ -1153,7 +1153,7 @@ void Win32GLFrameBuffer::Unlock ()
bool Win32GLFrameBuffer::IsLocked ()
{
return m_Lock>0;// true;
return m_Lock > 0;
}
//==========================================================================

View file

@ -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);

View file

@ -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

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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<Actor> classname, double distance, int flags = 0, int ptr = AAPTR_DEFAULT);
native double GetSpriteAngle(int ptr = AAPTR_DEFAULT);

View file

@ -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));
}
}

View file

@ -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())
{

View file

@ -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

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}

View file

@ -8,7 +8,6 @@ struct SBarInfo native ui
native void NewGame();
native bool MustDrawLog(int state);
native void Tick();
native void FlashItem(class<Inventory> 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<Inventory> itemtype)
{
core.FlashItem(itemtype);
}
override void ShowPop(int popnum)
{
Super.ShowPop(popnum);

View file

@ -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<Inventory> itemtype) {}
virtual void FlashItem (class<Inventory> 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<Inventory> 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<Inventory> 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<Weapon> weap, int piecenum)
int CheckWeaponPiece(class<Weapon> 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<Weapon> 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<Ammo> 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<Inventory> 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);

View file

@ -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<Inventory> 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)