From 9442a463d46284bc85cfac927bc1b7dc1ef6d832 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy <86008856+GenericHeroGuy@users.noreply.github.com> Date: Mon, 1 Apr 2024 21:43:50 +0200 Subject: [PATCH 01/12] Shrink drawlists, take 2 Approximately 2/3rds smaller --- src/lua_hudlib_drawlist.c | 45 ++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/lua_hudlib_drawlist.c b/src/lua_hudlib_drawlist.c index de1f234c3..7ec5398e4 100644 --- a/src/lua_hudlib_drawlist.c +++ b/src/lua_hudlib_drawlist.c @@ -37,27 +37,32 @@ typedef struct drawitem_s { enum drawitem_e type; fixed_t x; fixed_t y; - fixed_t w; - fixed_t h; - INT32 c; - fixed_t scale; - fixed_t hscale; - fixed_t vscale; - patch_t *patch; - INT32 flags; - UINT16 basecolor; - UINT16 outlinecolor; + union { + INT32 flags; + INT32 c; + }; + + union { + fixed_t scale; // drawScaled + fixed_t hscale; // drawStretched + fixed_t w; // drawFill + INT32 align; // drawString + INT32 num; // drawNum, drawPaddedNum, drawPingNum + UINT16 color; // fadeScreen + }; + union { + fixed_t vscale; // drawStretched + fixed_t h; // drawFill + INT32 digits; // drawPaddedNum + UINT8 strength; // fadeScreen + }; + + // pointers (and size_t's) last, for potentially better packing + union { + patch_t *patch; + size_t stroffset; // offset into strbuf to get str + }; const UINT8 *colormap; - UINT8 *basecolormap; - UINT8 *outlinecolormap; - fixed_t sx; - fixed_t sy; - INT32 num; - INT32 digits; - size_t stroffset; // offset into strbuf to get str - UINT16 color; - UINT8 strength; - INT32 align; } drawitem_t; // The internal structure of a drawlist. -- 2.54.0 From 5f69bfcf222535b73bae57a7d0c8a702f1298566 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy <86008856+GenericHeroGuy@users.noreply.github.com> Date: Tue, 2 Apr 2024 03:22:24 +0200 Subject: [PATCH 02/12] Split game drawlist per displayplayer --- src/lua_hud.h | 2 +- src/lua_hudlib.c | 29 +++++------------------------ src/st_stuff.c | 13 ++++++++----- 3 files changed, 14 insertions(+), 30 deletions(-) diff --git a/src/lua_hud.h b/src/lua_hud.h index d0fec7f1e..ce9f6e7a8 100644 --- a/src/lua_hud.h +++ b/src/lua_hud.h @@ -44,7 +44,7 @@ extern boolean hud_running; boolean LUA_HudEnabled(enum hud option); -void LUAh_GameHUD(player_t *stplyr, huddrawlist_h list); +void LUAh_GameHUD(huddrawlist_h list); void LUAh_ScoresHUD(huddrawlist_h list); void LUAh_IntermissionHUD(huddrawlist_h list); void LUAh_VoteHUD(huddrawlist_h list); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 2f81d98bf..3ec03537b 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -1413,7 +1413,7 @@ boolean LUA_HudEnabled(enum hud option) } // Hook for HUD rendering -void LUAh_GameHUD(player_t *stplayr, huddrawlist_h list) +void LUAh_GameHUD(huddrawlist_h list) { if (!gL || !(hudAvailable & (1< 2 && stplayr == &players[displayplayers[3]]) - { - LUA_PushUserdata(gL, &camera[3], META_CAMERA); - camnum = 4; - } - else if (splitscreen > 1 && stplayr == &players[displayplayers[2]]) - { - LUA_PushUserdata(gL, &camera[2], META_CAMERA); - camnum = 3; - } - else if (splitscreen && stplayr == &players[displayplayers[1]]) - { - LUA_PushUserdata(gL, &camera[1], META_CAMERA); - camnum = 2; - } - else - { - LUA_PushUserdata(gL, &camera[0], META_CAMERA); - camnum = 1; - } + LUA_PushUserdata(gL, stplyr, META_PLAYER); + LUA_PushUserdata(gL, &camera[stplyrnum], META_CAMERA); + camnum = stplyrnum + 1; lua_pushnil(gL); while (lua_next(gL, -5) != 0) { lua_pushvalue(gL, -5); // graphics library (HUD[1]) - lua_pushvalue(gL, -5); // stplayr + lua_pushvalue(gL, -5); // stplyr lua_pushvalue(gL, -5); // camera LUA_Call(gL, 3, 0, 1); } diff --git a/src/st_stuff.c b/src/st_stuff.c index 2ecfd73d5..3e64e6626 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -193,7 +193,7 @@ hudinfo_t hudinfo[NUMHUDITEMS] = { 240, 160}, // HUD_LAP }; -static huddrawlist_h luahuddrawlist_game; +static huddrawlist_h luahuddrawlist_game[MAXSPLITSCREENPLAYERS]; // variable to stop mayonaka static from flickering consvar_t cv_lessflicker = {"lessflicker", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -473,7 +473,8 @@ void ST_Init(void) ST_LoadGraphics(); - luahuddrawlist_game = LUA_HUD_CreateDrawList(); + for (int i = 0; i < MAXSPLITSCREENPLAYERS; i++) + luahuddrawlist_game[i] = LUA_HUD_CreateDrawList(); } // change the status bar too, when pressing F12 while viewing a demo. @@ -846,7 +847,7 @@ static void ST_overlayDrawer(void) { if (renderisnewtic) { - LUAh_GameHUD(stplyr, luahuddrawlist_game); + LUAh_GameHUD(luahuddrawlist_game[stplyrnum]); } } @@ -1024,7 +1025,8 @@ void ST_Drawer(void) { if (renderisnewtic) { - LUA_HUD_ClearDrawList(luahuddrawlist_game); + for (i = 0; i <= splitscreen; i++) + LUA_HUD_ClearDrawList(luahuddrawlist_game[i]); } // No deadview! @@ -1035,7 +1037,8 @@ void ST_Drawer(void) ST_overlayDrawer(); } - LUA_HUD_DrawList(luahuddrawlist_game); + for (i = 0; i <= splitscreen; i++) + LUA_HUD_DrawList(luahuddrawlist_game[i]); // draw Midnight Channel's overlay ontop if (mapheaderinfo[gamemap-1]->typeoflevel & TOL_TV) // Very specific Midnight Channel stuff. -- 2.54.0 From b2f9a29eb0bca107ad4bbe7ce65832d48bcb57f3 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy <86008856+GenericHeroGuy@users.noreply.github.com> Date: Tue, 2 Apr 2024 21:00:23 +0200 Subject: [PATCH 03/12] Lua HUD interpolation --- src/lua_hud.h | 3 + src/lua_hudlib.c | 31 +++++++++ src/lua_hudlib_drawlist.c | 142 +++++++++++++++++++++++++++++--------- 3 files changed, 144 insertions(+), 32 deletions(-) diff --git a/src/lua_hud.h b/src/lua_hud.h index ce9f6e7a8..8601192b6 100644 --- a/src/lua_hud.h +++ b/src/lua_hud.h @@ -41,6 +41,9 @@ enum hud { }; extern boolean hud_running; +extern UINT8 hud_interptag; +extern UINT32 hud_interpcounter; +extern boolean hud_interpstring; boolean LUA_HudEnabled(enum hud option); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 3ec03537b..62aa30c37 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -32,6 +32,9 @@ #define HUDONLY if (!hud_running) return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); boolean hud_running = false; +UINT8 hud_interptag = 0; +UINT32 hud_interpcounter = 0; +boolean hud_interpstring = false; static UINT8 hud_enabled[(hud_MAX/8)+1]; static UINT8 hudAvailable; // hud hooks field @@ -1178,6 +1181,20 @@ static int libd_getDrawInfo(lua_State *L) return 3; } +static int libd_interpolate(lua_State *L) +{ + HUDONLY + hud_interptag = luaL_checkinteger(L, 1); + return 0; +} + +static int libd_interpString(lua_State *L) +{ + HUDONLY + hud_interpstring = luaL_checkboolean(L, 1); + return 0; +} + static luaL_Reg lib_draw[] = { {"patchExists", libd_patchExists}, {"cachePatch", libd_cachePatch}, @@ -1205,6 +1222,8 @@ static luaL_Reg lib_draw[] = { {"getDrawInfo", libd_getDrawInfo}, {"getHudColor", libd_getHudColor}, {"useColorHud", libd_useColorHud}, + {"interpolate", libd_interpolate}, + {"interpString", libd_interpString}, {NULL, NULL} }; @@ -1438,8 +1457,11 @@ void LUAh_GameHUD(huddrawlist_h list) LUA_PushUserdata(gL, &camera[stplyrnum], META_CAMERA); camnum = stplyrnum + 1; + hud_interpcounter = 0; lua_pushnil(gL); while (lua_next(gL, -5) != 0) { + hud_interptag = 0; + hud_interpcounter++; lua_pushvalue(gL, -5); // graphics library (HUD[1]) lua_pushvalue(gL, -5); // stplyr lua_pushvalue(gL, -5); // camera @@ -1474,7 +1496,10 @@ void LUAh_ScoresHUD(huddrawlist_h list) I_Assert(lua_istable(gL, -1)); lua_remove(gL, -3); // pop HUD lua_pushnil(gL); + hud_interpcounter = 0; while (lua_next(gL, -3) != 0) { + hud_interptag = 0; + hud_interpcounter++; lua_pushvalue(gL, -3); // graphics library (HUD[1]) LUA_Call(gL, 1, 0, 1); } @@ -1507,7 +1532,10 @@ void LUAh_IntermissionHUD(huddrawlist_h list) I_Assert(lua_istable(gL, -1)); lua_remove(gL, -3); // pop HUD lua_pushnil(gL); + hud_interpcounter = 0; while (lua_next(gL, -3) != 0) { + hud_interptag = 0; + hud_interpcounter++; lua_pushvalue(gL, -3); // graphics library (HUD[1]) LUA_Call(gL, 1, 0, 1); } @@ -1540,7 +1568,10 @@ void LUAh_VoteHUD(huddrawlist_h list) I_Assert(lua_istable(gL, -1)); lua_remove(gL, -3); // pop HUD lua_pushnil(gL); + hud_interpcounter = 0; while (lua_next(gL, -3) != 0) { + hud_interptag = 0; + hud_interpcounter++; lua_pushvalue(gL, -3); // graphics library (HUD[1]) LUA_Call(gL, 1, 0, 1); } diff --git a/src/lua_hudlib_drawlist.c b/src/lua_hudlib_drawlist.c index 7ec5398e4..14a24d90e 100644 --- a/src/lua_hudlib_drawlist.c +++ b/src/lua_hudlib_drawlist.c @@ -11,11 +11,16 @@ /// \brief a data structure for managing cached drawlists for the Lua hud lib #include "lua_hudlib_drawlist.h" +#include "lua_hud.h" +#include "blua/lstate.h" // shhhhhh +#include "lua_libs.h" #include #include "v_video.h" #include "z_zone.h" +#include "r_main.h" +#include "r_fps.h" enum drawitem_e { DI_Draw = 0, @@ -34,6 +39,7 @@ enum drawitem_e { // A single draw item with all possible arguments needed for a draw call. typedef struct drawitem_s { + UINT64 id; enum drawitem_e type; fixed_t x; fixed_t y; @@ -68,8 +74,10 @@ typedef struct drawitem_s { // The internal structure of a drawlist. struct huddrawlist_s { drawitem_t *items; - size_t items_capacity; size_t items_len; + drawitem_t *olditems; + size_t olditems_len; + size_t capacity; char *strbuf; size_t strbuf_capacity; size_t strbuf_len; @@ -93,8 +101,10 @@ huddrawlist_h LUA_HUD_CreateDrawList(void) drawlist = (huddrawlist_h) Z_Calloc(sizeof(struct huddrawlist_s), PU_STATIC, NULL); drawlist->items = NULL; - drawlist->items_capacity = 0; drawlist->items_len = 0; + drawlist->olditems = NULL; + drawlist->olditems_len = 0; + drawlist->capacity = 0; drawlist->strbuf = NULL; drawlist->strbuf_capacity = 0; drawlist->strbuf_len = 0; @@ -104,15 +114,14 @@ huddrawlist_h LUA_HUD_CreateDrawList(void) void LUA_HUD_ClearDrawList(huddrawlist_h list) { + // swap the old and new lists + void *tmp = list->olditems; + list->olditems = list->items; + list->items = tmp; + // rather than deallocate, we'll just save the existing allocation and empty // it out for reuse - - // this memset probably isn't necessary - if (list->items) - { - memset(list->items, 0, sizeof(drawitem_t) * list->items_capacity); - } - + list->olditems_len = list->items_len; list->items_len = 0; if (list->strbuf) @@ -130,6 +139,10 @@ void LUA_HUD_DestroyDrawList(huddrawlist_h list) { Z_Free(list->items); } + if (list->olditems) + { + Z_Free(list->olditems); + } if (list->strbuf) { Z_Free(list->strbuf); @@ -148,11 +161,11 @@ boolean LUA_HUD_IsDrawListValid(huddrawlist_h list) static size_t AllocateDrawItem(huddrawlist_h list) { if (!list) I_Error("can't allocate draw item: invalid list"); - if (list->items_capacity <= list->items_len + 1) + if (list->capacity <= list->items_len) { - if (list->items_capacity == 0) list->items_capacity = 128; - else list->items_capacity *= 2; - list->items = (drawitem_t *) Z_Realloc(list->items, sizeof(struct drawitem_s) * list->items_capacity, PU_STATIC, NULL); + list->capacity = list->capacity == 0 ? 128 : list->capacity * 2; + list->items = Z_Realloc(list->items, sizeof(struct drawitem_s) * list->capacity, PU_STATIC, NULL); + list->olditems = Z_Realloc(list->olditems, sizeof(struct drawitem_s) * list->capacity, PU_STATIC, NULL); } return list->items_len++; @@ -183,6 +196,14 @@ static size_t CopyString(huddrawlist_h list, const char* str) } } +// leave bit 0 free for the string mode +#define INTERP_LATCH 1 + +#define GETITEMID \ + item->id = hud_interptag \ + ? (((UINT64)gL->savedpc << 32) | (hud_interpcounter << 9) | (hud_interptag << 1) | (hud_interpstring ? INTERP_LATCH : 0)) \ + : 0; + void LUA_HUD_AddDraw( huddrawlist_h list, INT32 x, @@ -194,9 +215,10 @@ void LUA_HUD_AddDraw( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + GETITEMID item->type = DI_Draw; - item->x = x; - item->y = y; + item->x = x << FRACBITS; + item->y = y << FRACBITS; item->patch = patch; item->flags = flags; item->colormap = colormap; @@ -214,6 +236,7 @@ void LUA_HUD_AddDrawScaled( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + GETITEMID item->type = DI_DrawScaled; item->x = x; item->y = y; @@ -236,6 +259,7 @@ void LUA_HUD_AddDrawStretched( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + GETITEMID item->type = DI_DrawStretched; item->x = x; item->y = y; @@ -256,6 +280,7 @@ void LUA_HUD_AddDrawNum( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + GETITEMID item->type = DI_DrawNum; item->x = x; item->y = y; @@ -274,6 +299,7 @@ void LUA_HUD_AddDrawPaddedNum( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + GETITEMID item->type = DI_DrawPaddedNum; item->x = x; item->y = y; @@ -293,6 +319,7 @@ void LUA_HUD_AddDrawPingNum( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + GETITEMID item->type = DI_DrawPingNum; item->x = x; item->y = y; @@ -312,6 +339,7 @@ void LUA_HUD_AddDrawFill( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + GETITEMID item->type = DI_DrawFill; item->x = x; item->y = y; @@ -331,6 +359,7 @@ void LUA_HUD_AddDrawString( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + GETITEMID item->type = DI_DrawString; item->x = x; item->y = y; @@ -349,6 +378,7 @@ void LUA_HUD_AddDrawKartString( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + GETITEMID item->type = DI_DrawKartString; item->x = x; item->y = y; @@ -366,6 +396,7 @@ void LUA_HUD_AddDrawLevelTitle( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + GETITEMID item->type = DI_DrawLevelTitle; item->x = x; item->y = y; @@ -389,6 +420,11 @@ void LUA_HUD_AddFadeScreen( void LUA_HUD_DrawList(huddrawlist_h list) { size_t i; + size_t j = 0; + fixed_t frac = R_UsingFrameInterpolation() ? rendertimefrac : FRACUNIT; + fixed_t lerpx = 0, lerpy = 0; + drawitem_t *latchitem = NULL; + drawitem_t *oldlatchitem = NULL; if (!list) I_Error("HUD drawlist invalid"); if (list->items_len <= 0) return; @@ -397,68 +433,110 @@ void LUA_HUD_DrawList(huddrawlist_h list) for (i = 0; i < list->items_len; i++) { drawitem_t *item = &list->items[i]; + drawitem_t *olditem = NULL; const char *itemstr = &list->strbuf[item->stroffset]; + if (item->id) { + // find the old one too + // this is kinda cursed... we need to check every item + // but stop when the first-checked item is reached again + size_t stop = j; + while(true) + { + if (j == list->olditems_len) + { + // wrap around + j = 0; + if (j == stop) // i'm dumb + break; + } + drawitem_t *old = &list->olditems[j++]; + if (old->id == item->id) + { + // gotcha! + olditem = old; + if (item->id & INTERP_LATCH) { + if (!latchitem) { + lerpx = FixedMul(frac, item->x - olditem->x); + lerpy = FixedMul(frac, item->y - olditem->y); + latchitem = item; + oldlatchitem = olditem; + } + } else { + lerpx = FixedMul(frac, item->x - olditem->x); + lerpy = FixedMul(frac, item->y - olditem->y); + latchitem = NULL; + } + break; + } + if (j == stop) + break; + } + } + + #define LERP(it) (olditem ? olditem->it + FixedMul(frac, item->it - olditem->it) : item->it) + #define LERPS(it) (olditem ? (latchitem ? (latchitem->it + (item->it - latchitem->it)) - (latchitem->it - oldlatchitem->it) : olditem->it) + lerp##it : item->it) + switch (item->type) { case DI_Draw: - V_DrawFixedPatch(item->x<y<flags, item->patch, item->colormap); + V_DrawFixedPatch(LERPS(x), LERPS(y), FRACUNIT, item->flags, item->patch, item->colormap); break; case DI_DrawScaled: - V_DrawFixedPatch(item->x, item->y, item->scale, item->flags, item->patch, item->colormap); + V_DrawFixedPatch(LERPS(x), LERPS(y), LERP(scale), item->flags, item->patch, item->colormap); break; case DI_DrawStretched: - V_DrawStretchyFixedPatch(item->x, item->y, item->hscale, item->vscale, item->flags, item->patch, item->colormap); + V_DrawStretchyFixedPatch(LERPS(x), LERPS(y), LERP(hscale), LERP(vscale), item->flags, item->patch, item->colormap); break; case DI_DrawNum: - V_DrawTallNum(item->x, item->y, item->flags, item->num); + V_DrawTallNum(LERPS(x), LERPS(y), item->flags, item->num); break; case DI_DrawPaddedNum: - V_DrawPaddedTallNum(item->x, item->y, item->flags, item->num, item->digits); + V_DrawPaddedTallNum(LERPS(x), LERPS(y), item->flags, item->num, item->digits); break; case DI_DrawPingNum: - V_DrawPingNum(item->x, item->y, item->flags, item->num, item->colormap); + V_DrawPingNum(LERPS(x), LERPS(y), item->flags, item->num, item->colormap); break; case DI_DrawFill: - V_DrawFill(item->x, item->y, item->w, item->h, item->c); + V_DrawFill(LERPS(x), LERPS(y), item->w, item->h, item->c); break; case DI_DrawString: switch(item->align) { // hu_font case align_left: - V_DrawString(item->x, item->y, item->flags, itemstr); + V_DrawString(LERPS(x), LERPS(y), item->flags, itemstr); break; case align_center: - V_DrawCenteredString(item->x, item->y, item->flags, itemstr); + V_DrawCenteredString(LERPS(x), LERPS(y), item->flags, itemstr); break; case align_right: - V_DrawRightAlignedString(item->x, item->y, item->flags, itemstr); + V_DrawRightAlignedString(LERPS(x), LERPS(y), item->flags, itemstr); break; case align_fixed: - V_DrawStringAtFixed(item->x, item->y, item->flags, itemstr); + V_DrawStringAtFixed(LERPS(x), LERPS(y), item->flags, itemstr); break; // hu_font, 0.5x scale case align_small: - V_DrawSmallString(item->x, item->y, item->flags, itemstr); + V_DrawSmallString(LERPS(x), LERPS(y), item->flags, itemstr); break; case align_smallright: - V_DrawRightAlignedSmallString(item->x, item->y, item->flags, itemstr); + V_DrawRightAlignedSmallString(LERPS(x), LERPS(y), item->flags, itemstr); break; // tny_font case align_thin: - V_DrawThinString(item->x, item->y, item->flags, itemstr); + V_DrawThinString(LERPS(x), LERPS(y), item->flags, itemstr); break; case align_thinright: - V_DrawRightAlignedThinString(item->x, item->y, item->flags, itemstr); + V_DrawRightAlignedThinString(LERPS(x), LERPS(y), item->flags, itemstr); break; } break; case DI_DrawKartString: - V_DrawKartString(item->x, item->y, item->flags, itemstr); + V_DrawKartString(LERPS(x), LERPS(y), item->flags, itemstr); break; case DI_DrawLevelTitle: - V_DrawLevelTitle(item->x, item->y, item->flags, itemstr); + V_DrawLevelTitle(LERPS(x), LERPS(y), item->flags, itemstr); break; case DI_FadeScreen: V_DrawFadeScreen(item->color, item->strength); -- 2.54.0 From aeb5ae994ecd92cfea78da5c423af52cc76db854 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy <86008856+GenericHeroGuy@users.noreply.github.com> Date: Wed, 3 Apr 2024 01:37:24 +0200 Subject: [PATCH 04/12] Subpixel interpolation for strings and drawfill --- src/lua_hudlib_drawlist.c | 119 +++++++++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 2 deletions(-) diff --git a/src/lua_hudlib_drawlist.c b/src/lua_hudlib_drawlist.c index 14a24d90e..8aaaa67ff 100644 --- a/src/lua_hudlib_drawlist.c +++ b/src/lua_hudlib_drawlist.c @@ -196,6 +196,116 @@ static size_t CopyString(huddrawlist_h list, const char* str) } } +static void CalcCoords(huddrawlist_h list, drawitem_t *item) +{ + if (!(item->flags & V_NOSCALESTART) && cv_uncappedhud.value) + { + INT32 dupx = vid.dupx; + INT32 dupy = vid.dupy; + + item->flags |= V_NOSCALESTART; + + if (item->flags & V_SCALEPATCHMASK) switch ((item->flags & V_SCALEPATCHMASK) >> V_SCALEPATCHSHIFT) + { + case 1: // V_NOSCALEPATCH + dupx = dupy = 1; + break; + case 2: // V_SMALLSCALEPATCH + dupx = vid.smalldupx; + dupy = vid.smalldupy; + break; + case 3: // V_MEDSCALEPATCH + dupx = vid.meddupx; + dupy = vid.meddupy; + break; + default: + break; + } + + // only use one dup, to avoid stretching (har har) + dupx = dupy = (dupx < dupy ? dupx : dupy); + + INT32 x = item->x * dupx; + INT32 y = item->y * dupy; + + if (vid.width != BASEVIDWIDTH * dupx) + { + // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, + // so center this imaginary screen + if ((item->flags & (V_HORZSCREEN|V_SNAPTOLEFT)) == (V_HORZSCREEN|V_SNAPTOLEFT)) + x += (vid.width/2 - (BASEVIDWIDTH/2 * dupx)); + else if (item->flags & V_SNAPTORIGHT) + x += (vid.width - (BASEVIDWIDTH * dupx)); + else if (!(item->flags & V_SNAPTOLEFT)) + x += (vid.width - (BASEVIDWIDTH * dupx)) / 2; + } + if (vid.height != BASEVIDHEIGHT * dupy) + { + // same thing here + if ((item->flags & (V_SPLITSCREEN|V_SNAPTOTOP)) == (V_SPLITSCREEN|V_SNAPTOTOP)) + y += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy)); + else if (item->flags & V_SNAPTOBOTTOM) + y += (vid.height - (BASEVIDHEIGHT * dupy)); + else if (!(item->flags & V_SNAPTOTOP)) + y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; + } + + // need to compensate for dup here + + if (item->align == align_center) + x -= (V_StringWidth(&list->strbuf[item->stroffset], item->flags) * (dupx - 1))/2; + if (item->align == align_right) + x -= V_StringWidth(&list->strbuf[item->stroffset], item->flags) * (dupx - 1); + if (item->align == align_thinright) + x -= V_ThinStringWidth(&list->strbuf[item->stroffset], item->flags) * (dupx - 1); + + item->x = x; + item->y = y; + } +} + +static void CalcFillCoords(drawitem_t *item) +{ + if (!(item->flags & V_NOSCALESTART) && cv_uncappedhud.value) + { + INT32 dupx = vid.dupx; + INT32 dupy = vid.dupy; + INT32 x = item->x * dupx; + INT32 y = item->y * dupy; + INT32 c = item->c; + + item->flags |= V_NOSCALESTART; + item->w *= dupx; + item->h *= dupy; + + // Center it if necessary + if (vid.width != BASEVIDWIDTH * dupx) + { + // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, + // so center this imaginary screen + if (c & V_SNAPTORIGHT) + x += (vid.width - (BASEVIDWIDTH * dupx)); + else if (!(c & V_SNAPTOLEFT)) + x += (vid.width - (BASEVIDWIDTH * dupx)) / 2; + } + if (vid.height != BASEVIDHEIGHT * dupy) + { + // same thing here + if (c & V_SNAPTOBOTTOM) + y += (vid.height - (BASEVIDHEIGHT * dupy)); + else if (!(c & V_SNAPTOTOP)) + y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; + } + if (c & V_SPLITSCREEN) + y += (BASEVIDHEIGHT * dupy)/2; + if (c & V_HORZSCREEN) + x += (BASEVIDWIDTH * dupx)/2; + + item->x = x; + item->y = y; + } +} + // leave bit 0 free for the string mode #define INTERP_LATCH 1 @@ -346,6 +456,7 @@ void LUA_HUD_AddDrawFill( item->w = w; item->h = h; item->c = c; + CalcFillCoords(item); } void LUA_HUD_AddDrawString( @@ -366,6 +477,7 @@ void LUA_HUD_AddDrawString( item->stroffset = CopyString(list, str); item->flags = flags; item->align = align; + CalcCoords(list, item); } void LUA_HUD_AddDrawKartString( @@ -436,7 +548,7 @@ void LUA_HUD_DrawList(huddrawlist_h list) drawitem_t *olditem = NULL; const char *itemstr = &list->strbuf[item->stroffset]; - if (item->id) { + if (item->id && cv_uncappedhud.value) { // find the old one too // this is kinda cursed... we need to check every item // but stop when the first-checked item is reached again @@ -475,7 +587,10 @@ void LUA_HUD_DrawList(huddrawlist_h list) } #define LERP(it) (olditem ? olditem->it + FixedMul(frac, item->it - olditem->it) : item->it) - #define LERPS(it) (olditem ? (latchitem ? (latchitem->it + (item->it - latchitem->it)) - (latchitem->it - oldlatchitem->it) : olditem->it) + lerp##it : item->it) + + // half of this could be done when the coordinates are latched... zzzzzz + #define LERPS(it) (latchitem ? ((latchitem->it + (item->it - latchitem->it)) - (latchitem->it - oldlatchitem->it)) + lerp##it : (olditem ? olditem->it + lerp##it : item->it)) + //define LERPS(it) (olditem ? (latchitem ? (latchitem->it + (item->it - latchitem->it)) - (latchitem->it - oldlatchitem->it) : olditem->it) + lerp##it : item->it) switch (item->type) { -- 2.54.0 From 18e0485f399b928ac970814f365c4ebacbf64232 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy <86008856+GenericHeroGuy@users.noreply.github.com> Date: Thu, 4 Apr 2024 23:21:41 +0200 Subject: [PATCH 05/12] Make this less insufferable * Zero is now a valid tag for v.interpolate * Reset lerp coordinates when v.interpString is called again * Leaving string mode enabled on exit no longer breaks other scripts * Fix fadeScreen having an uninitialized ID --- src/lua_hud.h | 3 ++ src/lua_hudlib.c | 36 ++++++++++++++++++---- src/lua_hudlib_drawlist.c | 63 +++++++++++++++++++++++++-------------- 3 files changed, 73 insertions(+), 29 deletions(-) diff --git a/src/lua_hud.h b/src/lua_hud.h index 8601192b6..ccaed738d 100644 --- a/src/lua_hud.h +++ b/src/lua_hud.h @@ -41,9 +41,12 @@ enum hud { }; extern boolean hud_running; + +extern boolean hud_interpolate; extern UINT8 hud_interptag; extern UINT32 hud_interpcounter; extern boolean hud_interpstring; +extern boolean hud_interplatch; boolean LUA_HudEnabled(enum hud option); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 62aa30c37..bceb9ebc4 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -32,9 +32,12 @@ #define HUDONLY if (!hud_running) return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); boolean hud_running = false; + +boolean hud_interpolate = false; UINT8 hud_interptag = 0; UINT32 hud_interpcounter = 0; boolean hud_interpstring = false; +boolean hud_interplatch = false; static UINT8 hud_enabled[(hud_MAX/8)+1]; static UINT8 hudAvailable; // hud hooks field @@ -1184,14 +1187,35 @@ static int libd_getDrawInfo(lua_State *L) static int libd_interpolate(lua_State *L) { HUDONLY - hud_interptag = luaL_checkinteger(L, 1); + + // do type checking even if interpolation is disabled + boolean newinterpolate; + UINT8 newtag; + + if (lua_isnumber(L, 1)) + { + newinterpolate = true; + newtag = luaL_checkinteger(L, 1); + } + else + { + newinterpolate = luaL_checkboolean(L, 1); + newtag = 0; + } + + if (!cv_uncappedhud.value) + return 0; + + hud_interpolate = newinterpolate; + hud_interptag = newtag; + return 0; } static int libd_interpString(lua_State *L) { HUDONLY - hud_interpstring = luaL_checkboolean(L, 1); + hud_interpstring = hud_interplatch = luaL_checkboolean(L, 1); return 0; } @@ -1460,7 +1484,7 @@ void LUAh_GameHUD(huddrawlist_h list) hud_interpcounter = 0; lua_pushnil(gL); while (lua_next(gL, -5) != 0) { - hud_interptag = 0; + hud_interpolate = hud_interpstring = hud_interplatch = false; hud_interpcounter++; lua_pushvalue(gL, -5); // graphics library (HUD[1]) lua_pushvalue(gL, -5); // stplyr @@ -1498,7 +1522,7 @@ void LUAh_ScoresHUD(huddrawlist_h list) lua_pushnil(gL); hud_interpcounter = 0; while (lua_next(gL, -3) != 0) { - hud_interptag = 0; + hud_interpolate = hud_interpstring = hud_interplatch = false; hud_interpcounter++; lua_pushvalue(gL, -3); // graphics library (HUD[1]) LUA_Call(gL, 1, 0, 1); @@ -1534,7 +1558,7 @@ void LUAh_IntermissionHUD(huddrawlist_h list) lua_pushnil(gL); hud_interpcounter = 0; while (lua_next(gL, -3) != 0) { - hud_interptag = 0; + hud_interpolate = hud_interpstring = hud_interplatch = false; hud_interpcounter++; lua_pushvalue(gL, -3); // graphics library (HUD[1]) LUA_Call(gL, 1, 0, 1); @@ -1570,7 +1594,7 @@ void LUAh_VoteHUD(huddrawlist_h list) lua_pushnil(gL); hud_interpcounter = 0; while (lua_next(gL, -3) != 0) { - hud_interptag = 0; + hud_interpolate = hud_interpstring = hud_interplatch = false; hud_interpcounter++; lua_pushvalue(gL, -3); // graphics library (HUD[1]) LUA_Call(gL, 1, 0, 1); diff --git a/src/lua_hudlib_drawlist.c b/src/lua_hudlib_drawlist.c index 8aaaa67ff..65e6cef42 100644 --- a/src/lua_hudlib_drawlist.c +++ b/src/lua_hudlib_drawlist.c @@ -306,13 +306,27 @@ static void CalcFillCoords(drawitem_t *item) } } -// leave bit 0 free for the string mode #define INTERP_LATCH 1 +#define INTERP_STRING 2 -#define GETITEMID \ - item->id = hud_interptag \ - ? (((UINT64)gL->savedpc << 32) | (hud_interpcounter << 9) | (hud_interptag << 1) | (hud_interpstring ? INTERP_LATCH : 0)) \ - : 0; +static UINT64 GetItemId(void) +{ + if (!hud_interpolate) + return 0; + + // leave bits 0 and 1 free for the string mode + UINT64 id = ((UINT64)gL->savedpc << 32) | (hud_interpcounter << 10) | (hud_interptag << 2); + + if (hud_interplatch) + { + id |= INTERP_LATCH; + hud_interplatch = false; + } + if (hud_interpstring) + id |= INTERP_STRING; + + return id; +} void LUA_HUD_AddDraw( huddrawlist_h list, @@ -325,7 +339,7 @@ void LUA_HUD_AddDraw( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; - GETITEMID + item->id = GetItemId(); item->type = DI_Draw; item->x = x << FRACBITS; item->y = y << FRACBITS; @@ -346,7 +360,7 @@ void LUA_HUD_AddDrawScaled( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; - GETITEMID + item->id = GetItemId(); item->type = DI_DrawScaled; item->x = x; item->y = y; @@ -369,7 +383,7 @@ void LUA_HUD_AddDrawStretched( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; - GETITEMID + item->id = GetItemId(); item->type = DI_DrawStretched; item->x = x; item->y = y; @@ -390,7 +404,7 @@ void LUA_HUD_AddDrawNum( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; - GETITEMID + item->id = GetItemId(); item->type = DI_DrawNum; item->x = x; item->y = y; @@ -409,7 +423,7 @@ void LUA_HUD_AddDrawPaddedNum( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; - GETITEMID + item->id = GetItemId(); item->type = DI_DrawPaddedNum; item->x = x; item->y = y; @@ -429,7 +443,7 @@ void LUA_HUD_AddDrawPingNum( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; - GETITEMID + item->id = GetItemId(); item->type = DI_DrawPingNum; item->x = x; item->y = y; @@ -449,7 +463,7 @@ void LUA_HUD_AddDrawFill( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; - GETITEMID + item->id = GetItemId(); item->type = DI_DrawFill; item->x = x; item->y = y; @@ -470,7 +484,7 @@ void LUA_HUD_AddDrawString( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; - GETITEMID + item->id = GetItemId(); item->type = DI_DrawString; item->x = x; item->y = y; @@ -490,7 +504,7 @@ void LUA_HUD_AddDrawKartString( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; - GETITEMID + item->id = GetItemId(); item->type = DI_DrawKartString; item->x = x; item->y = y; @@ -508,7 +522,7 @@ void LUA_HUD_AddDrawLevelTitle( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; - GETITEMID + item->id = GetItemId(); item->type = DI_DrawLevelTitle; item->x = x; item->y = y; @@ -524,6 +538,8 @@ void LUA_HUD_AddFadeScreen( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + // nothing to interpolate here + item->id = 0; item->type = DI_FadeScreen; item->color = color; item->strength = strength; @@ -548,7 +564,7 @@ void LUA_HUD_DrawList(huddrawlist_h list) drawitem_t *olditem = NULL; const char *itemstr = &list->strbuf[item->stroffset]; - if (item->id && cv_uncappedhud.value) { + if (item->id) { // find the old one too // this is kinda cursed... we need to check every item // but stop when the first-checked item is reached again @@ -568,13 +584,11 @@ void LUA_HUD_DrawList(huddrawlist_h list) // gotcha! olditem = old; if (item->id & INTERP_LATCH) { - if (!latchitem) { - lerpx = FixedMul(frac, item->x - olditem->x); - lerpy = FixedMul(frac, item->y - olditem->y); - latchitem = item; - oldlatchitem = olditem; - } - } else { + lerpx = FixedMul(frac, item->x - olditem->x); + lerpy = FixedMul(frac, item->y - olditem->y); + latchitem = item; + oldlatchitem = olditem; + } else if (!(item->id & INTERP_STRING)) { lerpx = FixedMul(frac, item->x - olditem->x); lerpy = FixedMul(frac, item->y - olditem->y); latchitem = NULL; @@ -584,6 +598,9 @@ void LUA_HUD_DrawList(huddrawlist_h list) if (j == stop) break; } + } else { + lerpx = lerpy = 0; + latchitem = NULL; } #define LERP(it) (olditem ? olditem->it + FixedMul(frac, item->it - olditem->it) : item->it) -- 2.54.0 From 60e42472e32679b025615bc8257e2a9bf0f43386 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy <86008856+GenericHeroGuy@users.noreply.github.com> Date: Fri, 12 Apr 2024 21:00:54 +0200 Subject: [PATCH 06/12] Do string coordinate calcs on all functions (and fix) --- src/lua_hudlib_drawlist.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/lua_hudlib_drawlist.c b/src/lua_hudlib_drawlist.c index 65e6cef42..4a58371c8 100644 --- a/src/lua_hudlib_drawlist.c +++ b/src/lua_hudlib_drawlist.c @@ -196,7 +196,7 @@ static size_t CopyString(huddrawlist_h list, const char* str) } } -static void CalcCoords(huddrawlist_h list, drawitem_t *item) +static void CalcStringCoords(drawitem_t *item, const char *string) { if (!(item->flags & V_NOSCALESTART) && cv_uncappedhud.value) { @@ -228,6 +228,12 @@ static void CalcCoords(huddrawlist_h list, drawitem_t *item) INT32 x = item->x * dupx; INT32 y = item->y * dupy; + if (item->flags & V_SPLITSCREEN) + y += (BASEVIDHEIGHT * (dupy - 1))/2; + + if (item->flags & V_HORZSCREEN) + x += (BASEVIDWIDTH * (dupx - 1))/2; + if (vid.width != BASEVIDWIDTH * dupx) { // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, @@ -251,13 +257,17 @@ static void CalcCoords(huddrawlist_h list, drawitem_t *item) } // need to compensate for dup here - - if (item->align == align_center) - x -= (V_StringWidth(&list->strbuf[item->stroffset], item->flags) * (dupx - 1))/2; - if (item->align == align_right) - x -= V_StringWidth(&list->strbuf[item->stroffset], item->flags) * (dupx - 1); - if (item->align == align_thinright) - x -= V_ThinStringWidth(&list->strbuf[item->stroffset], item->flags) * (dupx - 1); + if (item->type == DI_DrawString) + { + if (item->align == align_center) + x -= (V_StringWidth(string, item->flags) * (dupx - 1))/2; + if (item->align == align_right) + x -= V_StringWidth(string, item->flags) * (dupx - 1); + if (item->align == align_smallright) + x -= V_SmallStringWidth(string, item->flags) * (dupx - 1); + if (item->align == align_thinright) + x -= V_ThinStringWidth(string, item->flags) * (dupx - 1); + } item->x = x; item->y = y; @@ -410,6 +420,7 @@ void LUA_HUD_AddDrawNum( item->y = y; item->num = num; item->flags = flags; + CalcStringCoords(item, NULL); } void LUA_HUD_AddDrawPaddedNum( @@ -430,6 +441,7 @@ void LUA_HUD_AddDrawPaddedNum( item->num = num; item->digits = digits; item->flags = flags; + CalcStringCoords(item, NULL); } void LUA_HUD_AddDrawPingNum( @@ -450,6 +462,7 @@ void LUA_HUD_AddDrawPingNum( item->num = num; item->flags = flags; item->colormap = colormap; + CalcStringCoords(item, NULL); } void LUA_HUD_AddDrawFill( @@ -491,7 +504,8 @@ void LUA_HUD_AddDrawString( item->stroffset = CopyString(list, str); item->flags = flags; item->align = align; - CalcCoords(list, item); + if (item->align != align_fixed) + CalcStringCoords(item, str); } void LUA_HUD_AddDrawKartString( @@ -510,6 +524,7 @@ void LUA_HUD_AddDrawKartString( item->y = y; item->stroffset = CopyString(list, str); item->flags = flags; + CalcStringCoords(item, str); } void LUA_HUD_AddDrawLevelTitle( @@ -528,6 +543,7 @@ void LUA_HUD_AddDrawLevelTitle( item->y = y; item->stroffset = CopyString(list, str); item->flags = flags; + CalcStringCoords(item, str); } void LUA_HUD_AddFadeScreen( -- 2.54.0 From 995777c676657f45b0db2b5d158edc63a9b070cd Mon Sep 17 00:00:00 2001 From: GenericHeroGuy <86008856+GenericHeroGuy@users.noreply.github.com> Date: Fri, 12 Apr 2024 22:36:23 +0200 Subject: [PATCH 07/12] Exclude string mode flags from olditem search --- src/lua_hudlib_drawlist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lua_hudlib_drawlist.c b/src/lua_hudlib_drawlist.c index 4a58371c8..c621512ba 100644 --- a/src/lua_hudlib_drawlist.c +++ b/src/lua_hudlib_drawlist.c @@ -595,7 +595,7 @@ void LUA_HUD_DrawList(huddrawlist_h list) break; } drawitem_t *old = &list->olditems[j++]; - if (old->id == item->id) + if ((old->id & ~3) == (item->id & ~3)) { // gotcha! olditem = old; -- 2.54.0 From 1abf6a4ce1302d46073c28c8b97cecee8e19962a Mon Sep 17 00:00:00 2001 From: GenericHeroGuy <86008856+GenericHeroGuy@users.noreply.github.com> Date: Tue, 23 Apr 2024 21:17:06 +0200 Subject: [PATCH 08/12] Add interpolation docs to LUASTUFF --- LUASTUFF.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/LUASTUFF.md b/LUASTUFF.md index 05ca33bd0..96df6b5f8 100644 --- a/LUASTUFF.md +++ b/LUASTUFF.md @@ -52,6 +52,45 @@ Returns the displayplayer's HUD color. Returns true if colorization is enabled, false otherwise. +## v.interpolate(true) + +Enables HUD interpolation. Each call to a drawing function will have its coordinates interpolated +by assigning an unique ID to every call. +For example, three successive calls to `v.draw` will each have their own ID and interpolation offsets. +Pass `true` to enable interpolation, `false` to disable. + +Alternatively, pass a number to enable interpolation with the specified tag. +Tags allow HUD items drawn by the same call to a drawing function to be differentiated. +Valid tags range from 0-255. +For example, when iterating players, use a unique tag for each player to avoid artifacting: +```lua +for p in players.iterate do + -- enable interpolation, using player numbers as the tag + -- every draw will have different interp offsets per player + v.interpolate(#p) + + -- doesn't matter for unconditional draws like this one... + v.draw(...) + + -- but it does matter if there's a condition! + -- without tags, this patch would warp between players + -- whenever their `someVar` changes + if p.someVar then v.draw(...) end +end + +-- don't want interpolation anymore? then disable it +v.interpolate(false) +``` +NOTE: The default tag for `true` is 0. + +## v.interpString(true) + +Enables string interpolation mode. The next call to a drawing function will have its interpolation offsets +latched and reused for all following draw calls. +Disable with `false` when done. + +When using a custom string drawer, enable this mode to avoid interpolation artifacting when the string changes. + ## mobj.spritexscale, mobj.spriteyscale, mobj.spritexoffset, mobj.spriteyoffset, mobj.rollangle, mobj.sloperoll, mobj.rollmodel fields Same fields as in SRB2 2.2 -- 2.54.0 From 9cd1233c3224bf2000180a1ce866348c4bdd268f Mon Sep 17 00:00:00 2001 From: GenericHeroGuy <86008856+GenericHeroGuy@users.noreply.github.com> Date: Thu, 23 May 2024 16:36:26 +0200 Subject: [PATCH 09/12] Dust this crap off a bit --- src/lua_hud.h | 10 +++++----- src/lua_hudlib_drawlist.c | 19 +++++++++++++------ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/lua_hud.h b/src/lua_hud.h index ccaed738d..5d1f41c83 100644 --- a/src/lua_hud.h +++ b/src/lua_hud.h @@ -42,11 +42,11 @@ enum hud { extern boolean hud_running; -extern boolean hud_interpolate; -extern UINT8 hud_interptag; -extern UINT32 hud_interpcounter; -extern boolean hud_interpstring; -extern boolean hud_interplatch; +extern boolean hud_interpolate; // interpolation enabled +extern UINT8 hud_interptag; // current tag +extern UINT32 hud_interpcounter; // number of HUD hooks ran +extern boolean hud_interpstring; // string mode +extern boolean hud_interplatch; // string mode was toggled boolean LUA_HudEnabled(enum hud option); diff --git a/src/lua_hudlib_drawlist.c b/src/lua_hudlib_drawlist.c index c621512ba..98f0d45e7 100644 --- a/src/lua_hudlib_drawlist.c +++ b/src/lua_hudlib_drawlist.c @@ -318,6 +318,7 @@ static void CalcFillCoords(drawitem_t *item) #define INTERP_LATCH 1 #define INTERP_STRING 2 +#define INTERP_FLAGS 3 // all bits combined static UINT64 GetItemId(void) { @@ -325,7 +326,7 @@ static UINT64 GetItemId(void) return 0; // leave bits 0 and 1 free for the string mode - UINT64 id = ((UINT64)gL->savedpc << 32) | (hud_interpcounter << 10) | (hud_interptag << 2); + UINT64 id = ((uintptr_t)gL->savedpc << 32) | (hud_interpcounter << 10) | (hud_interptag << 2); if (hud_interplatch) { @@ -580,7 +581,8 @@ void LUA_HUD_DrawList(huddrawlist_h list) drawitem_t *olditem = NULL; const char *itemstr = &list->strbuf[item->stroffset]; - if (item->id) { + if (item->id) + { // find the old one too // this is kinda cursed... we need to check every item // but stop when the first-checked item is reached again @@ -595,16 +597,19 @@ void LUA_HUD_DrawList(huddrawlist_h list) break; } drawitem_t *old = &list->olditems[j++]; - if ((old->id & ~3) == (item->id & ~3)) + if ((old->id & ~INTERP_FLAGS) == (item->id & ~INTERP_FLAGS)) // don't include flags in search { // gotcha! olditem = old; - if (item->id & INTERP_LATCH) { + if (item->id & INTERP_LATCH) + { lerpx = FixedMul(frac, item->x - olditem->x); lerpy = FixedMul(frac, item->y - olditem->y); latchitem = item; oldlatchitem = olditem; - } else if (!(item->id & INTERP_STRING)) { + } + else if (!(item->id & INTERP_STRING)) + { lerpx = FixedMul(frac, item->x - olditem->x); lerpy = FixedMul(frac, item->y - olditem->y); latchitem = NULL; @@ -614,7 +619,9 @@ void LUA_HUD_DrawList(huddrawlist_h list) if (j == stop) break; } - } else { + } + else + { lerpx = lerpy = 0; latchitem = NULL; } -- 2.54.0 From a17a5387ff294d0a0a8916f8f97be508d2f6aec7 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy <86008856+GenericHeroGuy@users.noreply.github.com> Date: Sat, 25 May 2024 14:08:52 +0200 Subject: [PATCH 10/12] Rename interpString to interpLatch --- src/lua_hudlib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index bceb9ebc4..bc56e6688 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -1212,7 +1212,7 @@ static int libd_interpolate(lua_State *L) return 0; } -static int libd_interpString(lua_State *L) +static int libd_interpLatch(lua_State *L) { HUDONLY hud_interpstring = hud_interplatch = luaL_checkboolean(L, 1); @@ -1247,7 +1247,7 @@ static luaL_Reg lib_draw[] = { {"getHudColor", libd_getHudColor}, {"useColorHud", libd_useColorHud}, {"interpolate", libd_interpolate}, - {"interpString", libd_interpString}, + {"interpLatch", libd_interpLatch}, {NULL, NULL} }; -- 2.54.0 From 142c01f516f839d48e292ff115203b3b8f0677c0 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy <86008856+GenericHeroGuy@users.noreply.github.com> Date: Sat, 25 May 2024 14:09:20 +0200 Subject: [PATCH 11/12] Update docs for interpLatch --- LUASTUFF.md | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/LUASTUFF.md b/LUASTUFF.md index 96df6b5f8..79e2a2545 100644 --- a/LUASTUFF.md +++ b/LUASTUFF.md @@ -83,12 +83,37 @@ v.interpolate(false) ``` NOTE: The default tag for `true` is 0. -## v.interpString(true) +## v.interpLatch(true) -Enables string interpolation mode. The next call to a drawing function will have its interpolation offsets -latched and reused for all following draw calls. -Disable with `false` when done. +Enables interpolation offset latching. The next call to a drawing function will have its lerp offsets +saved and reused for all following draw calls. Disable with `false` when done. +Interpolation cannot easily "snap" between two points; latching can help overcome this by manually +setting the lerp offsets. +```lua +v.interpolate(true) +-- X coordinate for the HUD item +-- every so often, this will wrap around to zero +local x = (leveltime*4) % 256 + +-- draw an interpolated patch, but... when X rolls back to zero, +-- the patch will slide all the way across the screen! +v.draw(x, 100, ...) + +-- this is where interpLatch comes into play +-- enable latching, then draw an invisible patch, +-- moving at the same speed as the visible patch +-- the exact coordinates don't matter, it just has to move at the right speed +v.interpLatch(true) +v.draw(leveltime*4, 0, v.cachePatch("K_TRNULL")) + +-- now we can draw the patch again, and when X becomes zero, +-- it'll snap right back without sliding across the screen +v.draw(x, 150, ...) + +-- don't forget to turn off latching! +v.interpLatch(false) +``` When using a custom string drawer, enable this mode to avoid interpolation artifacting when the string changes. ## mobj.spritexscale, mobj.spriteyscale, mobj.spritexoffset, mobj.spriteyoffset, mobj.rollangle, mobj.sloperoll, mobj.rollmodel fields -- 2.54.0 From 05a56512606ce4c1e04b4fea0075aa2dd71bcf41 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy <86008856+GenericHeroGuy@users.noreply.github.com> Date: Sat, 25 May 2024 17:05:08 +0200 Subject: [PATCH 12/12] Finishing touches Some cleanup, also interpolate drawfill size (dunno why it wasn't before) --- src/lua_hudlib_drawlist.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/lua_hudlib_drawlist.c b/src/lua_hudlib_drawlist.c index 98f0d45e7..ff98c6e8b 100644 --- a/src/lua_hudlib_drawlist.c +++ b/src/lua_hudlib_drawlist.c @@ -318,7 +318,7 @@ static void CalcFillCoords(drawitem_t *item) #define INTERP_LATCH 1 #define INTERP_STRING 2 -#define INTERP_FLAGS 3 // all bits combined +#define INTERP_FLAGMASK 0x3 static UINT64 GetItemId(void) { @@ -587,17 +587,15 @@ void LUA_HUD_DrawList(huddrawlist_h list) // this is kinda cursed... we need to check every item // but stop when the first-checked item is reached again size_t stop = j; - while(true) + do { if (j == list->olditems_len) { - // wrap around j = 0; - if (j == stop) // i'm dumb - break; + continue; } drawitem_t *old = &list->olditems[j++]; - if ((old->id & ~INTERP_FLAGS) == (item->id & ~INTERP_FLAGS)) // don't include flags in search + if ((old->id & ~INTERP_FLAGMASK) == (item->id & ~INTERP_FLAGMASK)) { // gotcha! olditem = old; @@ -616,9 +614,8 @@ void LUA_HUD_DrawList(huddrawlist_h list) } break; } - if (j == stop) - break; } + while (j != stop); } else { @@ -653,7 +650,7 @@ void LUA_HUD_DrawList(huddrawlist_h list) V_DrawPingNum(LERPS(x), LERPS(y), item->flags, item->num, item->colormap); break; case DI_DrawFill: - V_DrawFill(LERPS(x), LERPS(y), item->w, item->h, item->c); + V_DrawFill(LERPS(x), LERPS(y), LERP(w), LERP(h), item->c); break; case DI_DrawString: switch(item->align) -- 2.54.0