diff --git a/src/hardware/Sourcefile b/src/hardware/Sourcefile index 1c05de76cca6d71251023e3e9e7bdde7d8cffaab..0a6279f4580d3b5c613b081dc6c6592c916c61bf 100644 --- a/src/hardware/Sourcefile +++ b/src/hardware/Sourcefile @@ -10,4 +10,5 @@ hw_md3load.c hw_model.c u_list.c hw_batching.c +hw_splitpoly.c r_opengl/r_opengl.c diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index 4db69ff8b130b00eb46c403f8a47a8c86e535947..32086c51d70a0ecad6789697e2e4a9ee2248f9f9 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -13,6 +13,7 @@ #include "../doomstat.h" #ifdef HWRENDER #include "hw_glob.h" +#include "hw_splitpoly.h" #include "../r_local.h" #include "../z_zone.h" #include "../console.h" @@ -35,12 +36,6 @@ extrasubsector_t *extrasubsectors = NULL; static size_t totsubsectors; size_t addsubsector; -typedef struct -{ - float x, y; - float dx, dy; -} fdivline_t; - // ========================================================================== // FLOOR & CEILING CONVEX POLYS GENERATION // ========================================================================== @@ -164,7 +159,7 @@ static void HWR_FreePoly(poly_t *poly) // with the polygon segment // static float bspfrac; -static polyvertex_t *fracdivline(fdivline_t *bsp, polyvertex_t *v1, +static polyvertex_t *fracdivline(FDivLine *bsp, polyvertex_t *v1, polyvertex_t *v2) { static polyvertex_t pt; @@ -216,32 +211,11 @@ static polyvertex_t *fracdivline(fdivline_t *bsp, polyvertex_t *v1, // point. Note: hardcoded value, 1.0f could be anything else. static boolean SameVertice (polyvertex_t *p1, polyvertex_t *p2) { -#if 0 - float diff; - diff = p2->x - p1->x; - if (diff < -1.5f || diff > 1.5f) - return false; - diff = p2->y - p1->y; - if (diff < -1.5f || diff > 1.5f) - return false; -#elif 0 - if (p1->x != p2->x) - return false; - if (p1->y != p2->y) - return false; -#elif 0 - if (fabsf( p2->x - p1->x ) > 1.0E-36f ) - return false; - if (fabsf( p2->y - p1->y ) > 1.0E-36f ) - return false; -#else -#define DIVLINE_VERTEX_DIFF 0.45f float ep = DIVLINE_VERTEX_DIFF; if (fabsf( p2->x - p1->x ) > ep ) return false; if (fabsf( p2->y - p1->y ) > ep ) return false; -#endif // p1 and p2 are considered the same vertex return true; } @@ -252,7 +226,7 @@ static boolean SameVertice (polyvertex_t *p1, polyvertex_t *p2) // frontpoly : polygon on right side of bsp line // backpoly : polygon on left side // -static void SplitPoly (fdivline_t *bsp, //splitting parametric line +static void SplitPoly (FDivLine *bsp, //splitting parametric line poly_t *poly, //the convex poly we split poly_t **frontpoly, //return one poly here poly_t **backpoly) //return the other here @@ -435,7 +409,7 @@ static poly_t *CutOutSubsecPoly(seg_t *lseg, INT32 count, poly_t *poly) p1 = {0, 0, 0}, p2 = {0, 0, 0}; float fracs = 0.0f; - fdivline_t cutseg; // x, y, dx, dy as start of node_t struct + FDivLine cutseg; // x, y, dx, dy as start of node_t struct poly_t *temppoly; @@ -566,7 +540,7 @@ static inline void HWR_SubsecPoly(INT32 num, poly_t *poly) // the bsp divline have not enouth presition // search for the segs source of this divline -static inline void SearchDivline(node_t *bsp, fdivline_t *divline) +static inline void SearchDivline(node_t *bsp, FDivLine *divline) { divline->x = FIXED_TO_FLOAT(bsp->x); divline->y = FIXED_TO_FLOAT(bsp->y); @@ -609,7 +583,7 @@ static void WalkBSPNode(INT32 bspnum, poly_t *poly, UINT16 *leafnode, fixed_t *b { node_t *bsp; poly_t *backpoly, *frontpoly; - fdivline_t fdivline; + FDivLine fdivline; polyvertex_t *pt; INT32 i; diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 8df9b8916b2e563d7c1eebb16511b222a636a312..e4357f3bb6da10bdb31d66b9ad254bc41817ef05 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -72,7 +72,7 @@ typedef struct FColorARGB FColorARGB; typedef struct { FLOAT x,y; -} F2DCoord, v2d_t; +} F2DCoord; // Simple 3D vector typedef struct FVector @@ -80,11 +80,11 @@ typedef struct FVector FLOAT x,y,z; } FVector; -// ====================== -// wallVert3D -// ---------------------- -// :crab: IS GONE! :crab: -// ====================== +// Simple 2D line +typedef struct +{ + F2DCoord v1, v2; +} F2DLine; // ----------- // structures diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 8223705bd1afa4a30e6d1c1239693fcab98d8374..ecfaff7a4e533d540a7b3993e165b24b7dc1e4dc 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -20,6 +20,7 @@ #include "hw_main.h" #include "hw_glob.h" #include "hw_drv.h" +#include "hw_splitpoly.h" #include "../m_misc.h" //FIL_WriteFile() #include "../r_draw.h" //viewborderlump @@ -382,6 +383,344 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p HWD.pfnDrawPolygon(NULL, v, 4, flags); } +#if 0 +static FOutVector *Intersect2DRectangle(FOutVector *v, F2DLine *line, INT32 *numpts, boolean useTop) +{ + FOutVector *frontpoly, *backpoly; + INT32 frontpts = 0, backpts = 0, i; + + FOutVector *toppoly = NULL; + INT32 toppts = 0; + + if (!HWR_SplitPolygon(line, v, *numpts, &frontpoly, &frontpts, &backpoly, &backpts)) + return v; + + for (i = 0; i < frontpts; i++) + { + if ((useTop && frontpoly[i].y < (INT32)line->v1.y) + || (!useTop && frontpoly[i].y >= (INT32)line->v1.y)) + { + toppoly = frontpoly; + toppts = frontpts; + } + else + { + toppoly = backpoly; + toppts = backpts; + break; + } + } + + *numpts = toppts; + return toppoly; +} +#endif + +void HWR_DrawRotatedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, angle_t angle, INT32 option, const UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h) +{ + FOutVector v[4]; + FOutVector *vPtr = v; + INT32 numpts = 4; + FBITFIELD flags; + float cx = FIXED_TO_FLOAT(x); + float cy = FIXED_TO_FLOAT(y); + float ang = ANG2RAD(angle); + float offsetx, offsety; + float stex[2]; + UINT8 alphalevel = ((option & V_ALPHAMASK) >> V_ALPHASHIFT); + GLPatch_t *hwrPatch; + INT32 i; + +// 3--2 +// | /| +// |/ | +// 0--1 + float dupx, dupy, fscalew, fscaleh, fwidth, fheight; + + UINT8 perplayershuffle = 0; + + if (alphalevel >= 10 && alphalevel < 13) + return; + + // make patch ready in hardware cache + if (!colormap) + HWR_GetPatch(gpatch); + else + HWR_GetMappedPatch(gpatch, colormap); + + hwrPatch = ((GLPatch_t *)gpatch->hardware); + + dupx = (float)vid.dupx; + dupy = (float)vid.dupy; + + switch (option & V_SCALEPATCHMASK) + { + case V_NOSCALEPATCH: + dupx = dupy = 1.0f; + break; + case V_SMALLSCALEPATCH: + dupx = (float)vid.smalldupx; + dupy = (float)vid.smalldupy; + break; + case V_MEDSCALEPATCH: + dupx = (float)vid.meddupx; + dupy = (float)vid.meddupy; + break; + } + + dupx = dupy = (dupx < dupy ? dupx : dupy); + fscalew = fscaleh = FIXED_TO_FLOAT(pscale); + if (vscale != pscale) + fscaleh = FIXED_TO_FLOAT(vscale); + + // left offset + if (option & V_FLIP) + offsetx = (float)(gpatch->width - gpatch->leftoffset) * fscalew; + else + offsetx = (float)(gpatch->leftoffset) * fscalew; + + // top offset + offsety = (float)(gpatch->topoffset) * fscaleh; + + cx -= offsetx; + cy -= offsety; + + offsetx *= dupx; + offsety *= dupy; + + 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)) + { + cx = cx * dupx; + cy = cy * dupy; + + if (!(option & V_SCALEPATCHMASK)) + { + // 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) + { + if (option & V_SNAPTORIGHT) + 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) + { + if (option & V_SNAPTOBOTTOM) + 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 = FIXED_TO_FLOAT(w); + fheight = FIXED_TO_FLOAT(h); + + if (sx + w > gpatch->width<<FRACBITS) + fwidth = FIXED_TO_FLOAT((gpatch->width<<FRACBITS) - sx); + + if (sy + h > gpatch->height<<FRACBITS) + fheight = FIXED_TO_FLOAT((gpatch->height<<FRACBITS) - sy); + + if (pscale != FRACUNIT || vscale != FRACUNIT || (splitscreen && option & V_PERPLAYER)) + { + fwidth *= fscalew * dupx; + fheight *= fscaleh * dupy; + } + else + { + fwidth *= dupx; + fheight *= dupy; + } + + // set the polygon vertices to the right positions + v[0].x = v[3].x = 0.0f; + v[2].x = v[1].x = fwidth; + + v[0].y = v[1].y = 0.0f; + v[2].y = v[3].y = fheight; + + for (i = 0; i < 4; i++) + { + float temp_x = v[i].x - offsetx; + float temp_y = v[i].y - offsety; + + float rotated_x = (temp_x * cos(ang)) - (temp_y * sin(ang)); + float rotated_y = (temp_x * sin(ang)) + (temp_y * cos(ang)); + + v[i].x = rotated_x + offsetx + cx; + v[i].y = rotated_y + offsety; + + if (splitscreen && (option & V_PERPLAYER)) + v[i].y /= 2; + + v[i].y += cy; + } + + stex[0] = (FIXED_TO_FLOAT(sx)/(float)(gpatch->width))*hwrPatch->max_s; + if (sx + w > gpatch->width<<FRACBITS) + stex[1] = hwrPatch->max_s; + else + stex[1] = (FIXED_TO_FLOAT(sx+w)/(float)(gpatch->width))*hwrPatch->max_s; + + if (option & V_FLIP) + { + v[2].s = v[1].s = stex[0]; + v[0].s = v[3].s = stex[1]; + } + else + { + v[0].s = v[3].s = stex[0]; + v[2].s = v[1].s = stex[1]; + } + + v[0].t = v[1].t = (FIXED_TO_FLOAT(sy)/(float)(gpatch->height))*hwrPatch->max_t; + if (sy + h > gpatch->height<<FRACBITS) + v[2].t = v[3].t = hwrPatch->max_t; + else + v[2].t = v[3].t = (FIXED_TO_FLOAT(sy+h)/(float)(gpatch->height))*hwrPatch->max_t; + +#if 0 + // Auto-crop at splitscreen borders! + if (splitscreen && (option & V_PERPLAYER)) + { + boolean p1 = (stplyr == &players[displayplayer]); + boolean visible = false; + + F2DLine line; + + line.v1.x = 0.0; + line.v2.x = vid.width; + + line.v1.y = line.v2.y = vid.height / 2; + + vPtr = Intersect2DRectangle(v, &line, &numpts, p1); + if (!numpts) + return; + + for (i = 0; i < numpts; i++) + { + if ((p1 && vPtr[i].y < vid.height / 2) || (!p1 && vPtr[i].y >= vid.height / 2)) + { + visible = true; + break; + } + } + + if (!visible) + return; + } +#endif + + for (i = 0; i < numpts; i++) + { + vPtr[i].x = -1 + (vPtr[i].x / (vid.width/2)); + vPtr[i].y = 1 - (vPtr[i].y / (vid.height/2)); + vPtr[i].z = 1.0f; + } + + flags = PF_Translucent|PF_NoDepthTest; + + if (option & V_WRAPX) + flags |= PF_ForceWrapX; + if (option & V_WRAPY) + flags |= PF_ForceWrapY; + + // clip it since it is used for bunny scroll in doom I + if (alphalevel) + { + FSurfaceInfo Surf; + Surf.PolyColor.s.red = Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0xff; + if (alphalevel == 13) Surf.PolyColor.s.alpha = softwaretranstogl_lo[st_translucency]; + else if (alphalevel == 14) Surf.PolyColor.s.alpha = softwaretranstogl[st_translucency]; + else if (alphalevel == 15) Surf.PolyColor.s.alpha = softwaretranstogl_hi[st_translucency]; + else Surf.PolyColor.s.alpha = softwaretranstogl[10-alphalevel]; + flags |= PF_Modulated; + HWD.pfnDrawPolygon(&Surf, vPtr, numpts, flags); + } + else + HWD.pfnDrawPolygon(NULL, vPtr, numpts, flags); +} + 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]; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index a55555ef4619f7058575f5233711738b1dfc5666..d189c6c83cab585f3fee29d00e25ba22ec4cbe02 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1042,7 +1042,7 @@ static void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf) static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { FOutVector wallVerts[4]; - v2d_t vs, ve; // start, end vertices of 2d line (view from above) + F2DCoord vs, ve; // start, end vertices of 2d line (view from above) fixed_t worldtop, worldbottom; fixed_t worldhigh = 0, worldlow = 0; diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index b751b2a6e1c7698663e353c56d49e778e81fb7f0..60e28994e8026814373331976540d2eeeccf3878 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -39,6 +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_DrawRotatedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, angle_t angle, INT32 option, const UINT8 *colormap, 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); diff --git a/src/hardware/hw_splitpoly.c b/src/hardware/hw_splitpoly.c new file mode 100644 index 0000000000000000000000000000000000000000..4dcc4cfa41c8adade7201d55ac8ec8fa0a31133e --- /dev/null +++ b/src/hardware/hw_splitpoly.c @@ -0,0 +1,253 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file hw_splitpoly.c +/// \brief Convex polygon splitting + +#include "../doomdef.h" +#include "../doomstat.h" + +#ifdef HWRENDER +#include "hw_glob.h" +#include "hw_splitpoly.h" + +static FOutVector *IntersectLines (FOutVector *v1, FOutVector *v2, F2DLine *line, float *outfrac) +{ + static FOutVector pt; + double frac; + double num; + double den; + double v1x,v1y,v1dx,v1dy; + double v2x,v2y,v2dx,v2dy; + + // a segment of a polygon + v1x = v1->x; + v1y = v1->y; + v1dx = v2->x - v1->x; + v1dy = v2->y - v1->y; + + // the intersection line + v2x = line->v1.x; + v2y = line->v1.y; + v2dx = line->v2.x - line->v1.x; + v2dy = line->v2.y - line->v1.y; + + den = v2dy*v1dx - v2dx*v1dy; + if (fabsf((float)den) < 1.0E-36f) // avoid checking exactly for 0.0 + return NULL; // parallel + + // first check the frac along the polygon segment, + // (do not accept hit with the extensions) + num = (v2x - v1x)*v2dy + (v1y - v2y)*v2dx; + frac = num / den; + if (frac < 0.0l || frac > 1.0l) + return NULL; + + // now get the frac along the line + // which is useful to determine what is left, what is right + num = (v2x - v1x)*v1dy + (v1y - v2y)*v1dx; + frac = num / den; + *outfrac = (float)frac; + + // find the interception point along the partition line + pt.x = (float)(v2x + v2dx*frac); + pt.y = (float)(v2y + v2dy*frac); + + return &pt; +} + +// if two vertice coords have a x and/or y difference +// of less or equal than 1 FRACUNIT, they are considered the same +// point. Note: hardcoded value, 1.0f could be anything else. +static boolean SameVertice (FOutVector *p1, FOutVector *p2) +{ + float ep = DIVLINE_VERTEX_DIFF; + if (fabsf( p2->x - p1->x ) > ep ) + return false; + if (fabsf( p2->y - p1->y ) > ep ) + return false; + // p1 and p2 are considered the same vertex + return true; +} + +// Splits a convex polygon into two convex polygons +boolean HWR_SplitPolygon (F2DLine *line, + FOutVector *poly, INT32 numpts, + FOutVector **frontpoly, INT32 *frontpts, + FOutVector **backpoly, INT32 *backpts) +{ + INT32 i, j; + FOutVector *pv; + + INT32 ps = -1, pe = -1; + INT32 nptfront, nptback; + FOutVector vs = {0,0,0,0,0}; + FOutVector ve = {0,0,0,0,0}; + FOutVector lastpv = {0,0,0,0,0}; + float fracs = 0.0f, frace = 0.0f; + INT32 psonline = 0, peonline = 0; + + static FOutVector polyfront[16]; + static FOutVector polyback[16]; + + for (i = 0; i < numpts; i++) + { + float frac; + + j = i + 1; + if (j == numpts) j = 0; + + // start & end points + pv = IntersectLines(&poly[i], &poly[j], line, &frac); + + if (pv == NULL) + continue; + + if (ps < 0) + { + // first point + ps = i; + vs = *pv; + fracs = frac; + } + else + { + // the partition line traverse a junction between two segments + // or the two points are so close, they can be considered as one + // thus, don't accept, since split 2 must be another vertex + if (SameVertice(pv, &lastpv)) + { + if (pe < 0) + { + ps = i; + psonline = 1; + } + else + { + pe = i; + peonline = 1; + } + } + else + { + if (pe < 0) + { + pe = i; + ve = *pv; + frace = frac; + } + else + { + // a frac, not same vertice as last one + // we already got pt2 so pt 2 is not on the line, + // so we probably got back to the start point + // which is on the line + if (SameVertice(pv, &vs)) + psonline = 1; + break; + } + } + } + + // remember last point intercept to detect identical points + lastpv = *pv; + } + + // no split: the partition line is either parallel and + // aligned with one of the poly segments, or the line is totally + // out of the polygon and doesn't traverse it + if (ps < 0 || pe < 0) + { + *frontpoly = poly; + *frontpts = numpts; + *backpoly = NULL; + *backpts = 0; + return false; + } + else if (pe <= ps) + { + *frontpoly = NULL; + *frontpts = 0; + *backpoly = NULL; + *backpts = 0; + return false; + } + + // number of points on each side, _not_ counting those + // that may lie just one the line + nptback = pe - ps - peonline; + nptfront = numpts - peonline - psonline - nptback; + + if (nptback > 0) + { + *backpoly = polyback; + *backpts = 2 + nptback; + } + else + { + *backpoly = NULL; + *backpts = 0; + } + + if (nptfront > 0) + { + *frontpoly = polyfront; + *frontpts = 2 + nptfront; + } + else + { + *frontpoly = NULL; + *frontpts = 0; + } + + // generate FRONT poly + if (*frontpoly) + { + pv = *frontpoly; + *pv++ = vs; + *pv++ = ve; + i = pe; + do + { + if (++i == numpts) + i = 0; + *pv++ = poly[i]; + } while (i != ps && --nptfront); + } + + // generate BACK poly + if (*backpoly) + { + pv = *backpoly; + *pv++ = ve; + *pv++ = vs; + i = ps; + do + { + if (++i == numpts) + i = 0; + *pv++ = poly[i]; + } while (i != pe && --nptback); + } + + // make sure frontpoly is the one on the 'right' side + // of the partition line + if (fracs > frace) + { + FOutVector *swappoly = *backpoly; + INT32 swappts = *backpts; + *backpoly = *frontpoly; + *backpts = *frontpts; + *frontpoly = swappoly; + *frontpts = swappts; + } + + return true; +} + +#endif diff --git a/src/hardware/hw_splitpoly.h b/src/hardware/hw_splitpoly.h new file mode 100644 index 0000000000000000000000000000000000000000..e218ffce108181136f1988232ed783ab4540f669 --- /dev/null +++ b/src/hardware/hw_splitpoly.h @@ -0,0 +1,28 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file hw_splitpoly.h +/// \brief Convex polygon splitting + +#ifndef __HWR_SPLITPOLY_H__ +#define __HWR_SPLITPOLY_H__ + +#define DIVLINE_VERTEX_DIFF 0.45f + +typedef struct +{ + float x, y; + float dx, dy; +} FDivLine; + +boolean HWR_SplitPolygon (F2DLine *line, + FOutVector *poly, INT32 numpts, + FOutVector **frontpoly, INT32 *frontpts, + FOutVector **backpoly, INT32 *backpts); + +#endif // __HWR_SPLITPOLY_H__ diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 0a8081fbc159338ec04e8e2ca4291d198a7664d6..6b37d37f066cc0fe9f34de3dd7115226e0c506bc 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -725,6 +725,35 @@ static int libd_drawStretched(lua_State *L) return 0; } +static int libd_drawRotated(lua_State *L) +{ + fixed_t x, y, hscale, vscale; + angle_t angle; + 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"); + angle = luaL_checkangle(L, 5); + patch = *((patch_t **)luaL_checkudata(L, 6, META_PATCH)); + flags = luaL_optinteger(L, 7, 0); + if (!lua_isnoneornil(L, 8)) + colormap = *((UINT8 **)luaL_checkudata(L, 8, META_COLORMAP)); + + flags &= ~V_PARAMMASK; // Don't let crashes happen. + + V_DrawRotatedPatch(x, y, hscale, vscale, angle, flags, patch, colormap, 0, 0, patch->width<<FRACBITS, patch->height<<FRACBITS); + return 0; +} + static int libd_drawCropped(lua_State *L) { fixed_t x, y, hscale, vscale, sx, sy, w, h; @@ -1226,6 +1255,7 @@ static luaL_Reg lib_draw[] = { {"draw", libd_draw}, {"drawScaled", libd_drawScaled}, {"drawStretched", libd_drawStretched}, + {"drawRotated", libd_drawRotated}, {"drawCropped", libd_drawCropped}, {"drawNum", libd_drawNum}, {"drawPaddedNum", libd_drawPaddedNum}, diff --git a/src/v_video.c b/src/v_video.c index c3993854403fe87db28c06e18705a69f01932a84..4562c4b002e42becc2d594527d136051c7ff63ba 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -490,23 +490,55 @@ static UINT8 hudminusalpha[11] = { 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5}; static const UINT8 *v_colormap = NULL; static const UINT8 *v_translevel = NULL; +#define STANDARDPDRAW(px) px +#define MAPPEDPDRAW(px) *(v_colormap + px) +#define TRANSLUCENTPDRAW(px) *(v_translevel + ((px<<8)&0xff00) + (*dest&0xff)) +#define TRANSMAPPEDPDRAW(px) *(v_translevel + (((*(v_colormap + px))<<8)&0xff00) + (*dest&0xff)) + static inline UINT8 standardpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs) { - (void)dest; return source[ofs>>FRACBITS]; + (void)dest; return STANDARDPDRAW(source[ofs>>FRACBITS]); } static inline UINT8 mappedpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs) { - (void)dest; return *(v_colormap + source[ofs>>FRACBITS]); + (void)dest; return MAPPEDPDRAW(source[ofs>>FRACBITS]); } static inline UINT8 translucentpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs) { - return *(v_translevel + ((source[ofs>>FRACBITS]<<8)&0xff00) + (*dest&0xff)); + return TRANSLUCENTPDRAW(source[ofs>>FRACBITS]); } static inline UINT8 transmappedpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs) { - return *(v_translevel + (((*(v_colormap + source[ofs>>FRACBITS]))<<8)&0xff00) + (*dest&0xff)); + return TRANSMAPPEDPDRAW(source[ofs>>FRACBITS]); +} + +// Used in V_DrawRotatedPatch. +static inline UINT8 standardpdrawspan(const UINT8 *dest, const UINT16 *source, fixed_t ofs) +{ + UINT8 px = (source[ofs>>FRACBITS] & 0xFF); + (void)dest; return STANDARDPDRAW(px); +} +static inline UINT8 mappedpdrawspan(const UINT8 *dest, const UINT16 *source, fixed_t ofs) +{ + UINT8 px = (source[ofs>>FRACBITS] & 0xFF); + (void)dest; return MAPPEDPDRAW(px); +} +static inline UINT8 translucentpdrawspan(const UINT8 *dest, const UINT16 *source, fixed_t ofs) +{ + UINT8 px = (source[ofs>>FRACBITS] & 0xFF); + return TRANSLUCENTPDRAW(px); +} +static inline UINT8 transmappedpdrawspan(const UINT8 *dest, const UINT16 *source, fixed_t ofs) +{ + UINT8 px = (source[ofs>>FRACBITS] & 0xFF); + return TRANSMAPPEDPDRAW(px); } +#undef STANDARDPDRAW +#undef MAPPEDPDRAW +#undef TRANSLUCENTPDRAW +#undef TRANSMAPPEDPDRAW + // Draws a patch scaled to arbitrary size. void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap) { @@ -808,6 +840,473 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca } } +struct rotationraster { + fixed_t startcol, stopcol; + vector2_t *pstart, *pstop; + fixed_t srcregion[4]; + fixed_t invrow, invcol; + fixed_t invcos, invsin; + fixed_t colfrac, rowfrac; + UINT8 *desttop; + patch_t *patch; + UINT8 (*patchdrawfunc)(const UINT8*, const UINT16*, fixed_t); +}; + +static struct rotationraster v_rotationraster; + +static void RasterizeRotatedSpan(fixed_t row) +{ + struct rotationraster *r = &v_rotationraster; + UINT16 *source = r->patch->flats[0]; + + // Precalculate sine and cosine for this row + fixed_t rowcos = FixedMul(r->invrow, r->invcos); + fixed_t rowsin = FixedMul(r->invrow, r->invsin); + + UINT8 *deststart = r->desttop + (row * vid.width); // Pointer to row + UINT8 *dest = deststart + r->startcol; // Pointer to starting column + UINT8 *destend = deststart + r->stopcol; // Pointer to ending column + + for (; dest <= destend; dest++, r->startcol++, r->invcol += FRACUNIT) + { + vector2_t srcpos; + UINT16 *srcline; + UINT16 srcpx; + + if (r->startcol < 0) + continue; + + // Wherever it is + srcpos.x = FixedMul(r->invcol, r->invcos) - rowsin; + srcpos.y = FixedMul(r->invcol, r->invsin) + rowcos; + + if (srcpos.x < r->pstart->x || srcpos.x >= r->pstop->x + || srcpos.y < r->pstart->y || srcpos.y >=r-> pstop->y) + continue; + + // Scale it and offset by cropping position + srcpos.x = r->srcregion[0] + FixedMul(srcpos.x - r->pstart->x, r->colfrac); + srcpos.y = r->srcregion[1] + FixedMul(srcpos.y - r->pstart->y, r->rowfrac); + + srcline = &(source[(srcpos.y >> FRACBITS) * r->patch->width]); + srcpx = srcline[srcpos.x >> FRACBITS]; + + if (srcpx & 0xFF00) + *dest = r->patchdrawfunc(dest, srcline, srcpos.x); + } +} + +static void RasterizeRotatedSpanFlipX(fixed_t row) +{ + struct rotationraster *r = &v_rotationraster; + UINT16 *source = r->patch->flats[0]; + + // Precalculate sine and cosine for this row + fixed_t rowcos = FixedMul(r->invrow, r->invcos); + fixed_t rowsin = FixedMul(r->invrow, r->invsin); + + UINT8 *deststart = r->desttop + (row * vid.width); // Pointer to row + UINT8 *dest = deststart + r->startcol; // Pointer to starting column + UINT8 *destend = deststart + r->stopcol; // Pointer to ending column + + for (; dest <= destend; dest++, r->startcol++, r->invcol += FRACUNIT) + { + vector2_t srcpos; + UINT16 *srcline; + UINT16 srcpx; + + if (r->startcol < 0) + continue; + + // Wherever it is + srcpos.x = FixedMul(r->invcol, r->invcos) - rowsin; + srcpos.y = FixedMul(r->invcol, r->invsin) + rowcos; + + if (srcpos.x < r->pstart->x || srcpos.x >= r->pstop->x + || srcpos.y < r->pstart->y || srcpos.y >=r-> pstop->y) + continue; + + // Scale it and offset by cropping position + srcpos.x = r->srcregion[2] - FixedMul(srcpos.x - r->pstart->x, r->colfrac); + srcpos.y = r->srcregion[1] + FixedMul(srcpos.y - r->pstart->y, r->rowfrac); + + srcline = &(source[(srcpos.y >> FRACBITS) * r->patch->width]); + srcpx = srcline[srcpos.x >> FRACBITS]; + + if (srcpx & 0xFF00) + *dest = r->patchdrawfunc(dest, srcline, srcpos.x); + } +} + +// Draws a scaled, cropped, and rotated patch. +void V_DrawRotatedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, angle_t angle, INT32 scrn, patch_t *patch, const UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h) +{ + void (*spanraster)(fixed_t) = RasterizeRotatedSpan; + UINT32 alphalevel = 0; + fixed_t offsetx = 0, offsety = 0; + + INT32 dupx, dupy; + INT32 startrow = 0; + INT32 stoprow = vid.height; + fixed_t pwidth, pheight; // patch width and height + fixed_t destrow, destcol; + fixed_t invcol, invrow; + + boolean perplayer = (splitscreen && (scrn & V_PERPLAYER)); + UINT8 perplayershuffle = 0; + fixed_t invfrac = FRACUNIT; + + vector2_t rasterstart, rasterstop; + vector2_t patchstart, patchstop; + + struct rotationraster *r = &v_rotationraster; + + if (!angle) + { + V_DrawCroppedPatch(x, y, pscale, vscale, scrn, patch, colormap, sx, sy, w, h); + return; + } + + if (rendermode == render_none) + return; + +#ifdef HWRENDER + if (rendermode == render_opengl) + { + HWR_DrawRotatedPatch(patch, x, y, pscale, vscale, angle, scrn, colormap, sx, sy, w, h); + return; + } +#endif + + r->patchdrawfunc = standardpdrawspan; + + v_translevel = NULL; + if ((alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT))) + { + if (alphalevel == 13) + alphalevel = hudminusalpha[st_translucency]; + else if (alphalevel == 14) + alphalevel = 10 - st_translucency; + else if (alphalevel == 15) + alphalevel = hudplusalpha[st_translucency]; + + if (alphalevel >= 10) + return; // invis + + if (alphalevel) + { + v_translevel = R_GetTranslucencyTable(alphalevel); + r->patchdrawfunc = translucentpdrawspan; + } + } + + v_colormap = NULL; + if (colormap) + { + v_colormap = colormap; + r->patchdrawfunc = (v_translevel) ? transmappedpdrawspan : mappedpdrawspan; + } + + dupx = vid.dupx; + dupy = vid.dupy; + if (scrn & V_SCALEPATCHMASK) switch ((scrn & 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); + + // left offset + if (scrn & V_FLIP) + offsetx = FixedMul((patch->width - patch->leftoffset)<<FRACBITS, pscale) + 1; + else + offsetx = FixedMul(patch->leftoffset<<FRACBITS, pscale); + + // top offset + offsety = FixedMul(patch->topoffset<<FRACBITS, vscale); + + if (perplayer) + { + fixed_t adjusty = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1); + y >>= 1; +#ifdef QUADS + if (splitscreen > 1) // 3 or 4 players + { + fixed_t adjustx = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1)); + x >>= 1; + if (stplyr == &players[displayplayer]) + { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; + scrn &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT; + } + else if (stplyr == &players[secondarydisplayplayer]) + { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; + x += adjustx; + scrn &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT; + } + else if (stplyr == &players[thirddisplayplayer]) + { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; + y += adjusty; + scrn &= ~V_SNAPTOTOP|V_SNAPTORIGHT; + } + else //if (stplyr == &players[fourthdisplayplayer]) + { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; + x += adjustx; + y += adjusty; + scrn &= ~V_SNAPTOTOP|V_SNAPTOLEFT; + } + } + else +#endif + // 2 players + { + if (stplyr == &players[displayplayer]) + { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle = 1; + scrn &= ~V_SNAPTOBOTTOM; + } + else //if (stplyr == &players[secondarydisplayplayer]) + { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle = 2; + y += adjusty; + scrn &= ~V_SNAPTOTOP; + } + } + } + + r->desttop = screens[scrn&V_PARAMMASK]; + if (!r->desttop) + return; + + if (!(scrn & V_NOSCALESTART)) + { + x = FixedMul(x,dupx<<FRACBITS); + y = FixedMul(y,dupy<<FRACBITS); + + // Center it if necessary + if (!(scrn & V_SCALEPATCHMASK)) + { + if (vid.width != BASEVIDWIDTH * dupx) + { + // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, + // so center this imaginary screen + if (scrn & V_SNAPTORIGHT) + x += (vid.width - (BASEVIDWIDTH * dupx)) * FRACUNIT; + else if (!(scrn & V_SNAPTOLEFT)) + x += ((vid.width - (BASEVIDWIDTH * dupx)) / 2) * FRACUNIT; + if (perplayershuffle & 4) + x -= ((vid.width - (BASEVIDWIDTH * dupx)) / 4) * FRACUNIT; + else if (perplayershuffle & 8) + x += ((vid.width - (BASEVIDWIDTH * dupx)) / 4) * FRACUNIT; + } + if (vid.height != BASEVIDHEIGHT * dupy) + { + // same thing here + if (scrn & V_SNAPTOBOTTOM) + y += (vid.height - (BASEVIDHEIGHT * dupy)) * FRACUNIT; + else if (!(scrn & V_SNAPTOTOP)) + y += ((vid.height - (BASEVIDHEIGHT * dupy)) / 2) * FRACUNIT; + if (perplayershuffle & 1) + y -= ((vid.height - (BASEVIDHEIGHT * dupy)) / 4) * FRACUNIT; + else if (perplayershuffle & 2) + y += ((vid.height - (BASEVIDHEIGHT * dupy)) / 4) * FRACUNIT; + } + } + } + + // Auto-crop at splitscreen borders! + if (perplayer) + { +#ifdef QUADS + if (splitscreen > 1) // 3 or 4 players + { + #error Auto-cropping doesnt take quadscreen into account! Fix it! + // Hint: For player 1/2, copy player 1's code below. For player 3/4, copy player 2's code below + // For player 1/3 and 2/4, hijack the X wrap prevention lines? That's probably easiest + } + else +#endif + // 2 players + { + if (stplyr == &players[displayplayer]) // Player 1's screen, crop at the bottom + { + // Just put a big old stop sign halfway through the screen + stoprow = vid.height>>1; + } + else //if (stplyr == &players[secondarydisplayplayer]) // Player 2's screen, crop at the top + { + // Start drawing at the border + startrow = vid.height>>1; + } + } + } + + if (pscale != FRACUNIT) // scale width properly + { + pwidth = patch->width<<FRACBITS; + pwidth = FixedMul(pwidth, pscale); + pwidth = FixedMul(pwidth, dupx<<FRACBITS); + } + else + pwidth = patch->width * dupx<<FRACBITS; + + if (vscale != FRACUNIT) // scale height properly + { + pheight = patch->height<<FRACBITS; + pheight = FixedMul(pheight, vscale); + pheight = FixedMul(pheight, dupy<<FRACBITS); + } + else + pheight = patch->height * dupy<<FRACBITS; + + if (perplayer) + { + y += pheight / 2; + invfrac <<= 1; + } + + // X/Y scaling values + r->colfrac = FixedDiv(w, pwidth); + r->rowfrac = FixedDiv(h, pheight); + + // Determine patch region + offsetx = -FixedMul(offsetx, dupx<<FRACBITS); + offsety = -FixedMul(offsety, dupy<<FRACBITS); + + patchstart.x = offsetx; + patchstop.x = patchstart.x + pwidth; + patchstart.y = offsety; + patchstop.y = patchstart.y + pheight; + + // Determine region to rasterize into + rasterstart.x = patchstart.x; + rasterstart.y = patchstart.y; + rasterstop.x = patchstop.x; + rasterstop.y = patchstop.y; + +#define CALC_SIDE(sx, sy) { \ + fixed_t angcos = FINECOSINE(angle>>ANGLETOFINESHIFT); \ + fixed_t angsin = FINESINE(angle>>ANGLETOFINESHIFT); \ + fixed_t xcalc = FixedMul(sx, angcos) - FixedMul(sy, angsin); \ + fixed_t ycalc = FixedMul(sx, angsin) + FixedMul(sy, angcos); \ + if (rasterstart.x > xcalc) \ + rasterstart.x = xcalc; \ + if (rasterstop.x < xcalc) \ + rasterstop.x = xcalc; \ + if (rasterstart.y > ycalc) \ + rasterstart.y = ycalc; \ + if (rasterstop.y < ycalc) \ + rasterstop.y = ycalc; \ +} + + CALC_SIDE(patchstart.x, patchstart.y); + CALC_SIDE(patchstop.x, patchstart.y); + CALC_SIDE(patchstart.x, patchstop.y); + CALC_SIDE(patchstop.x, patchstop.y); + +#undef CALC_SIDE + + // Offset bounding box by the patch position + rasterstart.x += x; + rasterstart.y += y; + rasterstop.x += x; + rasterstop.y += y; + + if (rasterstart.x < 0 && rasterstop.x < 0) + return; + else if (rasterstart.y < startrow && rasterstop.y < startrow) + return; + else if (rasterstart.x>>FRACBITS >= vid.width && rasterstop.x>>FRACBITS >= vid.width) + return; + else if (rasterstart.y>>FRACBITS >= stoprow && rasterstop.y>>FRACBITS >= stoprow) + return; + else if (rasterstop.x < rasterstart.x || rasterstop.y < rasterstart.y) + return; + + rasterstop.x /= FRACUNIT; + rasterstop.y /= FRACUNIT; + + if (rasterstop.y >= stoprow) + rasterstop.y = stoprow - 1; + + destrow = rasterstart.y >> FRACBITS; + invrow = rasterstart.y - y; + + // Precalculated sine and cosine + angle = InvAngle(angle); + r->invcos = FINECOSINE(angle>>ANGLETOFINESHIFT); + r->invsin = FINESINE(angle>>ANGLETOFINESHIFT); + + Patch_GenerateFlat((r->patch = patch), 0); + + r->srcregion[0] = sx; + r->srcregion[1] = sy; + r->srcregion[2] = sx + w; + r->srcregion[3] = sy + h; + + r->pstart = &patchstart; + r->pstop = &patchstop; + + if (scrn & V_FLIP) + spanraster = RasterizeRotatedSpanFlipX; + + for (; destrow <= rasterstop.y; destrow++, invrow += invfrac) + { + fixed_t stopcol; + + if (destrow < startrow) + continue; + + destcol = rasterstart.x / FRACUNIT; + invcol = rasterstart.x - x; + stopcol = destcol + rasterstop.x; + + // Expand the ending column if the starting one is out of bounds + if (destcol < 0) + stopcol += -destcol; + + if (stopcol >= vid.width - 1) + stopcol = vid.width - 1; + + r->startcol = destcol; + r->stopcol = stopcol; + r->invrow = invrow; + r->invcol = invcol; + + spanraster(destrow); + } +} + // Draws a patch cropped and scaled to arbitrary size. 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) { diff --git a/src/v_video.h b/src/v_video.h index c10ab22cea8f56497f998aa449fb672b59f62f84..e4af33e1b560bd1e4d6ede2b281407fb215d2cfd 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -164,7 +164,9 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue); #define V_DrawTinyTranslucentPatch(x,y,s,p) V_DrawFixedPatch((x)<<FRACBITS, (y)<<FRACBITS, FRACUNIT/4, s, p, NULL) #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_DrawRotatedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, angle_t angle, INT32 scrn, patch_t *patch, const UINT8 *colormap, 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);