first attempt at dynamic HUD widget positioning (#890)

* factor out HUD widget generation from HU_Drawer() into HU_Ticker()

* removed unused dead code

* remove obsolete comment

* fix typo

* first attempt at dynamic HUD widget positioning

* fix build error

* proper alignment

* minor fixes

* be a bit more careful when calculating string lengths

* determine font height from the 'A' letter

* reset color range in the w_keys

* some clean-up

* replace coord widgets with a single widget, add fps widget

* git rid of separate K/I/S and time widgets

* add back STRICTMODE

* move HU_top() closer to HU_widget_build_keys()

* separate config keys for stats/time widgets on automap, hud, status bar

* add config key to choose HUD font

* no need for a separate setting for widgets above status bar

* factor out HU_ResetWidgets() and call it after rearranging HUD

* improve color scheme for the monsec widget

* fix ammo widget rendering bug with no ammo

* improve color scheme for the time widget

* some macros

* rearrange HU_Start()

* rearrange HU_Ticker()

* fix build

* add parser

* rename HU_ResetWidgetWidths() back to HU_ResetWidgets()

* working inplementation!

* init hud variable

* fix direct positioning for secret message widget

* move coord widget to the topright corner

* get rid of hud_distributed, iterate through HUD by hud_active

* fix Crispy HUD "off" state

* don't leave "empty" HUD completely empty actually
This commit is contained in:
Fabian Greffrath 2023-02-10 12:37:23 +01:00 committed by GitHub
parent 4d5adaf346
commit 914a4ccf12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 670 additions and 705 deletions

View File

@ -5,6 +5,7 @@
//
// Copyright (C) 1999 by
// id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
// Copyright (C) 2023 Fabian Greffrath
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@ -38,6 +39,21 @@
// boolean : whether the screen is always erased
#define noterased viewwindowx
static int align_offset[num_aligns];
void HUlib_resetAlignOffsets (void)
{
int bottom = 199;
if (scaledviewheight < SCREENHEIGHT || crispy_hud || automap_on)
bottom -= 32;
align_offset[align_topleft] = 0;
align_offset[align_topright] = 0;
align_offset[align_bottomleft] = bottom;
align_offset[align_bottomright] = bottom;
}
//
// not used currently
// code to initialize HUlib would go here if needed
@ -65,6 +81,7 @@ void HUlib_clearTextLine(hu_textline_t* t)
t->len = 0;
t->l[0] = 0;
t->needsupdate = true;
t->width = 0;
}
//
@ -114,6 +131,35 @@ boolean HUlib_addCharToTextLine(hu_textline_t *t, char ch)
}
}
void HUlib_addStringToTextLine(hu_textline_t *l, char *s)
{
int w = 0;
unsigned char c;
while (*s)
{
c = toupper(*s++);
if (c == '\x1b')
{
HUlib_addCharToTextLine(l, c);
HUlib_addCharToTextLine(l, *s++);
continue;
}
else if (c != ' ' && c >= l->sc && c <= HU_FONTEND + 6)
w += SHORT(l->f[c - l->sc]->width);
else
w += 4;
HUlib_addCharToTextLine(l, c);
}
while (*--s == ' ')
w -= 4;
l->width = w;
}
//
// HUlib_delCharFromTextLine()
//
@ -142,6 +188,43 @@ 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)
{
const int font_height = SHORT(l->f['A'-HU_FONTSTART]->height) + 1;
if (l->width)
{
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);
}
}
}
void HUlib_drawTextLineAt(hu_textline_t *l, int x, int y, boolean drawcursor)
{
int i; // killough 1/18/98 -- support multiple lines
@ -294,10 +377,8 @@ void HUlib_addMessageToSText(hu_stext_t *s, char *prefix, char *msg)
{
HUlib_addLineToSText(s);
if (prefix)
while (*prefix)
HUlib_addCharToTextLine(&s->l[s->cl], *prefix++);
while (*msg)
HUlib_addCharToTextLine(&s->l[s->cl], *msg++);
HUlib_addStringToTextLine(&s->l[s->cl], prefix);
HUlib_addStringToTextLine(&s->l[s->cl], msg);
}
//
@ -309,7 +390,7 @@ void HUlib_addMessageToSText(hu_stext_t *s, char *prefix, char *msg)
// Returns nothing
//
void HUlib_drawSText(hu_stext_t* s)
void HUlib_drawSText(hu_stext_t* s, align_t align)
{
int i;
if (*s->on)
@ -319,7 +400,7 @@ void HUlib_drawSText(hu_stext_t* s)
if (idx < 0)
idx += s->h; // handle queue of lines
// need a decision made here on whether to skip the draw
HUlib_drawTextLine(&s->l[idx], false); // no cursor, please
HUlib_drawTextLineAligned(&s->l[idx], align, false); // no cursor, please
}
}
@ -422,11 +503,9 @@ void HUlib_addMessageToMText(hu_mtext_t *m, char *prefix, char *msg)
HUlib_addLineToMText(m);
if (prefix)
while (*prefix)
HUlib_addCharToTextLine(&m->l[m->cl], *prefix++);
HUlib_addStringToTextLine(&m->l[m->cl], prefix);
while (*msg)
HUlib_addCharToTextLine(&m->l[m->cl], *msg++);
HUlib_addStringToTextLine(&m->l[m->cl], msg);
}
//
@ -439,7 +518,7 @@ void HUlib_addMessageToMText(hu_mtext_t *m, char *prefix, char *msg)
//
// killough 11/98: Simplified, allowed text to scroll in either direction
void HUlib_drawMText(hu_mtext_t* m)
void HUlib_drawMText(hu_mtext_t* m, align_t align)
{
int i;
@ -455,7 +534,7 @@ void HUlib_drawMText(hu_mtext_t* m)
m->l[idx].y = i * HU_REFRESHSPACING;
HUlib_drawTextLine(&m->l[idx], false); // no cursor, please
HUlib_drawTextLineAligned(&m->l[idx], align, false); // no cursor, please
}
}
@ -569,11 +648,11 @@ boolean HUlib_keyInIText(hu_itext_t *it, unsigned char ch)
// Returns nothing
//
void HUlib_drawIText(hu_itext_t *it)
void HUlib_drawIText(hu_itext_t *it, align_t align)
{
hu_textline_t *l = &it->l;
if (*it->on)
HUlib_drawTextLine(l, true); // draw the line w/ cursor
if ((l->width = *it->on))
HUlib_drawTextLineAligned(l, align, true); // draw the line w/ cursor
}
//

