some fixes to the dynamic HUD implementation (#916)

* build and align text widgets in HU_Ticker(), drawn then in HU_Drawer()

* fix widget scope

* fix clang build

* minor fix

* simplify

* back to alignment in HU_Drawer()

* fix the widgets jumping around when switching from status bar to fullscreen
This commit is contained in:
Fabian Greffrath 2023-02-28 17:14:49 +01:00 committed by GitHub
parent 1997a14c1f
commit d75ef3c308
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 146 additions and 122 deletions

View File

@ -96,13 +96,14 @@ void HUlib_clearTextLine(hu_textline_t* t)
// //
void HUlib_initTextLine(hu_textline_t *t, int x, int y, patch_t ***f, int sc, void HUlib_initTextLine(hu_textline_t *t, int x, int y, patch_t ***f, int sc,
char *cr) //jff 2/16/98 add color range parameter char *cr, void (*builder)(void)) //jff 2/16/98 add color range parameter
{ {
t->x = x; t->x = x;
t->y = y; t->y = y;
t->f = f; t->f = f;
t->sc = sc; t->sc = sc;
t->cr = cr; t->cr = cr;
t->builder = builder;
HUlib_clearTextLine(t); HUlib_clearTextLine(t);
} }
@ -186,52 +187,44 @@ static boolean HUlib_delCharFromTextLine(hu_textline_t* t)
// Returns nothing // Returns nothing
// //
void HUlib_drawTextLine(hu_textline_t *l, boolean drawcursor)
{
HUlib_drawTextLineAt(l, l->x, l->y, drawcursor);
}
#define HU_GAPX 2 #define HU_GAPX 2
#define HU_GAPX_L (HU_GAPX - WIDESCREENDELTA) #define HU_GAPX_L (HU_GAPX - WIDESCREENDELTA)
#define HU_GAPX_R (ORIGWIDTH - HU_GAPX_L) #define HU_GAPX_R (ORIGWIDTH - HU_GAPX_L)
void HUlib_drawTextLineAligned(hu_textline_t *l, align_t align, boolean drawcursor) static void HUlib_alignWidget(hu_textline_t *l, align_t align)
{ {
patch_t *const *const f = *l->f; patch_t *const *const f = *l->f;
const int font_height = SHORT(f['A'-HU_FONTSTART]->height) + 1; const int font_height = SHORT(f['A'-HU_FONTSTART]->height) + 1;
if (l->visible) if (align == align_topleft)
{ {
if (align == align_topleft) l->x = HU_GAPX_L;
{ l->y = align_offset[align];
HUlib_drawTextLineAt(l, l->x = HU_GAPX_L, l->y = align_offset[align], drawcursor); align_offset[align] += font_height;
align_offset[align] += font_height; }
} else if (align == align_topright)
else if (align == align_topright) {
{ l->x = HU_GAPX_R - l->width;
HUlib_drawTextLineAt(l, l->x = HU_GAPX_R - l->width, l->y = align_offset[align], drawcursor); l->y = align_offset[align];
align_offset[align] += font_height; align_offset[align] += font_height;
} }
else if (align == align_bottomleft) else if (align == align_bottomleft)
{ {
align_offset[align] -= font_height; align_offset[align] -= font_height;
HUlib_drawTextLineAt(l, l->x = HU_GAPX_L, l->y = align_offset[align], drawcursor); l->x = HU_GAPX_L;
} l->y = align_offset[align];
else if (align == align_bottomright) }
{ else if (align == align_bottomright)
align_offset[align] -= font_height; {
HUlib_drawTextLineAt(l, l->x = HU_GAPX_R - l->width, l->y = align_offset[align], drawcursor); align_offset[align] -= font_height;
} l->x = HU_GAPX_R - l->width;
else l->y = align_offset[align];
{
HUlib_drawTextLineAt(l, l->x, l->y, drawcursor);
}
} }
} }
void HUlib_drawTextLineAt(hu_textline_t *l, int x, int y, boolean drawcursor) static void HUlib_drawTextLineAligned(hu_textline_t *l, boolean drawcursor)
{ {
int i; // killough 1/18/98 -- support multiple lines int i, x = l->x, y = l->y; // killough 1/18/98 -- support multiple lines
unsigned char c; unsigned char c;
char *oc = l->cr; //jff 2/17/98 remember default color char *oc = l->cr; //jff 2/17/98 remember default color
patch_t *const *const f = *l->f; patch_t *const *const f = *l->f;
@ -280,6 +273,12 @@ void HUlib_drawTextLineAt(hu_textline_t *l, int x, int y, boolean drawcursor)
V_DrawPatchDirect(x, y, FG, f['_' - l->sc]); V_DrawPatchDirect(x, y, FG, f['_' - l->sc]);
} }
void HUlib_drawTextLine(hu_textline_t *l, align_t align, boolean drawcursor)
{
HUlib_alignWidget(l, align);
HUlib_drawTextLineAligned(l, drawcursor);
}
// //
// HUlib_eraseTextLine() // HUlib_eraseTextLine()
// //
@ -348,7 +347,7 @@ void HUlib_initSText(hu_stext_t *s, int x, int y, int h, patch_t ***font,
s->cl = 0; s->cl = 0;
for (i=0;i<h;i++) for (i=0;i<h;i++)
HUlib_initTextLine(s->l+i, x, y - i*(SHORT((*font[0])->height)+1), HUlib_initTextLine(s->l+i, x, y - i*(SHORT((*font[0])->height)+1),
font, startchar, cr); font, startchar, cr, NULL);
} }
// //
@ -406,7 +405,7 @@ void HUlib_drawSText(hu_stext_t* s, align_t align)
if (idx < 0) if (idx < 0)
idx += s->h; // handle queue of lines idx += s->h; // handle queue of lines
// need a decision made here on whether to skip the draw // need a decision made here on whether to skip the draw
HUlib_drawTextLineAligned(&s->l[idx], align, false); // no cursor, please HUlib_drawTextLine(&s->l[idx], align, false); // no cursor, please
} }
} }
@ -466,7 +465,7 @@ void HUlib_initMText(hu_mtext_t *m, int x, int y, patch_t ***font,
y += HU_REFRESHSPACING * hud_msg_lines; y += HU_REFRESHSPACING * hud_msg_lines;
for (i=0; i<hud_msg_lines; i++, y -= HU_REFRESHSPACING) for (i=0; i<hud_msg_lines; i++, y -= HU_REFRESHSPACING)
HUlib_initTextLine(&m->l[i], x, y, font, startchar, cr); HUlib_initTextLine(&m->l[i], x, y, font, startchar, cr, NULL);
} }
// //
@ -540,7 +539,7 @@ void HUlib_drawMText(hu_mtext_t* m, align_t align)
m->l[idx].y = i * HU_REFRESHSPACING; m->l[idx].y = i * HU_REFRESHSPACING;
HUlib_drawTextLineAligned(&m->l[idx], align, false); // no cursor, please HUlib_drawTextLine(&m->l[idx], align, false); // no cursor, please
} }
} }
@ -587,7 +586,7 @@ void HUlib_initIText(hu_itext_t *it, int x, int y, patch_t ***font,
it->lm = 0; // default left margin is start of text it->lm = 0; // default left margin is start of text
it->on = on; it->on = on;
it->laston = true; it->laston = true;
HUlib_initTextLine(&it->l, x, y, font, startchar, cr); HUlib_initTextLine(&it->l, x, y, font, startchar, cr, NULL);
} }
// The following deletion routines adhere to the left margin restriction // The following deletion routines adhere to the left margin restriction
@ -658,7 +657,7 @@ void HUlib_drawIText(hu_itext_t *it, align_t align)
{ {
hu_textline_t *l = &it->l; hu_textline_t *l = &it->l;
if ((l->visible = *it->on)) if ((l->visible = *it->on))
HUlib_drawTextLineAligned(l, align, true); // draw the line w/ cursor HUlib_drawTextLine(l, align, true); // draw the line w/ cursor
} }
// //

