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,
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->y = y;
t->f = f;
t->sc = sc;
t->cr = cr;
t->builder = builder;
HUlib_clearTextLine(t);
}
@ -186,52 +187,44 @@ static boolean HUlib_delCharFromTextLine(hu_textline_t* t)
// 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_L (HU_GAPX - WIDESCREENDELTA)
#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;
const int font_height = SHORT(f['A'-HU_FONTSTART]->height) + 1;
if (l->visible)
if (align == align_topleft)
{
if (align == align_topleft)
{
HUlib_drawTextLineAt(l, l->x = HU_GAPX_L, l->y = align_offset[align], drawcursor);
align_offset[align] += font_height;
}
else if (align == align_topright)
{
HUlib_drawTextLineAt(l, l->x = HU_GAPX_R - l->width, l->y = align_offset[align], drawcursor);
align_offset[align] += font_height;
}
else if (align == align_bottomleft)
{
align_offset[align] -= font_height;
HUlib_drawTextLineAt(l, l->x = HU_GAPX_L, l->y = align_offset[align], drawcursor);
}
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);
}
else
{
HUlib_drawTextLineAt(l, l->x, l->y, drawcursor);
}
l->x = HU_GAPX_L;
l->y = align_offset[align];
align_offset[align] += font_height;
}
else if (align == align_topright)
{
l->x = HU_GAPX_R - l->width;
l->y = align_offset[align];
align_offset[align] += font_height;
}
else if (align == align_bottomleft)
{
align_offset[align] -= font_height;
l->x = HU_GAPX_L;
l->y = align_offset[align];
}
else if (align == align_bottomright)
{
align_offset[align] -= font_height;
l->x = HU_GAPX_R - l->width;
l->y = align_offset[align];
}
}
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;
char *oc = l->cr; //jff 2/17/98 remember default color
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]);
}
void HUlib_drawTextLine(hu_textline_t *l, align_t align, boolean drawcursor)
{
HUlib_alignWidget(l, align);
HUlib_drawTextLineAligned(l, drawcursor);
}
//
// 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;
for (i=0;i<h;i++)
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)
idx += s->h; // handle queue of lines
// 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;
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;
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->on = on;
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
@ -658,7 +657,7 @@ void HUlib_drawIText(hu_itext_t *it, align_t align)
{
hu_textline_t *l = &it->l;
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
#define HU_MAXMESSAGES 8
typedef enum {
align_topleft,
align_topright,
align_bottomleft,
align_bottomright,
align_direct,
num_aligns,
} align_t;
//
// Typedefs of widgets
//
@ -84,9 +75,24 @@ typedef struct
int width;
boolean visible;
void (*builder) (void);
} 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
@ -158,7 +164,8 @@ void HUlib_initTextLine
int y,
patch_t ***f,
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
@ -166,11 +173,8 @@ boolean HUlib_addCharToTextLine(hu_textline_t *t, char ch);
void HUlib_addStringToTextLine(hu_textline_t *t, char *s);
// draws tline
void HUlib_drawTextLine(hu_textline_t *l, boolean drawcursor);
void HUlib_drawTextLineAt(hu_textline_t *l, int x, int y, boolean drawcursor);
void HUlib_drawTextLine(hu_textline_t *l, align_t align, boolean drawcursor);
void HUlib_resetAlignOffsets();
void HUlib_drawTextLineAligned(hu_textline_t *l, align_t align, boolean drawcursor);
// erases text line
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_WIDGETS 12
typedef struct {
hu_textline_t *widget;
align_t align;
int x, y;
} widget_t;
static widget_t widgets[MAX_HUDS][MAX_WIDGETS] = {
{
{&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 boolean always_off = false;
@ -495,19 +491,27 @@ void HU_Init(void)
HU_ResetMessageColors();
}
void HU_ResetWidgets (void)
static inline void HU_enableWidget (hu_textline_t *line, boolean cond)
{
widget_t *widget = widgets[hud_active];
while (widget->widget)
if (cond)
{
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;
widget->widget->y = widget->y;
w->line->x = w->x;
w->line->y = w->y;
}
widget->widget->visible = false;
widget++;
w->line->visible = false;
w++;
}
}
@ -534,6 +538,17 @@ void HU_Stop(void)
//
// 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)
{
int i;
@ -592,32 +607,32 @@ void HU_Start(void)
//jff 2/16/98 added some HUD widgets
// create the map title widget - map title display in lower left of automap
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
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
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
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
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
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
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
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
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);
HUlib_addStringToTextLine(&w_keys, hud_keysstr);
HU_ResetWidgets();
HU_disableAllWidgets();
// init crosshair
if (hud_crosshair)
@ -1343,9 +1358,11 @@ int hud_level_stats, hud_level_time;
//
void HU_Drawer(void)
{
widget_t *widget = widgets[hud_active];
widget_t *w = widget;
align_t align_text = message_centered ? align_direct : align_topleft;
HUlib_resetAlignOffsets();
// jff 4/24/98 Erase current lines before drawing current
// needed when screen not fullsize
// killough 11/98: only do it when not fullsize
@ -1355,8 +1372,6 @@ void HU_Drawer(void)
HU_Erase();
}
HUlib_resetAlignOffsets();
if (message_list)
HUlib_drawMText(&w_rtext, align_text);
else
@ -1372,10 +1387,13 @@ void HU_Drawer(void)
ST_Drawer (false, true);
}
while (widget->widget)
while (w->line)
{
HUlib_drawTextLineAligned(widget->widget, widget->align, false);
widget++;
if (w->line->visible)
{
HUlib_drawTextLine(w->line, w->align, false);
}
w++;
}
}
@ -1384,9 +1402,11 @@ void WI_DrawTimeWidget(void)
{
if (hud_level_time)
{
w_sttime.x = HU_HUDX;
w_sttime.y = 0;
// leveltime is already added to totalleveltimes before WI_Start()
//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)
{
widget_t *w = widget = widgets[hud_active];
plr = &players[displayplayer]; // killough 3/7/98
HU_ResetWidgets();
HU_disableAllWidgets();
draw_crispy_hud = false;
hu_invul = (plr->powers[pw_invulnerability] > 4*32 ||
@ -1582,25 +1603,18 @@ void HU_Ticker(void)
if (automapactive)
{
// map title
w_title.visible = true;
HU_enableWidget(&w_title, true);
if (map_level_stats)
HU_widget_build_monsec();
if (map_level_time)
HU_widget_build_sttime();
if (STRICTMODE(map_player_coords))
HU_widget_build_coord();
HU_enableWidget(&w_monsec, map_level_stats);
HU_enableWidget(&w_sttime, map_level_time);
HU_enableWidget(&w_coord, STRICTMODE(map_player_coords));
}
else
{
if (STRICTMODE(map_player_coords) == 2)
HU_widget_build_coord();
HU_enableWidget(&w_coord, STRICTMODE(map_player_coords) == 2);
}
if (plr->powers[pw_showfps])
HU_widget_build_fps();
HU_enableWidget(&w_fps, plr->powers[pw_showfps]);
if (hud_displayed &&
scaledviewheight == SCREENHEIGHT &&
@ -1613,28 +1627,32 @@ void HU_Ticker(void)
}
else
{
HU_widget_build_weapon();
HU_widget_build_armor();
HU_widget_build_health();
HU_widget_build_ammo();
HU_widget_build_keys();
HU_enableWidget(&w_weapon, true);
HU_enableWidget(&w_armor, true);
HU_enableWidget(&w_health, true);
HU_enableWidget(&w_ammo, true);
HU_enableWidget(&w_keys, true);
}
if (hud_level_stats)
HU_widget_build_monsec();
if (hud_level_time)
HU_widget_build_sttime();
HU_enableWidget(&w_monsec, hud_level_stats);
HU_enableWidget(&w_sttime, hud_level_time);
}
else if (scaledviewheight &&
scaledviewheight < SCREENHEIGHT &&
automap_off)
{
if (hud_level_stats)
HU_widget_build_monsec();
HU_enableWidget(&w_monsec, hud_level_stats);
HU_enableWidget(&w_sttime, hud_level_time);
}
if (hud_level_time)
HU_widget_build_sttime();
while (w->line)
{
if (w->line->visible)
{
if (w->line->builder)
w->line->builder();
}
w++;
}
// update crosshair properties
@ -1855,7 +1873,7 @@ boolean HU_Responder(event_t *ev)
static const struct {
const char *name, *altname;
hu_textline_t *const widget;
hu_textline_t *const line;
} w_names[] = {
{"title", "levelname", &w_title},
{"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++)
{
if (widgets[hud][i].widget == NULL)
if (widgets[hud][i].line == NULL)
{
break;
}
@ -1891,12 +1909,12 @@ static boolean HU_AddToWidgets (hu_textline_t *widget, int hud, align_t align, i
return false;
}
widgets[hud][i].widget = widget;
widgets[hud][i].line = widget;
widgets[hud][i].align = align;
widgets[hud][i].x = x;
widgets[hud][i].y = y;
widgets[hud][i + 1].widget = NULL;
widgets[hud][i + 1].line = NULL;
return true;
}
@ -1910,7 +1928,7 @@ static hu_textline_t *HU_WidgetByName (const char *name)
if (strcasecmp(name, w_names[i].name) == 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_Start(void);
void HU_ResetWidgets (void);
void HU_disableAllWidgets (void);
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_active = (hud_active + 1) % 3; // cycle hud_active
HU_ResetWidgets();
HU_disableAllWidgets();
}
return true;
}

View File

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