View File

@ -47,6 +47,15 @@
//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
//
@ -73,6 +82,8 @@ typedef struct
// whether this line needs to be udpated
int needsupdate;
int width;
} hu_textline_t;
@ -151,11 +162,15 @@ void HUlib_initTextLine
// returns success
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_resetAlignOffsets();
void HUlib_drawTextLineAligned(hu_textline_t *l, align_t align, boolean drawcursor);
// erases text line
void HUlib_eraseTextLine(hu_textline_t *l);
@ -182,7 +197,7 @@ void HUlib_addMessageToSText
char* msg );
// draws stext
void HUlib_drawSText(hu_stext_t* s);
void HUlib_drawSText(hu_stext_t* s, align_t align);
// erases all stext lines
void HUlib_eraseSText(hu_stext_t* s);
@ -208,7 +223,7 @@ void HUlib_addMessageToMText
//jff 2/26/98 message refresh widget
// draws mtext
void HUlib_drawMText(hu_mtext_t* m);
void HUlib_drawMText(hu_mtext_t* m, align_t align);
//jff 4/28/98 erases behind message list
void HUlib_eraseMText(hu_mtext_t* m);
@ -231,7 +246,7 @@ boolean HUlib_keyInIText
( hu_itext_t* it,
unsigned char ch );
void HUlib_drawIText(hu_itext_t* it);
void HUlib_drawIText(hu_itext_t* it, align_t align);
// erases all itext lines
void HUlib_eraseIText(hu_itext_t* it);

File diff suppressed because it is too large Load Diff

View File

