Merge pull request 'Port cliprects over and add Lua Support' (#24) from cliprect into ACS2

Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/24
This commit is contained in:
NepDisk 2025-02-22 18:43:05 +00:00
commit 121fe48ae3
14 changed files with 508 additions and 263 deletions

View file

@ -371,6 +371,9 @@ static bool D_Display(void)
if (dedicated) //bail out after wipe logic
return false;
// Catch runaway clipping rectangles.
V_ClearClipRect();
// do buffered drawing
switch (gamestate)
{

View file

@ -1252,6 +1252,7 @@ struct int_const_s const INT_CONST[] = {
{"V_OVERLAY",V_OVERLAY},
{"V_ALLOWLOWERCASE",V_ALLOWLOWERCASE},
{"V_FLIP",V_FLIP},
{"V_VFLIP",V_VFLIP},
{"V_SNAPTOTOP",V_SNAPTOTOP},
{"V_SNAPTOBOTTOM",V_SNAPTOBOTTOM},
{"V_SNAPTOLEFT",V_SNAPTOLEFT},

View file

@ -145,6 +145,11 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p
// 0--1
float dupx, dupy, fscalew, fscaleh, fwidth, fheight;
const cliprect_t *clip = V_GetClipRect();
float s_min, s_max;
float t_min, t_max;
// make patch ready in hardware cache
if (!colormap)
HWR_GetPatch(gpatch);
@ -188,7 +193,10 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p
offsetx = (float)(gpatch->leftoffset) * fscalew;
// top offset
offsety = (float)(gpatch->topoffset) * fscaleh;
if (option & V_VFLIP)
offsety = (float)(gpatch->height - gpatch->topoffset) * fscaleh;
else
offsety = (float)(gpatch->topoffset) * fscaleh;
cx -= offsetx;
cy -= offsety;
@ -204,7 +212,7 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p
INT32 intx, inty;
intx = (INT32)cx;
inty = (INT32)cy;
K_AdjustXYWithSnap(&intx, &inty, option, dupx, dupy);
V_AdjustXYWithSnap(&intx, &inty, option, dupx, dupy);
cx = (float)intx;
cy = (float)inty;
}
@ -221,6 +229,47 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p
fheight = (float)(gpatch->height) * dupy;
}
s_min = t_min = 0.0f;
s_max = hwrPatch->max_s;
t_max = hwrPatch->max_t;
if (clip)
{
float cx1 = cx;
float cy1 = cy;
float cx2 = cx + fwidth;
float cy2 = cy + fheight;
if (cx1 < clip->left)
{
s_min = (clip->left - cx1) / fwidth * hwrPatch->max_s;
cx1 = clip->left;
}
if (cy1 < clip->top)
{
t_min = (clip->top - cy1) / fheight * hwrPatch->max_t;
cy1 = clip->top;
}
if (cx2 > clip->right)
{
s_max = s_min + (clip->right - cx1) / fwidth * hwrPatch->max_s;
cx2 = clip->right;
}
if (cy2 > clip->bottom)
{
t_max = t_min + (clip->bottom - cy1) / fheight * hwrPatch->max_t;
cy2 = clip->bottom;
}
cx = cx1;
cy = cy1;
fwidth = fmaxf(0.0f, cx2 - cx1);
fheight = fmaxf(0.0f, cy2 - cy1);
}
// positions of the cx, cy, are between 0 and vid.width/vid.height now, we need them to be between -1 and 1
cx = -1.0f + (cx / (vid.width / 2.0f));
cy = 1.0f - (cy / (vid.height / 2.0f));
@ -240,17 +289,25 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p
if (option & V_FLIP)
{
v[0].s = v[3].s = hwrPatch->max_s;
v[2].s = v[1].s = 0.0f;
v[0].s = v[3].s = s_max;
v[2].s = v[1].s = s_min;
}
else
{
v[0].s = v[3].s = 0.0f;
v[2].s = v[1].s = hwrPatch->max_s;
v[0].s = v[3].s = s_min;
v[2].s = v[1].s = s_max;
}
v[0].t = v[1].t = 0.0f;
v[2].t = v[3].t = hwrPatch->max_t;
if (option & V_VFLIP)
{
v[0].t = v[1].t = t_max;
v[2].t = v[3].t = t_min;
}
else
{
v[0].t = v[1].t = t_min;
v[2].t = v[3].t = t_max;
}
flags = PF_NoDepthTest;
@ -1000,7 +1057,7 @@ void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT32
intx = (INT32)fx;
inty = (INT32)fy;
K_AdjustXYWithSnap(&intx, &inty, color, dupx, dupy);
V_AdjustXYWithSnap(&intx, &inty, color, dupx, dupy);
fx = (float)intx;
fy = (float)inty;
}
@ -1092,7 +1149,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
intx = (INT32)fx;
inty = (INT32)fy;
K_AdjustXYWithSnap(&intx, &inty, color, dupx, dupy);
V_AdjustXYWithSnap(&intx, &inty, color, dupx, dupy);
fx = (float)intx;
fy = (float)inty;
}

