From 029e79024ba33f5b9ebfb08bba2be328df64fe14 Mon Sep 17 00:00:00 2001 From: Zwip-Zwap Zapony Date: Fri, 11 Dec 2020 23:43:38 +0100 Subject: [PATCH] V_DrawCroppedPatch Lua exposure and improvements Separated X and Y scale, and added colormap argument Added V_*SCALEPATCH and V_PERPLAYER flags support Made sx,sy,w,h into fixed-point values Exposed to Lua as "v.drawCropped(...)" (Also fix HWR_DrawStretchyFixedPatch ignoring vscale without pscale) --- src/console.c | 4 +- src/hardware/hw_draw.c | 147 ++++++++++++++++++++++++++++++----------- src/hardware/hw_main.h | 2 +- src/lua_hudlib.c | 40 +++++++++++ src/m_menu.c | 2 +- src/v_video.c | 71 +++++++++++++------- src/v_video.h | 2 +- src/y_inter.c | 2 +- 8 files changed, 202 insertions(+), 68 deletions(-) diff --git a/src/console.c b/src/console.c index b19b8818d..bcf01c989 100644 --- a/src/console.c +++ b/src/console.c @@ -1736,8 +1736,8 @@ static void CON_DrawBackpic(void) } // Draw the patch. - V_DrawCroppedPatch(x << FRACBITS, 0, FRACUNIT, V_NOSCALESTART, con_backpic, - 0, ( BASEVIDHEIGHT - h ), BASEVIDWIDTH, h); + V_DrawCroppedPatch(x << FRACBITS, 0, FRACUNIT, FRACUNIT, V_NOSCALESTART, con_backpic, NULL, + 0, (BASEVIDHEIGHT - h) << FRACBITS, BASEVIDWIDTH << FRACBITS, h << FRACBITS); // Unlock the cached patch. W_UnlockCachedPatch(con_backpic); diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index c5d362520..0322e9d27 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -317,7 +317,7 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p } } - if (pscale != FRACUNIT || (splitscreen && option & V_PERPLAYER)) + if (pscale != FRACUNIT || vscale != FRACUNIT || (splitscreen && option & V_PERPLAYER)) { fwidth = (float)(gpatch->width) * fscalew * dupx; fheight = (float)(gpatch->height) * fscaleh * dupy; @@ -382,7 +382,7 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p HWD.pfnDrawPolygon(NULL, v, 4, flags); } -void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h) +void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h) { FOutVector v[4]; FBITFIELD flags; @@ -395,13 +395,19 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, // | /| // |/ | // 0--1 - float dupx, dupy, fscale, fwidth, fheight; + float dupx, dupy, fscalew, fscaleh, fwidth, fheight; + + UINT8 perplayershuffle = 0; if (alphalevel >= 10 && alphalevel < 13) return; // make patch ready in hardware cache - HWR_GetPatch(gpatch); + if (!colormap) + HWR_GetPatch(gpatch); + else + HWR_GetMappedPatch(gpatch, colormap); + hwrPatch = ((GLPatch_t *)gpatch->hardware); dupx = (float)vid.dupx; @@ -423,12 +429,80 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, } dupx = dupy = (dupx < dupy ? dupx : dupy); - fscale = FIXED_TO_FLOAT(pscale); + fscalew = fscaleh = FIXED_TO_FLOAT(pscale); + if (vscale != pscale) + fscaleh = FIXED_TO_FLOAT(vscale); - // fuck it, no GL support for croppedpatch v_perplayer right now. it's not like it's accessible to Lua or anything, and we only use it for menus... + cx -= (float)(gpatch->leftoffset) * fscalew; + cy -= (float)(gpatch->topoffset) * fscaleh; - cy -= (float)(gpatch->topoffset) * fscale; - cx -= (float)(gpatch->leftoffset) * fscale; + if (splitscreen && (option & V_PERPLAYER)) + { + float adjusty = ((option & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f; + fscaleh /= 2; + cy /= 2; +#ifdef QUADS + if (splitscreen > 1) // 3 or 4 players + { + float adjustx = ((option & V_NOSCALESTART) ? vid.width : BASEVIDWIDTH)/2.0f; + fscalew /= 2; + cx /= 2; + if (stplyr == &players[displayplayer]) + { + if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(option & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; + option &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT; + } + else if (stplyr == &players[secondarydisplayplayer]) + { + if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(option & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; + cx += adjustx; + option &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT; + } + else if (stplyr == &players[thirddisplayplayer]) + { + if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(option & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; + cy += adjusty; + option &= ~V_SNAPTOTOP|V_SNAPTORIGHT; + } + else if (stplyr == &players[fourthdisplayplayer]) + { + if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(option & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; + cx += adjustx; + cy += adjusty; + option &= ~V_SNAPTOTOP|V_SNAPTOLEFT; + } + } + else +#endif + // 2 players + { + if (stplyr == &players[displayplayer]) + { + if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle = 1; + option &= ~V_SNAPTOBOTTOM; + } + else //if (stplyr == &players[secondarydisplayplayer]) + { + if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle = 2; + cy += adjusty; + option &= ~V_SNAPTOTOP; + } + } + } if (!(option & V_NOSCALESTART)) { @@ -437,18 +511,9 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, if (!(option & V_SCALEPATCHMASK)) { - // if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT) - // cx and cy are possibly *slightly* off from float maths - // This is done before here compared to software because we directly alter cx and cy to centre - if (cx >= -0.1f && cx <= 0.1f && gpatch->width == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && gpatch->height == BASEVIDHEIGHT) - { - const column_t *column = (const column_t *)((const UINT8 *)(gpatch->columns) + (gpatch->columnofs[0])); - if (!column->topdelta) - { - const UINT8 *source = (const UINT8 *)(column) + 3; - HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); - } - } + // if it's meant to cover the whole screen, black out the rest + // no the patch is cropped do not do this ever + // centre screen if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f) { @@ -456,6 +521,10 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)); else if (!(option & V_SNAPTOLEFT)) cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/2; + if (perplayershuffle & 4) + cx -= ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/4; + else if (perplayershuffle & 8) + cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/4; } if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f) { @@ -463,23 +532,27 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)); else if (!(option & V_SNAPTOTOP)) cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/2; + if (perplayershuffle & 1) + cy -= ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/4; + else if (perplayershuffle & 2) + cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/4; } } } - fwidth = w; - fheight = h; + fwidth = FIXED_TO_FLOAT(w); + fheight = FIXED_TO_FLOAT(h); - if (fwidth > gpatch->width) - fwidth = gpatch->width; + if (sx + w > gpatch->width<width< gpatch->height) - fheight = gpatch->height; + if (sy + h > gpatch->height<height<width))*hwrPatch->max_s; - if (sx + w > gpatch->width) - v[2].s = v[1].s = hwrPatch->max_s - ((sx+w)/(float)(gpatch->width))*hwrPatch->max_s; + v[0].s = v[3].s = (FIXED_TO_FLOAT(sx)/(float)(gpatch->width))*hwrPatch->max_s; + if (sx + w > gpatch->width<max_s; else - v[2].s = v[1].s = ((sx+w)/(float)(gpatch->width))*hwrPatch->max_s; + v[2].s = v[1].s = (FIXED_TO_FLOAT(sx+w)/(float)(gpatch->width))*hwrPatch->max_s; - v[0].t = v[1].t = ((sy)/(float)(gpatch->height))*hwrPatch->max_t; - if (sy + h > gpatch->height) - v[2].t = v[3].t = hwrPatch->max_t - ((sy+h)/(float)(gpatch->height))*hwrPatch->max_t; + v[0].t = v[1].t = (FIXED_TO_FLOAT(sy)/(float)(gpatch->height))*hwrPatch->max_t; + if (sy + h > gpatch->height<max_t; else - v[2].t = v[3].t = ((sy+h)/(float)(gpatch->height))*hwrPatch->max_t; + v[2].t = v[3].t = (FIXED_TO_FLOAT(sy+h)/(float)(gpatch->height))*hwrPatch->max_t; flags = PF_Translucent|PF_NoDepthTest; diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 4ad09aa3d..708227585 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -39,7 +39,7 @@ void HWR_InitTextureMapping(void); void HWR_SetViewSize(void); void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option); void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap); -void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t scale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); +void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); void HWR_MakePatch(const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap); void HWR_CreatePlanePolygons(INT32 bspnum); void HWR_CreateStaticLightmaps(INT32 bspnum); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index e58cd4a58..20eb33f37 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -660,6 +660,45 @@ static int libd_drawStretched(lua_State *L) return 0; } +static int libd_drawCropped(lua_State *L) +{ + fixed_t x, y, hscale, vscale, sx, sy, w, h; + INT32 flags; + patch_t *patch; + const UINT8 *colormap = NULL; + + HUDONLY + x = luaL_checkinteger(L, 1); + y = luaL_checkinteger(L, 2); + hscale = luaL_checkinteger(L, 3); + if (hscale < 0) + return luaL_error(L, "negative horizontal scale"); + vscale = luaL_checkinteger(L, 4); + if (vscale < 0) + return luaL_error(L, "negative vertical scale"); + patch = *((patch_t **)luaL_checkudata(L, 5, META_PATCH)); + flags = luaL_checkinteger(L, 6); + if (!lua_isnoneornil(L, 7)) + colormap = *((UINT8 **)luaL_checkudata(L, 7, META_COLORMAP)); + sx = luaL_checkinteger(L, 8); + if (sx < 0) // Don't crash. Now, we could do "x-=sx*FRACUNIT; sx=0;" here... + return luaL_error(L, "negative crop sx"); + sy = luaL_checkinteger(L, 9); + if (sy < 0) // ...but it's more truthful to just deny it, as negative values would crash + return luaL_error(L, "negative crop sy"); + w = luaL_checkinteger(L, 10); + if (w < 0) // Again, don't crash + return luaL_error(L, "negative crop w"); + h = luaL_checkinteger(L, 11); + if (h < 0) + return luaL_error(L, "negative crop h"); + + flags &= ~V_PARAMMASK; // Don't let crashes happen. + + V_DrawCroppedPatch(x, y, hscale, vscale, flags, patch, colormap, sx, sy, w, h); + return 0; +} + static int libd_drawNum(lua_State *L) { INT32 x, y, flags, num; @@ -1084,6 +1123,7 @@ static luaL_Reg lib_draw[] = { {"draw", libd_draw}, {"drawScaled", libd_drawScaled}, {"drawStretched", libd_drawStretched}, + {"drawCropped", libd_drawCropped}, {"drawNum", libd_drawNum}, {"drawPaddedNum", libd_drawPaddedNum}, {"drawFill", libd_drawFill}, diff --git a/src/m_menu.c b/src/m_menu.c index 5ec9132f7..003e308b0 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4183,7 +4183,7 @@ static void M_DrawStaticBox(fixed_t x, fixed_t y, INT32 flags, fixed_t w, fixed_ if (staticalong > pw) // simplified for base LSSTATIC staticalong -= pw; - V_DrawCroppedPatch(x<> 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); + fdup = vdup = FixedMul(dupx<topoffset<leftoffset<topoffset<>= 1; + vdup >>= 1; rowfrac <<= 1; y >>= 1; - sy >>= 1; - h >>= 1; #ifdef QUADS if (splitscreen > 1) // 3 or 4 players { fixed_t adjustx = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1)); + fdup >>= 1; colfrac <<= 1; x >>= 1; - sx >>= 1; - w >>= 1; if (stplyr == &players[displayplayer]) { if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) @@ -896,7 +921,6 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) perplayershuffle |= 8; x += adjustx; - sx += adjustx; scrn &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT; } else if (stplyr == &players[thirddisplayplayer]) @@ -906,7 +930,6 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) perplayershuffle |= 4; y += adjusty; - sy += adjusty; scrn &= ~V_SNAPTOTOP|V_SNAPTORIGHT; } else //if (stplyr == &players[fourthdisplayplayer]) @@ -916,9 +939,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) perplayershuffle |= 8; x += adjustx; - sx += adjustx; y += adjusty; - sy += adjusty; scrn &= ~V_SNAPTOTOP|V_SNAPTOLEFT; } } @@ -937,7 +958,6 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) perplayershuffle |= 2; y += adjusty; - sy += adjusty; scrn &= ~V_SNAPTOTOP; } } @@ -950,7 +970,8 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ deststop = desttop + vid.rowbytes * vid.height; - if (scrn & V_NOSCALESTART) { + if (scrn & V_NOSCALESTART) + { x >>= FRACBITS; y >>= FRACBITS; desttop += (y*vid.width) + x; @@ -998,7 +1019,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ desttop += (y*vid.width) + x; } - for (col = sx<>FRACBITS) < patch->width && ((col>>FRACBITS) - sx) < w; col += colfrac, ++x, desttop++) + for (col = sx; (col>>FRACBITS) < patch->width && (col - sx) < w; col += colfrac, ++x, desttop++) { INT32 topdelta, prevdelta = -1; if (x < 0) // don't draw off the left of the screen (WRAP PREVENTION) @@ -1015,15 +1036,15 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ prevdelta = topdelta; source = (const UINT8 *)(column) + 3; dest = desttop; - if (topdelta-sy > 0) + if ((topdelta< 0) { - dest += FixedInt(FixedMul((topdelta-sy)<>FRACBITS) < column->length && (((ofs>>FRACBITS) - sy) + topdelta) < h; ofs += rowfrac) + for (; dest < deststop && (ofs>>FRACBITS) < column->length && ((ofs - sy) + (topdelta<= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION) *dest = patchdrawfunc(dest, source, ofs); diff --git a/src/v_video.h b/src/v_video.h index 8a18f82ad..f3f169079 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -165,7 +165,7 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue); #define V_DrawSciencePatch(x,y,s,p,sc) V_DrawFixedPatch(x,y,sc,s,p,NULL) #define V_DrawFixedPatch(x,y,sc,s,p,c) V_DrawStretchyFixedPatch(x,y,sc,sc,s,p,c) void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap); -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); +void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT16 skincolor); diff --git a/src/y_inter.c b/src/y_inter.c index 061cbb5e1..f2f676919 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -212,7 +212,7 @@ static void Y_IntermissionTokenDrawer(void) calc = (lowy - y)*2; if (calc > 0) - V_DrawCroppedPatch(32<width, calc); + V_DrawCroppedPatch(32<width<