View File

@ -47,15 +47,6 @@
//jff 2/26/98 maximum number of messages allowed in refresh list //jff 2/26/98 maximum number of messages allowed in refresh list
#define HU_MAXMESSAGES 8 #define HU_MAXMESSAGES 8
typedef enum {
align_topleft,
align_topright,
align_bottomleft,
align_bottomright,
align_direct,
num_aligns,
} align_t;
// //
// Typedefs of widgets // Typedefs of widgets
// //
@ -84,9 +75,24 @@ typedef struct
int width; int width;
boolean visible; boolean visible;
void (*builder) (void);
} hu_textline_t; } hu_textline_t;
typedef enum {
align_topleft,
align_topright,
align_bottomleft,
align_bottomright,
align_direct,
num_aligns,
} align_t;
typedef struct {
hu_textline_t *line;
align_t align;
int x, y;
} widget_t;
// Scrolling Text window widget // Scrolling Text window widget
@ -158,7 +164,8 @@ void HUlib_initTextLine
int y, int y,
patch_t ***f, patch_t ***f,
int sc, int sc,
char *cr //jff 2/16/98 add color range parameter char *cr, //jff 2/16/98 add color range parameter
void (*builder)(void)
); );
// returns success // returns success
@ -166,11 +173,8 @@ boolean HUlib_addCharToTextLine(hu_textline_t *t, char ch);
void HUlib_addStringToTextLine(hu_textline_t *t, char *s); void HUlib_addStringToTextLine(hu_textline_t *t, char *s);
// draws tline // draws tline
void HUlib_drawTextLine(hu_textline_t *l, boolean drawcursor); void HUlib_drawTextLine(hu_textline_t *l, align_t align, boolean drawcursor);
void HUlib_drawTextLineAt(hu_textline_t *l, int x, int y, boolean drawcursor);
void HUlib_resetAlignOffsets(); void HUlib_resetAlignOffsets();
void HUlib_drawTextLineAligned(hu_textline_t *l, align_t align, boolean drawcursor);
// erases text line // erases text line
void HUlib_eraseTextLine(hu_textline_t *l); void HUlib_eraseTextLine(hu_textline_t *l);