@ -55,6 +55,7 @@ extern patch_t *hu_font[HU_FONTSIZE+6];
//
void HU_Init(void);
void HU_Start(void);
void HU_ResetWidgets (void);
boolean HU_Responder(event_t* ev);
@ -80,15 +81,14 @@ extern int hud_msg_lines; // number of message lines in window up to 16
extern int message_list; // killough 11/98: whether message list is active
extern int message_timer; // killough 11/98: timer used for normal messages
extern int chat_msg_timer; // killough 11/98: timer used for chat messages
extern int hud_distributed; // whether hud is all in lower left or distributed
//jff 2/23/98 hud is currently displayed
extern int hud_displayed; // hud is displayed
//jff 2/18/98 hud/status control
extern int hud_active; // hud mode 0=off, 1=small, 2=full
extern int hud_nosecrets; // status does not list secrets/items/kills
extern int hud_secret_message; // "A secret is revealed!" message
extern int map_player_coords, map_level_stats, map_level_time; // [FG] level stats and level time widgets
extern int hud_timests; // Time/STS above status bar
extern int hud_level_stats, hud_level_time;
extern int hud_widget_font;
extern boolean message_centered; // center messages
extern boolean message_colorized; // colorize player messages

View File

@ -73,7 +73,6 @@
extern boolean message_dontfuckwithme;
extern boolean chat_on; // in heads-up code
extern int HU_MoveHud(void); // jff 3/9/98 avoid glitch in HUD display
//
// defaulted values
@ -3275,6 +3274,7 @@ enum {
stat1_stub1,
stat1_title2,
stat1_stats,
stat1_time,
stat1_healthr,
stat1_healthy,
stat1_healthg,
@ -3297,7 +3297,8 @@ setup_menu_t stat_settings1[] = // Status Bar and HUD Settings screen
{"HEADS-UP DISPLAY" ,S_SKIP|S_TITLE,m_null,M_X,M_Y+stat1_title2*M_SPC},
{"HIDE LEVEL STATS" ,S_YESNO|S_COSMETIC,m_null,M_X,M_Y+stat1_stats*M_SPC, {"hud_nosecrets"}},
{"SHOW LEVEL STATS" ,S_YESNO|S_COSMETIC,m_null,M_X,M_Y+stat1_stats*M_SPC, {"hud_level_stats"}},
{"SHOW LEVEL TIME" ,S_YESNO|S_COSMETIC,m_null,M_X,M_Y+stat1_time*M_SPC, {"hud_level_time"}},
{"HEALTH LOW/OK" ,S_NUM|S_COSMETIC,m_null,M_X,M_Y+stat1_healthr*M_SPC, {"health_red"}},
{"HEALTH OK/GOOD" ,S_NUM|S_COSMETIC,m_null,M_X,M_Y+stat1_healthy*M_SPC, {"health_yellow"}},
{"HEALTH GOOD/EXTRA" ,S_NUM|S_COSMETIC,m_null,M_X,M_Y+stat1_healthg*M_SPC, {"health_green"}},
@ -3323,7 +3324,7 @@ enum {
stat2_stub1,
stat2_title2,
stat2_crispyhud,
stat2_timests,
stat2_hudfont,
stat2_stub2,
stat2_title3,
stat2_xhair,
@ -3344,10 +3345,6 @@ static void M_UpdateCrosshairItems (void)
stat_settings2[stat2_xhairtcolor]);
}
static const char *timests_str[] = {
"OFF", "TIME", "STATS", "BOTH", NULL
};
static const char *crosshair_target_str[] = {
"OFF", "HIGHLIGHT", "HEALTH", NULL
};
@ -3369,7 +3366,7 @@ setup_menu_t stat_settings2[] =
{"EXTENDED HUD",S_SKIP|S_TITLE,m_null,M_X,M_Y+stat2_title2*M_SPC },
{"PREFER CRISPY HUD OVER BOOM HUD" ,S_YESNO ,m_null,M_X,M_Y+stat2_crispyhud*M_SPC, {"crispy_hud"}},
{"SHOW TIME/STATS ABOVE STATUS BAR" ,S_CHOICE,m_null,M_X,M_Y+stat2_timests*M_SPC, {"hud_timests"}, 0, NULL, timests_str},
{"DRAW HUD WIDGETS WITH SMALL FONT" ,S_YESNO,m_null,M_X,M_Y+stat2_hudfont*M_SPC, {"hud_widget_font"}},
{"",S_SKIP,m_null,M_X,M_Y+stat2_stub2*M_SPC},
@ -3489,8 +3486,8 @@ setup_menu_t auto_settings1[] = // 1st AutoMap Settings screen
// [FG] show level statistics and level time widgets
{"Show player coords" ,S_CHOICE,m_null,M_X,M_Y+auto1_coords*M_SPC, {"map_player_coords"},0,NULL,show_widgets_strings},
{"Coords follow pointer",S_YESNO ,m_null,M_X,M_Y+auto1_pointer*M_SPC, {"map_point_coord"}}, // killough 10/98
{"Show level stats" ,S_CHOICE,m_null,M_X,M_Y+auto1_stats*M_SPC, {"map_level_stats"},0,NULL,show_widgets_strings},
{"Show level time" ,S_CHOICE,m_null,M_X,M_Y+auto1_time*M_SPC, {"map_level_time"},0,NULL,show_widgets_strings},
{"Show level stats" ,S_YESNO ,m_null,M_X,M_Y+auto1_stats*M_SPC, {"map_level_stats"}},
{"Show level time" ,S_YESNO ,m_null,M_X,M_Y+auto1_time*M_SPC, {"map_level_time"}},
{"",S_SKIP,m_null,M_X,M_Y+auto1_stub2*M_SPC},
@ -5550,12 +5547,8 @@ boolean M_Responder (event_t* ev)
else
{
hud_displayed = 1; //jff 3/3/98 turn hud on
hud_active = crispy_hud ? !hud_active : (hud_active+1)%3; // cycle hud_active
if (!hud_active) //jff 3/4/98 add distributed
{
hud_distributed = !hud_distributed; // to cycle
HU_MoveHud(); //jff 3/9/98 move it now to avoid glitch
}
hud_active = (hud_active + 1) % 3; // cycle hud_active
HU_ResetWidgets();
}
return true;
}