View file

@ -620,116 +620,6 @@ INT32 ITEM2_X, ITEM2_Y;
INT32 LAPS2_X, LAPS2_Y;
INT32 POSI2_X, POSI2_Y;
void K_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 dupy)
{
// dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx
INT32 screenwidth = vid.width;
INT32 screenheight = vid.height;
INT32 basewidth = BASEVIDWIDTH * dupx;
INT32 baseheight = BASEVIDHEIGHT * dupy;
SINT8 player = -1;
UINT8 i;
if (options & V_SPLITSCREEN)
{
if (r_splitscreen > 0)
{
screenheight /= 2;
baseheight /= 2;
}
if (r_splitscreen > 1)
{
screenwidth /= 2;
basewidth /= 2;
}
}
for (i = 0; i <= r_splitscreen; i++)
{
if (stplyr == &players[displayplayers[i]])
{
player = i;
break;
}
}
if (vid.width != (BASEVIDWIDTH * dupx))
{
if (options & V_SNAPTORIGHT)
*x += (screenwidth - basewidth);
else if (!(options & V_SNAPTOLEFT))
*x += (screenwidth - basewidth) / 2;
}
if (vid.height != (BASEVIDHEIGHT * dupy))
{
if (options & V_SNAPTOBOTTOM)
*y += (screenheight - baseheight);
else if (!(options & V_SNAPTOTOP))
*y += (screenheight - baseheight) / 2;
}
if (options & V_SPLITSCREEN)
{
if (r_splitscreen == 1)
{
if (player == 1)
*y += screenheight;
}
else if (r_splitscreen > 1)
{
if (player == 1 || player == 3)
*x += screenwidth;
if (player == 2 || player == 3)
*y += screenheight;
}
}
if (options & V_SLIDEIN)
{
const tic_t length = TICRATE/4;
tic_t timer = lt_exitticker;
if (bossinfo.boss == true)
{
if (leveltime <= 3)
timer = 0;
else
timer = leveltime-3;
}
if (timer < length)
{
boolean slidefromright = false;
const INT32 offsetAmount = (screenwidth * FRACUNIT/2) / length;
fixed_t offset = (screenwidth * FRACUNIT/2) - (timer * offsetAmount);
offset += FixedMul(offsetAmount, renderdeltatics);
offset /= FRACUNIT;
if (r_splitscreen > 1)
{
if (stplyr == &players[displayplayers[1]] || stplyr == &players[displayplayers[3]])
slidefromright = true;
}
if (options & V_SNAPTORIGHT)
slidefromright = true;
else if (options & V_SNAPTOLEFT)
slidefromright = false;
if (slidefromright == true)
{
offset = -offset;
}
*x -= offset;
}
}
}
// This version of the function was prototyped in Lua by Nev3r ... a HUGE thank you goes out to them!
void K_ObjectTracking(trackingResult_t *result, vector3_t *point, boolean reverse)
{
@ -1269,6 +1159,8 @@ static void K_drawKartItem(void)
V_DrawScaledPatch(fx, fy, V_HUDTRANS|fflags, localbg);
//V_SetClipRect((fx + 10) << FRACBITS, (fy + 10) << FRACBITS, 30 << FRACBITS, 30 << FRACBITS, V_HUDTRANS|V_SLIDEIN|fflags);
// Then, the numbers:
if (stplyr->itemamount >= numberdisplaymin && !stplyr->itemroulette)
{
@ -1288,6 +1180,8 @@ static void K_drawKartItem(void)
else
V_DrawFixedPatch(fx<<FRACBITS, fy<<FRACBITS, FRACUNIT, V_HUDTRANS|fflags, localpatch, colmap);
//V_ClearClipRect();
// Extensible meter, currently only used for rocket sneaker...
if (itembar)
{

View file

@ -25,8 +25,6 @@ extern "C" {
extern consvar_t cv_newspeedometer;
void K_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 dupy);
struct trackingResult_t
{
fixed_t x, y;

View file

@ -27,6 +27,8 @@
#include "d_netcmd.h" // for cv_perfstats
#include "i_system.h" // I_GetPreciseTime
#include "v_video.h" // V_ClearClipRect
/* =========================================================================
ABSTRACTION
========================================================================= */
@ -486,8 +488,12 @@ static int call_mapped_hud(Hook_State *hook, const hook_t *map)
{
hud_interpolate = hud_interpstring = hud_interplatch = false;
hud_interpcounter++;
get_hook(hook, map->ids, k);
call_single_hook(hook);
// Catch runaway clipping rectangles.
LUA_ClearClipRect();
}
return map->numHooks;
@ -672,8 +678,10 @@ void LUA_HookHUD(huddrawlist_h list, int hook_type)
hud_interpcounter = 0;
hud_running = true; // local hook
init_hook_call(&hook, 0, res_none);
call_mapped_hud(&hook, map);
hud_running = false;
}
}

View file

@ -59,6 +59,8 @@ boolean LUA_HudEnabled(enum hud option);
void LUA_SetHudHook(int hook, huddrawlist_h list);
void LUA_ClearClipRect(void);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -47,6 +47,8 @@ static UINT8 hud_enabled[(hud_MAX/8)+1];
static UINT8 camnum = 1;
static boolean cliprectenabled;
// must match enum hud in lua_hud.h
static const char *const hud_disable_options[] = {
"stagetitle",
@ -972,6 +974,47 @@ static int libd_drawKartString(lua_State *L)
return 0;
}
static int libd_setClipRect(lua_State *L)
{
fixed_t x = luaL_checkinteger(L, 1);
fixed_t y = luaL_checkinteger(L, 2);
fixed_t w = luaL_checkinteger(L, 3);
fixed_t h = luaL_checkinteger(L, 4);
INT32 flags = luaL_optinteger(L, 5, 0);
huddrawlist_h list;
flags &= ~V_PARAMMASK; // Don't let crashes happen.
HUDONLY
lua_getfield(L, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
list = (huddrawlist_h) lua_touserdata(L, -1);
lua_pop(L, 1);
cliprectenabled = true;
if (LUA_HUD_IsDrawListValid(list))
LUA_HUD_AddSetClipRect(list, x, y, w, h, flags);
else
V_SetClipRect(x, y, w, h, flags);
return 0;
}
static int libd_clearClipRect(lua_State *L)
{
huddrawlist_h list;
HUDONLY
lua_getfield(L, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
list = (huddrawlist_h) lua_touserdata(L, -1);
lua_pop(L, 1);
cliprectenabled = false;
if (LUA_HUD_IsDrawListValid(list))
LUA_HUD_AddClearClipRect(list);
else
V_ClearClipRect();
return 0;
}
static int libd_titleCardStringWidth(lua_State *L)
{
const char *str = luaL_checkstring(L, 1);
@ -1263,6 +1306,8 @@ static luaL_Reg lib_draw[] = {
{"drawString", libd_drawString},
{"drawTitleCardString", libd_drawTitleCardString},
{"drawKartString", libd_drawKartString},
{"setClipRect", libd_setClipRect},
{"clearClipRect", libd_clearClipRect},
// misc
{"stringWidth", libd_stringWidth},
{"titleCardStringWidth", libd_titleCardStringWidth},
@ -1417,6 +1462,8 @@ void LUA_SetHudHook(int hook, huddrawlist_h list)
lua_pushlightuserdata(gL, list);
lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
cliprectenabled = false;
switch (hook)
{
case HUD_HOOK(game):
@ -1435,3 +1482,13 @@ void LUA_SetHudHook(int hook, huddrawlist_h list)
break;
}
}
void LUA_ClearClipRect(void)
{
// V_ClearClipRect is not enough: we need to insert a clearClipRect
// into the drawlist to protect both hardcode and other HUD hooks.
// thankfully the below function takes zero Lua arguments :^)
if (cliprectenabled)
libd_clearClipRect(gL);
//cliprectenabled = false;
}

View file

@ -37,6 +37,8 @@ enum drawitem_e {
DI_DrawTitleCardString,
DI_DrawTitleCardStringBoss,
DI_DrawKartString,
DI_SetClipRect,
DI_ClearClipRect,
DI_MAX,
};
@ -201,6 +203,7 @@ static size_t CopyString(huddrawlist_h list, const char* str)
}
}
/*
static void CalcStringCoords(drawitem_t *item, const char *string)
{
if (!(item->flags & V_NOSCALESTART))
@ -307,6 +310,7 @@ static void CalcFillCoords(drawitem_t *item)
item->y = y;
}
}
*/
#define INTERP_LATCH 1
#define INTERP_STRING 2
@ -508,6 +512,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;
@ -555,6 +561,36 @@ void LUA_HUD_AddDrawKartString(
// CalcStringCoords(item, str);
}
void LUA_HUD_AddSetClipRect(
huddrawlist_h list,
fixed_t x,
fixed_t y,
fixed_t w,
fixed_t h,
INT32 flags
)
{
size_t i = AllocateDrawItem(list);
drawitem_t *item = &list->items[i];
item->id = GetItemId();
item->type = DI_SetClipRect;
item->x = x;
item->y = y;
item->w = w;
item->h = h;
item->flags = flags;
}
void LUA_HUD_AddClearClipRect(
huddrawlist_h list
)
{
size_t i = AllocateDrawItem(list);
drawitem_t *item = &list->items[i];
item->id = 0;
item->type = DI_ClearClipRect;
}
void LUA_HUD_DrawList(huddrawlist_h list)
{
size_t i;
@ -692,6 +728,12 @@ void LUA_HUD_DrawList(huddrawlist_h list)
case DI_DrawKartString:
V_DrawKartString(LERPS(x), LERPS(y), item->flags, itemstr);
break;
case DI_SetClipRect:
V_SetClipRect(LERPS(x), LERPS(y), LERP(w), LERP(h), item->flags);
break;
case DI_ClearClipRect:
V_ClearClipRect();
break;
default:
I_Error("can't draw draw list item: invalid draw list item type");
continue;

View file

@ -120,6 +120,17 @@ void LUA_HUD_AddDrawKartString(
const char *str,
INT32 flags
);
void LUA_HUD_AddSetClipRect(
huddrawlist_h list,
fixed_t x,
fixed_t y,
fixed_t w,
fixed_t h,
INT32 flags
);
void LUA_HUD_AddClearClipRect(
huddrawlist_h list
);
// Draws the given draw list
void LUA_HUD_DrawList(huddrawlist_h list);

View file

@ -724,7 +724,7 @@ void ST_preLevelTitleCardDrawer(void)
// Draw the status bar overlay, customisable: the user chooses which
// kind of information to overlay
//
static void ST_overlayDrawer(UINT8 playernum)
static void ST_overlayDrawer(void)
{
// hu_showscores = auto hide score/time/rings when tab rankings are shown
if (!(hu_showscores && (netgame || multiplayer)))
@ -733,9 +733,10 @@ static void ST_overlayDrawer(UINT8 playernum)
if (renderisnewtic)
{
LUA_HookHUD(luahuddrawlist_game[playernum], HUD_HOOK(game));
LUA_HUD_ClearDrawList(luahuddrawlist_game[stplyrnum]);
LUA_HookHUD(luahuddrawlist_game[stplyrnum], HUD_HOOK(game));
}
LUA_HUD_DrawList(luahuddrawlist_game[playernum]);
LUA_HUD_DrawList(luahuddrawlist_game[stplyrnum]);
}
if (!hu_showscores) // hide the following if TAB is held
@ -911,11 +912,6 @@ void ST_Drawer(void)
if (st_overlay)
{
UINT8 i;
if (renderisnewtic)
{
for (i = 0; i <= r_splitscreen; i++)
LUA_HUD_ClearDrawList(luahuddrawlist_game[i]);
}
// No deadview!
for (i = 0; i <= r_splitscreen; i++)
{
@ -923,12 +919,9 @@ void ST_Drawer(void)
stplyrnum = i;
R_SetViewContext(VIEWCONTEXT_PLAYER1 + i);
R_InterpolateView(rendertimefrac); // to assist with object tracking
ST_overlayDrawer(i);
ST_overlayDrawer();
}
for (i = 0; i <= r_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.
ST_MayonakaStatic();

View file

@ -397,6 +397,7 @@ TYPEDEF (taggroup_t);
// v_video.h
TYPEDEF (colorlookup_t);
TYPEDEF (cliprect_t);
// w_wad.h
TYPEDEF (filelump_t);

View file

@ -38,6 +38,7 @@
// SRB2Kart
#include "k_hud.h"
#include "k_boss.h"
#include "i_time.h"
// Each screen is [vid.width*vid.height];
@ -525,6 +526,211 @@ void VID_BlitLinearScreen(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT3
#endif
}
void V_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 dupy)
{
// dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx
INT32 screenwidth = vid.width;
INT32 screenheight = vid.height;
INT32 basewidth = BASEVIDWIDTH * dupx;
INT32 baseheight = BASEVIDHEIGHT * dupy;
SINT8 player = -1;
UINT8 i;
if (options & V_SPLITSCREEN)
{
if (r_splitscreen > 0)
{
screenheight /= 2;
baseheight /= 2;
}
if (r_splitscreen > 1)
{
screenwidth /= 2;
basewidth /= 2;
}
}
for (i = 0; i <= r_splitscreen; i++)
{
if (stplyr == &players[displayplayers[i]])
{
player = i;
break;
}
}
if (vid.width != (BASEVIDWIDTH * dupx))
{
if (options & V_SNAPTORIGHT)
*x += (screenwidth - basewidth);
else if (!(options & V_SNAPTOLEFT))
*x += (screenwidth - basewidth) / 2;
}
if (vid.height != (BASEVIDHEIGHT * dupy))
{
if (options & V_SNAPTOBOTTOM)
*y += (screenheight - baseheight);
else if (!(options & V_SNAPTOTOP))
*y += (screenheight - baseheight) / 2;
}
if (options & V_SPLITSCREEN)
{
if (r_splitscreen == 1)
{
if (player == 1)
*y += screenheight;
}
else if (r_splitscreen > 1)
{
if (player == 1 || player == 3)
*x += screenwidth;
if (player == 2 || player == 3)
*y += screenheight;
}
}
if (options & V_SLIDEIN)
{
const tic_t length = TICRATE/4;
tic_t timer = lt_exitticker;
if (bossinfo.boss == true)
{
if (leveltime <= 3)
timer = 0;
else
timer = leveltime-3;
}
if (timer < length)
{
boolean slidefromright = false;
const INT32 offsetAmount = (screenwidth * FRACUNIT/2) / length;
fixed_t offset = (screenwidth * FRACUNIT/2) - (timer * offsetAmount);
offset += FixedMul(offsetAmount, renderdeltatics);
offset /= FRACUNIT;
if (r_splitscreen > 1)
{
if (stplyr == &players[displayplayers[1]] || stplyr == &players[displayplayers[3]])
slidefromright = true;
}
if (options & V_SNAPTORIGHT)
slidefromright = true;
else if (options & V_SNAPTOLEFT)
slidefromright = false;
if (slidefromright == true)
{
offset = -offset;
}
*x -= offset;
}
}
}
static cliprect_t cliprect;
const cliprect_t *V_GetClipRect(void)
{
if (cliprect.enabled == false)
{
return NULL;
}
return &cliprect;
}
void V_SetClipRect(fixed_t x, fixed_t y, fixed_t w, fixed_t h, INT32 flags)
{
// Adjust position.
if (!(flags & V_NOSCALESTART))
{
fixed_t dupx = vid.dupx;
fixed_t dupy = vid.dupy;
if (flags & V_SCALEPATCHMASK)
{
switch ((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;
}
}
dupx = dupy = (dupx < dupy ? dupx : dupy);
x = FixedMul(x, dupx);
y = FixedMul(y, dupy);
w = FixedMul(w, dupx);
h = FixedMul(h, dupy);
if (!(flags & V_SCALEPATCHMASK))
{
V_AdjustXYWithSnap(&x, &y, flags, dupx, dupy);
}
}
if (x < 0)
{
w += x;
x = 0;
}
if (y < 0)
{
h += y;
y = 0;
}
if (x > vid.width)
{
x = vid.width;
w = 0;
}
if (y > vid.height)
{
y = vid.height;
h = 0;
}
cliprect.left = x;
cliprect.top = y;
cliprect.right = x + w;
cliprect.bottom = y + h;
cliprect.flags = flags;
cliprect.enabled = true;
/*
V_DrawFill(cliprect.l, cliprect.t, cliprect.r - cliprect.l, cliprect.b - cliprect.t, V_NOSCALESTART);
CONS_Printf("[(%d, %d), (%d, %d)]\n", cliprect.l, cliprect.t, cliprect.r, cliprect.b);
*/
}
void V_ClearClipRect(void)
{
cliprect.enabled = false;
}
static UINT8 hudplusalpha[11] = { 10, 8, 6, 4, 2, 0, 0, 0, 0, 0, 0};
static UINT8 hudminusalpha[11] = { 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5};
@ -562,6 +768,8 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
fixed_t pwidth; // patch width
fixed_t offx = 0; // x offset
const cliprect_t *clip = V_GetClipRect();
if (rendermode == render_none)
return;
@ -627,10 +835,6 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
colfrac = FixedDiv(FRACUNIT, fdup);
rowfrac = FixedDiv(FRACUNIT, vdup);
// So it turns out offsets aren't scaled in V_NOSCALESTART unless V_OFFSET is applied ...poo, that's terrible
// For now let's just at least give V_OFFSET the ability to support V_FLIP
// I'll probably make a better fix for 2.2 where I don't have to worry about breaking existing support for stuff
// -- Monster Iestyn 29/10/18
{
fixed_t offsetx = 0, offsety = 0;
@ -641,15 +845,17 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
offsetx = FixedMul(patch->leftoffset<<FRACBITS, pscale);
// top offset
// TODO: make some kind of vertical version of V_FLIP, maybe by deprecating V_OFFSET in future?!?
offsety = FixedMul(patch->topoffset<<FRACBITS, vscale);
if (scrn & V_VFLIP)
offsety = FixedMul((patch->height - patch->topoffset)<<FRACBITS, vscale) + 1;
else
offsety = FixedMul(patch->topoffset<<FRACBITS, vscale);
// Subtract the offsets from x/y positions
x -= offsetx;
y -= offsety;
}
desttop = screens[scrn&V_PARAMMASK];
desttop = screens[scrn&V_SCREENMASK];
if (!desttop)
return;
@ -672,7 +878,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
// Center it if necessary
if (!(scrn & V_SCALEPATCHMASK))
{
K_AdjustXYWithSnap(&x, &y, scrn, dupx, dupy);
V_AdjustXYWithSnap(&x, &y, scrn, dupx, dupy);
}
desttop += (y*vid.width) + x;
@ -694,40 +900,95 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
for (col = 0; (col>>FRACBITS) < patch->width; col += colfrac, ++offx, desttop++)
{
INT32 topdelta, prevdelta = -1;
if (scrn & V_FLIP) // offx is measured from right edge instead of left
{
if (x+pwidth-offx < 0) // don't draw off the left of the screen (WRAP PREVENTION)
if (x+pwidth-offx < (clip ? clip->left : 0)) // don't draw off the left of the screen (WRAP PREVENTION)
break;
if (x+pwidth-offx >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION)
if (x+pwidth-offx >= (clip ? clip->right : vid.width)) // don't draw off the right of the screen (WRAP PREVENTION)
continue;
}
else
{
if (x+offx < 0) // don't draw off the left of the screen (WRAP PREVENTION)
if (x+offx < (clip ? clip->left : 0)) // don't draw off the left of the screen (WRAP PREVENTION)
continue;
if (x+offx >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION)
if (x+offx >= (clip ? clip->right : vid.width)) // don't draw off the right of the screen (WRAP PREVENTION)
break;
}
column = (const column_t *)((const UINT8 *)(patch->columns) + (patch->columnofs[col>>FRACBITS]));
while (column->topdelta != 0xff)
{
fixed_t offy = 0;
topdelta = column->topdelta;
if (topdelta <= prevdelta)
topdelta += prevdelta;
prevdelta = topdelta;
source = (const UINT8 *)(column) + 3;
dest = desttop;
if (scrn & V_FLIP)
dest = deststart + (destend - desttop);
dest += FixedInt(FixedMul(topdelta<<FRACBITS,vdup))*vid.width;
dest = deststart + (destend - dest);
topdelta = FixedInt(FixedMul(topdelta << FRACBITS, vdup));
dest += topdelta * vid.width;
for (ofs = 0; dest < deststop && (ofs>>FRACBITS) < column->length; ofs += rowfrac)
if (scrn & V_VFLIP)
{
if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION)
*dest = patchdrawfunc(dest, source, ofs);
dest += vid.width;
for (ofs = (column->length << FRACBITS)-1; dest < deststop && ofs >= 0; ofs -= rowfrac, ++offy)
{
if (clip != NULL)
{
const INT32 cy = y + topdelta - offy;
if (cy < clip->top) // don't draw off the top of the clip rect
{
dest += vid.width;
continue;
}
if (cy >= clip->bottom) // don't draw off the bottom of the clip rect
{
dest += vid.width;
continue;
}
}
if (dest >= screens[scrn&V_SCREENMASK]) // don't draw off the top of the screen (CRASH PREVENTION)
*dest = patchdrawfunc(dest, source, ofs);
dest += vid.width;
}
}
else
{
for (ofs = 0; dest < deststop && ofs < (column->length << FRACBITS); ofs += rowfrac, ++offy)
{
if (clip != NULL)
{
const INT32 cy = y + topdelta + offy;
if (cy < clip->top) // don't draw off the top of the clip rect
{
dest += vid.width;
continue;
}
if (cy >= clip->bottom) // don't draw off the bottom of the clip rect
{
dest += vid.width;
continue;
}
}
if (dest >= screens[scrn&V_SCREENMASK]) // don't draw off the top of the screen (CRASH PREVENTION)
*dest = patchdrawfunc(dest, source, ofs);
dest += vid.width;
}
}
column = (const column_t *)((const UINT8 *)column + column->length + 4);
}
}
@ -736,115 +997,16 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
// Draws a patch cropped and scaled to arbitrary size.
void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t *patch, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h)
{
UINT8 (*patchdrawfunc)(const UINT8*, const UINT8*, fixed_t);
UINT32 alphalevel, blendmode;
// boolean flip = false;
cliprect_t oldClip = cliprect;
fixed_t col, ofs, colfrac, rowfrac, fdup;
INT32 dupx, dupy;
const column_t *column;
UINT8 *desttop, *dest;
const UINT8 *source, *deststop;
V_SetClipRect(x, y, w, h, scrn);
if (rendermode == render_none)
return;
x -= sx;
y -= sy;
#ifdef HWRENDER
//if (rendermode != render_soft && !con_startup) // Not this again
if (rendermode == render_opengl)
{
HWR_DrawCroppedPatch(patch,x,y,pscale,scrn,sx,sy,w,h);
return;
}
#endif
V_DrawStretchyFixedPatch(x, y, pscale, pscale, scrn, patch, NULL);
patchdrawfunc = standardpdraw;
if ((blendmode = ((scrn & V_BLENDMASK) >> V_BLENDSHIFT)))
blendmode++; // realign to constants
if ((alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT)))
{
if (alphalevel == 10) // V_HUDTRANSHALF
alphalevel = hudminusalpha[st_translucency];
else if (alphalevel == 11) // V_HUDTRANS
alphalevel = 10 - st_translucency;
else if (alphalevel == 12) // V_HUDTRANSDOUBLE
alphalevel = hudplusalpha[st_translucency];
if (alphalevel >= 10) // Still inelegible to render?
return;
}
if ((v_translevel = R_GetBlendTable(blendmode, alphalevel)))
patchdrawfunc = translucentpdraw;
// only use one dup, to avoid stretching (har har)
dupx = dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy);
fdup = FixedMul(dupx<<FRACBITS, pscale);
colfrac = FixedDiv(FRACUNIT, fdup);
rowfrac = FixedDiv(FRACUNIT, fdup);
y -= FixedMul(patch->topoffset<<FRACBITS, pscale);
x -= FixedMul(patch->leftoffset<<FRACBITS, pscale);
desttop = screens[scrn&V_PARAMMASK];
if (!desttop)
return;
deststop = desttop + vid.rowbytes * vid.height;
if (scrn & V_NOSCALESTART) {
x >>= FRACBITS;
y >>= FRACBITS;
desttop += (y*vid.width) + x;
}
else
{
x = FixedMul(x,dupx<<FRACBITS);
y = FixedMul(y,dupy<<FRACBITS);
x >>= FRACBITS;
y >>= FRACBITS;
// Center it if necessary
// adjustxy
desttop += (y*vid.width) + x;
}
for (col = sx<<FRACBITS; (col>>FRACBITS) < patch->width && ((col>>FRACBITS) - sx) < w; col += colfrac, ++x, desttop++)
{
INT32 topdelta, prevdelta = -1;
if (x < 0) // don't draw off the left of the screen (WRAP PREVENTION)
continue;
if (x >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION)
break;
column = (const column_t *)((const UINT8 *)(patch->columns) + (patch->columnofs[col>>FRACBITS]));
while (column->topdelta != 0xff)
{
topdelta = column->topdelta;
if (topdelta <= prevdelta)
topdelta += prevdelta;
prevdelta = topdelta;
source = (const UINT8 *)(column) + 3;
dest = desttop;
if (topdelta-sy > 0)
{
dest += FixedInt(FixedMul((topdelta-sy)<<FRACBITS,fdup))*vid.width;
ofs = 0;
}
else
ofs = (sy-topdelta)<<FRACBITS;
for (; dest < deststop && (ofs>>FRACBITS) < column->length && (((ofs>>FRACBITS) - sy) + topdelta) < h; ofs += rowfrac)
{
if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION)
*dest = patchdrawfunc(dest, source, ofs);
dest += vid.width;
}
column = (const column_t *)((const UINT8 *)column + column->length + 4);
}
}
cliprect = oldClip;
}
//
@ -943,7 +1105,7 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
h *= dupy;
// Center it if necessary
K_AdjustXYWithSnap(&x, &y, c, dupx, dupy);
V_AdjustXYWithSnap(&x, &y, c, dupx, dupy);
}
if (x >= vid.width || y >= vid.height)
@ -1070,7 +1232,7 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
h *= dupy;
// Center it if necessary
K_AdjustXYWithSnap(&x, &y, c, dupx, dupy);
V_AdjustXYWithSnap(&x, &y, c, dupx, dupy);
}
if (x >= vid.width || y >= vid.height)
@ -1157,7 +1319,7 @@ void V_DrawDiag(INT32 x, INT32 y, INT32 wh, INT32 c)
wh *= dupx;
// Center it if necessary
K_AdjustXYWithSnap(&x, &y, c, dupx, dupy);
V_AdjustXYWithSnap(&x, &y, c, dupx, dupy);
}
if (x >= vid.width || y >= vid.height)