View File

@ -128,12 +128,6 @@ static hu_textline_t w_sttime; // time above status bar
#define MAX_HUDS 3 #define MAX_HUDS 3
#define MAX_WIDGETS 12 #define MAX_WIDGETS 12
typedef struct {
hu_textline_t *widget;
align_t align;
int x, y;
} widget_t;
static widget_t widgets[MAX_HUDS][MAX_WIDGETS] = { static widget_t widgets[MAX_HUDS][MAX_WIDGETS] = {
{ {
{&w_title, align_bottomleft}, {&w_title, align_bottomleft},
@ -174,6 +168,8 @@ static widget_t widgets[MAX_HUDS][MAX_WIDGETS] = {
} }
}; };
static widget_t *widget = *widgets;
static void HU_ParseHUD (void); static void HU_ParseHUD (void);
static boolean always_off = false; static boolean always_off = false;
@ -495,19 +491,27 @@ void HU_Init(void)
HU_ResetMessageColors(); HU_ResetMessageColors();
} }
void HU_ResetWidgets (void) static inline void HU_enableWidget (hu_textline_t *line, boolean cond)
{ {
widget_t *widget = widgets[hud_active]; if (cond)
while (widget->widget)
{ {
if (widget->align == align_direct) line->visible = true;
}
}
void HU_disableAllWidgets (void)
{
widget_t *w = widget;
while (w->line)
{
if (w->align == align_direct)
{ {
widget->widget->x = widget->x; w->line->x = w->x;
widget->widget->y = widget->y; w->line->y = w->y;
} }
widget->widget->visible = false; w->line->visible = false;
widget++; w++;
} }
} }
@ -534,6 +538,17 @@ void HU_Stop(void)
// //
// Passed nothing, returns nothing // Passed nothing, returns nothing
// //
static void HU_widget_build_fps (void);
static void HU_widget_build_coord (void);
static void HU_widget_build_sttime(void);
static void HU_widget_build_monsec(void);
static void HU_widget_build_keys (void);
static void HU_widget_build_weapon (void);
static void HU_widget_build_armor (void);
static void HU_widget_build_health (void);
static void HU_widget_build_ammo (void);
void HU_Start(void) void HU_Start(void)
{ {
int i; int i;
@ -592,32 +607,32 @@ void HU_Start(void)
//jff 2/16/98 added some HUD widgets //jff 2/16/98 added some HUD widgets
// create the map title widget - map title display in lower left of automap // create the map title widget - map title display in lower left of automap
HUlib_initTextLine(&w_title, HU_TITLEX, HU_TITLEY, &hu_font, HUlib_initTextLine(&w_title, HU_TITLEX, HU_TITLEY, &hu_font,
HU_FONTSTART, colrngs[hudcolor_titl]); HU_FONTSTART, colrngs[hudcolor_titl], NULL);
// create the hud health widget // create the hud health widget
HUlib_initTextLine(&w_health, 0, 0, &hu_font2, HU_FONTSTART, colrngs[CR_GREEN]); HUlib_initTextLine(&w_health, 0, 0, &hu_font2, HU_FONTSTART, colrngs[CR_GREEN], HU_widget_build_health);
// create the hud armor widget // create the hud armor widget
HUlib_initTextLine(&w_armor, 0, 0, &hu_font2, HU_FONTSTART, colrngs[CR_GREEN]); HUlib_initTextLine(&w_armor, 0, 0, &hu_font2, HU_FONTSTART, colrngs[CR_GREEN], HU_widget_build_armor);
// create the hud ammo widget // create the hud ammo widget
HUlib_initTextLine(&w_ammo, 0, 0, &hu_font2, HU_FONTSTART, colrngs[CR_GOLD]); HUlib_initTextLine(&w_ammo, 0, 0, &hu_font2, HU_FONTSTART, colrngs[CR_GOLD], HU_widget_build_ammo);
// create the hud weapons widget // create the hud weapons widget
HUlib_initTextLine(&w_weapon, 0, 0, &hu_font2, HU_FONTSTART, colrngs[CR_GRAY]); HUlib_initTextLine(&w_weapon, 0, 0, &hu_font2, HU_FONTSTART, colrngs[CR_GRAY], HU_widget_build_weapon);
// create the hud keys widget // create the hud keys widget
HUlib_initTextLine(&w_keys, 0, 0, &hu_font2, HU_FONTSTART, colrngs[CR_GRAY]); HUlib_initTextLine(&w_keys, 0, 0, &hu_font2, HU_FONTSTART, colrngs[CR_GRAY], HU_widget_build_keys);
// create the hud monster/secret widget // create the hud monster/secret widget
HUlib_initTextLine(&w_monsec, 0, 0, &hu_font2, HU_FONTSTART, colrngs[CR_GRAY]); HUlib_initTextLine(&w_monsec, 0, 0, &hu_font2, HU_FONTSTART, colrngs[CR_GRAY], HU_widget_build_monsec);
HUlib_initTextLine(&w_sttime, 0, 0, &hu_font2, HU_FONTSTART, colrngs[CR_GRAY]); HUlib_initTextLine(&w_sttime, 0, 0, &hu_font2, HU_FONTSTART, colrngs[CR_GRAY], HU_widget_build_sttime);
// create the automaps coordinate widget // create the automaps coordinate widget
HUlib_initTextLine(&w_coord, 0, 0, &hu_font2, HU_FONTSTART, colrngs[hudcolor_xyco]); HUlib_initTextLine(&w_coord, 0, 0, &hu_font2, HU_FONTSTART, colrngs[hudcolor_xyco], HU_widget_build_coord);
HUlib_initTextLine(&w_fps, 0, 0, &hu_font2, HU_FONTSTART, colrngs[hudcolor_xyco]); HUlib_initTextLine(&w_fps, 0, 0, &hu_font2, HU_FONTSTART, colrngs[hudcolor_xyco], HU_widget_build_fps);
// initialize the automap's level title widget // initialize the automap's level title widget
if (gamemapinfo && gamemapinfo->levelname) if (gamemapinfo && gamemapinfo->levelname)
@ -685,7 +700,7 @@ void HU_Start(void)
sprintf(hud_keysstr, "%s %c%c", deathmatch ? "FRG" : "KEY", '\x1b', '0'+CR_RED); sprintf(hud_keysstr, "%s %c%c", deathmatch ? "FRG" : "KEY", '\x1b', '0'+CR_RED);
HUlib_addStringToTextLine(&w_keys, hud_keysstr); HUlib_addStringToTextLine(&w_keys, hud_keysstr);
HU_ResetWidgets(); HU_disableAllWidgets();
// init crosshair // init crosshair
if (hud_crosshair) if (hud_crosshair)
@ -1343,9 +1358,11 @@ int hud_level_stats, hud_level_time;
// //
void HU_Drawer(void) void HU_Drawer(void)
{ {
widget_t *widget = widgets[hud_active]; widget_t *w = widget;
align_t align_text = message_centered ? align_direct : align_topleft; align_t align_text = message_centered ? align_direct : align_topleft;
HUlib_resetAlignOffsets();
// jff 4/24/98 Erase current lines before drawing current // jff 4/24/98 Erase current lines before drawing current
// needed when screen not fullsize // needed when screen not fullsize
// killough 11/98: only do it when not fullsize // killough 11/98: only do it when not fullsize
@ -1355,8 +1372,6 @@ void HU_Drawer(void)
HU_Erase(); HU_Erase();
} }
HUlib_resetAlignOffsets();
if (message_list) if (message_list)
HUlib_drawMText(&w_rtext, align_text); HUlib_drawMText(&w_rtext, align_text);
else else
@ -1372,10 +1387,13 @@ void HU_Drawer(void)
ST_Drawer (false, true); ST_Drawer (false, true);
} }
while (widget->widget) while (w->line)
{ {
HUlib_drawTextLineAligned(widget->widget, widget->align, false); if (w->line->visible)
widget++; {
HUlib_drawTextLine(w->line, w->align, false);
}
w++;
} }
} }
@ -1384,9 +1402,11 @@ void WI_DrawTimeWidget(void)
{ {
if (hud_level_time) if (hud_level_time)
{ {
w_sttime.x = HU_HUDX;
w_sttime.y = 0;
// leveltime is already added to totalleveltimes before WI_Start() // leveltime is already added to totalleveltimes before WI_Start()
//HU_widget_build_sttime(); //HU_widget_build_sttime();
HUlib_drawTextLineAt(&w_sttime, HU_HUDX, 0, false); HUlib_drawTextLine(&w_sttime, align_direct, false);
} }
} }
@ -1437,9 +1457,10 @@ int M_StringWidth(char *string);
void HU_Ticker(void) void HU_Ticker(void)
{ {
widget_t *w = widget = widgets[hud_active];
plr = &players[displayplayer]; // killough 3/7/98 plr = &players[displayplayer]; // killough 3/7/98
HU_ResetWidgets(); HU_disableAllWidgets();
draw_crispy_hud = false; draw_crispy_hud = false;
hu_invul = (plr->powers[pw_invulnerability] > 4*32 || hu_invul = (plr->powers[pw_invulnerability] > 4*32 ||
@ -1582,25 +1603,18 @@ void HU_Ticker(void)
if (automapactive) if (automapactive)
{ {
// map title // map title
w_title.visible = true; HU_enableWidget(&w_title, true);
if (map_level_stats) HU_enableWidget(&w_monsec, map_level_stats);
HU_widget_build_monsec(); HU_enableWidget(&w_sttime, map_level_time);
HU_enableWidget(&w_coord, STRICTMODE(map_player_coords));
if (map_level_time)
HU_widget_build_sttime();
if (STRICTMODE(map_player_coords))
HU_widget_build_coord();
} }
else else
{ {
if (STRICTMODE(map_player_coords) == 2) HU_enableWidget(&w_coord, STRICTMODE(map_player_coords) == 2);
HU_widget_build_coord();
} }
if (plr->powers[pw_showfps]) HU_enableWidget(&w_fps, plr->powers[pw_showfps]);
HU_widget_build_fps();
if (hud_displayed && if (hud_displayed &&
scaledviewheight == SCREENHEIGHT && scaledviewheight == SCREENHEIGHT &&
@ -1613,28 +1627,32 @@ void HU_Ticker(void)
} }
else else
{ {
HU_widget_build_weapon(); HU_enableWidget(&w_weapon, true);
HU_widget_build_armor(); HU_enableWidget(&w_armor, true);
HU_widget_build_health(); HU_enableWidget(&w_health, true);
HU_widget_build_ammo(); HU_enableWidget(&w_ammo, true);
HU_widget_build_keys(); HU_enableWidget(&w_keys, true);
} }
if (hud_level_stats) HU_enableWidget(&w_monsec, hud_level_stats);
HU_widget_build_monsec(); HU_enableWidget(&w_sttime, hud_level_time);
if (hud_level_time)
HU_widget_build_sttime();
} }
else if (scaledviewheight && else if (scaledviewheight &&
scaledviewheight < SCREENHEIGHT && scaledviewheight < SCREENHEIGHT &&
automap_off) automap_off)
{ {
if (hud_level_stats) HU_enableWidget(&w_monsec, hud_level_stats);
HU_widget_build_monsec(); HU_enableWidget(&w_sttime, hud_level_time);
}
if (hud_level_time) while (w->line)
HU_widget_build_sttime(); {
if (w->line->visible)
{
if (w->line->builder)
w->line->builder();
}
w++;
} }
// update crosshair properties // update crosshair properties
@ -1855,7 +1873,7 @@ boolean HU_Responder(event_t *ev)
static const struct { static const struct {
const char *name, *altname; const char *name, *altname;
hu_textline_t *const widget; hu_textline_t *const line;
} w_names[] = { } w_names[] = {
{"title", "levelname", &w_title}, {"title", "levelname", &w_title},
{"armor", NULL, &w_armor}, {"armor", NULL, &w_armor},
@ -1880,7 +1898,7 @@ static boolean HU_AddToWidgets (hu_textline_t *widget, int hud, align_t align, i
for (i = 0; i < MAX_WIDGETS - 1; i++) for (i = 0; i < MAX_WIDGETS - 1; i++)
{ {
if (widgets[hud][i].widget == NULL) if (widgets[hud][i].line == NULL)
{ {
break; break;
} }
@ -1891,12 +1909,12 @@ static boolean HU_AddToWidgets (hu_textline_t *widget, int hud, align_t align, i
return false; return false;
} }
widgets[hud][i].widget = widget; widgets[hud][i].line = widget;
widgets[hud][i].align = align; widgets[hud][i].align = align;
widgets[hud][i].x = x; widgets[hud][i].x = x;
widgets[hud][i].y = y; widgets[hud][i].y = y;
widgets[hud][i + 1].widget = NULL; widgets[hud][i + 1].line = NULL;
return true; return true;
} }
@ -1910,7 +1928,7 @@ static hu_textline_t *HU_WidgetByName (const char *name)
if (strcasecmp(name, w_names[i].name) == 0 || if (strcasecmp(name, w_names[i].name) == 0 ||
(w_names[i].altname && strcasecmp(name, w_names[i].altname) == 0)) (w_names[i].altname && strcasecmp(name, w_names[i].altname) == 0))
{ {
return w_names[i].widget; return w_names[i].line;
} }
} }

View File

@ -55,7 +55,7 @@ extern patch_t **hu_font;
// //
void HU_Init(void); void HU_Init(void);
void HU_Start(void); void HU_Start(void);
void HU_ResetWidgets (void); void HU_disableAllWidgets (void);
boolean HU_Responder(event_t* ev); boolean HU_Responder(event_t* ev);

View File

@ -5553,7 +5553,7 @@ boolean M_Responder (event_t* ev)
{ {
hud_displayed = 1; //jff 3/3/98 turn hud on hud_displayed = 1; //jff 3/3/98 turn hud on
hud_active = (hud_active + 1) % 3; // cycle hud_active hud_active = (hud_active + 1) % 3; // cycle hud_active
HU_ResetWidgets(); HU_disableAllWidgets();
} }
return true; return true;
} }

View File

@ -38,6 +38,7 @@
#include "r_sky.h" #include "r_sky.h"
#include "v_video.h" #include "v_video.h"
#include "st_stuff.h" #include "st_stuff.h"
#include "hu_stuff.h"
// Fineangles in the SCREENWIDTH wide window. // Fineangles in the SCREENWIDTH wide window.
#define FIELDOFVIEW 2048 #define FIELDOFVIEW 2048
@ -550,6 +551,8 @@ void R_ExecuteSetViewSize (void)
} }
} }
HU_disableAllWidgets();
// [crispy] forcefully initialize the status bar backing screen // [crispy] forcefully initialize the status bar backing screen
ST_refreshBackground(true); ST_refreshBackground(true);