View File

@ -1901,13 +1901,6 @@ default_t defaults[] = {
"Duration of normal Doom messages (ms)"
},
{ // hud broken up into 3 displays //jff 3/4/98
"hud_distributed",
(config_t *) &hud_distributed, NULL,
{0}, {0,1}, number, ss_none, wad_yes,
"1 splits HUD into three 2 line displays"
},
{ // below is red
"health_red",
(config_t *) &health_red, NULL,
@ -1979,10 +1972,17 @@ default_t defaults[] = {
},
{ // no secrets/items/kills HUD line
"hud_nosecrets",
(config_t *) &hud_nosecrets, NULL,
{1}, {0,1}, number, ss_stat, wad_yes,
"1 to disable display of kills/items/secrets on HUD"
"hud_level_stats",
(config_t *) &hud_level_stats, NULL,
{0}, {0,1}, number, ss_stat, wad_yes,
"1 to show kills/items/secrets on HUD"
},
{ // no secrets/items/kills HUD line
"hud_level_time",
(config_t *) &hud_level_time, NULL,
{0}, {0,1}, number, ss_stat, wad_yes,
"1 to show level time on HUD"
},
// prefer Crispy HUD over Boom HUD
@ -2017,12 +2017,11 @@ default_t defaults[] = {
"\"A secret is revealed!\" message"
},
// Time/STS above status bar
{
"hud_timests",
(config_t *) &hud_timests, NULL,
{0}, {0,3}, number, ss_stat, wad_no,
"0 for off, 1 for time, 2 for stats, 3 for both"
"hud_widget_font",
(config_t *) &hud_widget_font, NULL,
{1}, {0,1}, number, ss_stat, wad_no,
"1 to draw HUD widgets in small font"
},
{

View File

@ -35,7 +35,7 @@
#include "i_video.h"
#include "w_wad.h"
#include "st_stuff.h"
#include "hu_stuff.h" // [FG] hud_displayed, hud_distributed
#include "hu_stuff.h" // [FG] hud_displayed
#include "st_lib.h"
#include "r_main.h"
#include "am_map.h"
@ -1320,7 +1320,7 @@ static void ST_MoveHud (void)
{
static int odelta = 0;
if (st_crispyhud && hud_distributed)
if (st_crispyhud && hud_active == 2)
distributed_delta = WIDESCREENDELTA;
else
distributed_delta = 0;