View file

@ -85,11 +85,14 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue);
#define V_GetColor(color) (pLocalPalette[color&0xFF])
#define V_GetMasterColor(color) (pMasterPalette[color&0xFF])
// Bottom 8 bits are used for parameter (screen or character)
// Bottom 8 bits are used for parameter (character)
#define V_PARAMMASK 0x000000FF
// strings/characters only
#define V_STRINGDANCE 0x00000002
// Bottom bit is used for screen (patches)
#define V_SCREENMASK 0x0000000F
#define V_STRINGDANCE 0x00000002 // (strings/characters only) funny undertale
#define V_VFLIP 0x00000010 // (patches only) Vertical flip
// flags hacked in scrn (not supported by all functions (see src))
// patch scaling uses bits 9 and 10
@ -168,6 +171,19 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue);
#define V_NOSCALESTART 0x40000000 // don't scale x, y, start coords
#define V_SPLITSCREEN 0x80000000 // Add half of screen width or height automatically depending on player number
void V_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 dupy);
struct cliprect_t
{
fixed_t left, right, top, bottom;
INT32 flags;
boolean enabled;
};
const cliprect_t *V_GetClipRect(void);
void V_SetClipRect(fixed_t x, fixed_t y, fixed_t w, fixed_t h, INT32 flags);
void V_ClearClipRect(void);
// defines for old functions
#define V_DrawPatch(x,y,s,p) V_DrawFixedPatch((x)<<FRACBITS, (y)<<FRACBITS, FRACUNIT, s|V_NOSCALESTART|V_NOSCALEPATCH, p, NULL)
#define V_DrawTranslucentMappedPatch(x,y,s,p,c) V_DrawFixedPatch((x)<<FRACBITS, (y)<<FRACBITS, FRACUNIT, s, p, c)