From 694804cd96cafb1bfb146406f775e2bd23b1fb7a Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 10 Sep 2022 21:27:37 -0700 Subject: [PATCH] Refactor hitbox renderer to project vissprites Properly accounts for portals (skyboxes). --- src/r_bbox.c | 46 ++++++--------- src/r_things.c | 155 ++++++++++++++++++++++++++++++++++++++++++------- src/r_things.h | 9 ++- 3 files changed, 161 insertions(+), 49 deletions(-) diff --git a/src/r_bbox.c b/src/r_bbox.c index e3b5216bf..bbac0f56b 100644 --- a/src/r_bbox.c +++ b/src/r_bbox.c @@ -165,11 +165,11 @@ draw_bbox_row } static UINT8 -get_bbox_color (mobj_t *thing) +get_bbox_color (vissprite_t *vis) { - UINT32 flags = thing->flags; + UINT32 flags = vis->mobjflags; - if (thing->player) + if (vis->mobj->player) return 255; // 0FF if (flags & (MF_NOCLIPTHING)) @@ -187,26 +187,21 @@ get_bbox_color (mobj_t *thing) return 0; // FFF } -void R_DrawThingBoundingBox(mobj_t *thing) +void R_DrawThingBoundingBox(vissprite_t *vis) { - fixed_t rs, rc; // radius offsets - fixed_t gx, gy; // origin - fixed_t tx, ty; // translated coordinates + // radius offsets + fixed_t rs = vis->scale; + fixed_t rc = vis->xscale; - struct bbox_config bb = {0}; + // translated coordinates + fixed_t tx = vis->gx; + fixed_t ty = vis->gy; - rs = FixedMul(thing->radius, viewsin); - rc = FixedMul(thing->radius, viewcos); - - gx = thing->x - viewx; - gy = thing->y - viewy; - - tx = FixedMul(gx, viewsin) - FixedMul(gy, viewcos); - ty = FixedMul(gx, viewcos) + FixedMul(gy, viewsin); - - bb.height = thing->height; - bb.tz = (thing->z + bb.height) - viewz; - bb.color = get_bbox_color(thing); + struct bbox_config bb = { + .height = vis->thingheight, + .tz = vis->texturemid, + .color = get_bbox_color(vis), + }; // 1--3 // | | @@ -214,18 +209,15 @@ void R_DrawThingBoundingBox(mobj_t *thing) // left - tx -= rs; - ty -= rc; - - draw_bbox_col(&bb, 0, tx + rc, ty - rs); // bottom + draw_bbox_col(&bb, 0, tx, ty); // bottom draw_bbox_col(&bb, 1, tx - rc, ty + rs); // top // right - tx += rs + rs; - ty += rc + rc; + tx += rs; + ty += rc; - draw_bbox_col(&bb, 2, tx + rc, ty - rs); // bottom + draw_bbox_col(&bb, 2, tx, ty); // bottom draw_bbox_col(&bb, 3, tx - rc, ty + rs); // top // connect all four columns diff --git a/src/r_things.c b/src/r_things.c index 65047176d..6e4062219 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1424,6 +1424,91 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, objectsdrawn++; } +static void R_ProjectBoundingBox(mobj_t *thing, vissprite_t *vis) +{ + fixed_t gx, gy; + fixed_t tx, tz; + + vissprite_t *box; + + if (!R_ThingBoundingBoxVisible(thing)) + { + return; + } + + // 1--3 + // | | + // 0--2 + + // start in the (0) corner + gx = thing->x - thing->radius - viewx; + gy = thing->y - thing->radius - viewy; + + tz = FixedMul(gx, viewcos) + FixedMul(gy, viewsin); + + // thing is behind view plane? + // if parent vis is visible, ignore this + if (!vis && (tz < FixedMul(MINZ, thing->scale))) + { + return; + } + + tx = FixedMul(gx, viewsin) - FixedMul(gy, viewcos); + + // too far off the side? + if (!vis && abs(tx) > FixedMul(tz, fovtan)<<2) + { + return; + } + + box = R_NewVisSprite(); + box->mobj = thing; + box->mobjflags = thing->flags; + box->thingheight = thing->height; + box->cut = SC_BBOX; + + box->gx = tx; + box->gy = tz; + + box->scale = 2 * FixedMul(thing->radius, viewsin); + box->xscale = 2 * FixedMul(thing->radius, viewcos); + + box->pz = thing->z; + box->pzt = box->pz + box->thingheight; + + box->gzt = box->pzt; + box->gz = box->pz; + box->texturemid = box->gzt - viewz; + + if (vis) + { + box->x1 = vis->x1; + box->x2 = vis->x2; + box->szt = vis->szt; + box->sz = vis->sz; + + box->sortscale = vis->sortscale; // link sorting to sprite + box->dispoffset = vis->dispoffset + 5; + + box->cut |= SC_LINKDRAW; + } + else + { + fixed_t xscale = FixedDiv(projection, tz); + fixed_t yscale = FixedDiv(projectiony, tz); + fixed_t top = (centeryfrac - FixedMul(box->texturemid, yscale)); + + box->x1 = (centerxfrac + FixedMul(box->gx, xscale)) / FRACUNIT; + box->x2 = box->x1; + + box->szt = top / FRACUNIT; + box->sz = (top + FixedMul(box->thingheight, yscale)) / FRACUNIT; + + box->sortscale = yscale; + box->dispoffset = 0; + } +} + // // R_ProjectSprite // Generates a vissprite for a thing @@ -2181,6 +2266,8 @@ static void R_ProjectSprite(mobj_t *thing) if (oldthing->shadowscale && cv_shadow.value) R_ProjectDropShadow(oldthing, vis, oldthing->shadowscale, basetx, basetz); + R_ProjectBoundingBox(oldthing, vis); + // Debug ++objectsdrawn; } @@ -2406,8 +2493,26 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) hoop_limit_dist = (fixed_t)(cv_drawdist_nights.value) << FRACBITS; for (thing = sec->thinglist; thing; thing = thing->snext) { - if (R_ThingVisibleWithinDist(thing, limit_dist, hoop_limit_dist)) - R_ProjectSprite(thing); + if (R_ThingWithinDist(thing, limit_dist, hoop_limit_dist)) + { + const INT32 oldobjectsdrawn = objectsdrawn; + + if (R_ThingVisible(thing)) + { + R_ProjectSprite(thing); + } + + // I'm so smart :^) + if (objectsdrawn == oldobjectsdrawn) + { + /* + Object is invisible OR is off screen but + render its bbox even if the latter because + radius could be bigger than sprite. + */ + R_ProjectBoundingBox(thing, NULL); + } + } } // no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off @@ -2495,6 +2600,10 @@ static void R_SortVisSprites(vissprite_t* vsprsortedhead, UINT32 start, UINT32 e if (dsfirst->cut & SC_SHADOW) continue; + // don't connect to your bounding box! + if (dsfirst->cut & SC_BBOX) + continue; + // don't connect if it's not the tracer if (dsfirst->mobj != ds->mobj) continue; @@ -2935,18 +3044,12 @@ static void R_DrawSprite(vissprite_t *spr) mfloorclip = spr->clipbot; mceilingclip = spr->cliptop; - if (spr->cut & SC_SPLAT) + if (spr->cut & SC_BBOX) + R_DrawThingBoundingBox(spr); + else if (spr->cut & SC_SPLAT) R_DrawFloorSplat(spr); else R_DrawVisSprite(spr); - - if (R_ThingBoundingBoxVisible(spr->mobj)) - { - // fuck you fuck you fuck you FUCK YOU - // (shadows are linked to their mobj) - if (!(spr->cut & SC_SHADOW)) - R_DrawThingBoundingBox(spr->mobj); - } } // Special drawer for precipitation sprites Tails 08-18-2002 @@ -3182,9 +3285,13 @@ void R_ClipSprites(drawseg_t* dsstart, portal_t* portal) for (; clippedvissprites < visspritecount; clippedvissprites++) { vissprite_t *spr = R_GetVisSprite(clippedvissprites); - INT32 x1 = (spr->cut & SC_SPLAT) ? 0 : spr->x1; - INT32 x2 = (spr->cut & SC_SPLAT) ? viewwidth : spr->x2; - R_ClipVisSprite(spr, x1, x2, dsstart, portal); + + if (!(spr->cut & SC_BBOX)) // Do not clip bounding boxes + { + INT32 x1 = (spr->cut & SC_SPLAT) ? 0 : spr->x1; + INT32 x2 = (spr->cut & SC_SPLAT) ? viewwidth : spr->x2; + R_ClipVisSprite(spr, x1, x2, dsstart, portal); + } } } @@ -3198,16 +3305,11 @@ boolean R_ThingVisible (mobj_t *thing) )); } -boolean R_ThingVisibleWithinDist (mobj_t *thing, +boolean R_ThingWithinDist (mobj_t *thing, fixed_t limit_dist, fixed_t hoop_limit_dist) { - fixed_t approx_dist; - - if (! R_ThingVisible(thing)) - return false; - - approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); + const fixed_t approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); if (thing->sprite == SPR_HOOP) { @@ -3223,6 +3325,17 @@ boolean R_ThingVisibleWithinDist (mobj_t *thing, return true; } +// For OpenGL, TODO: REMOVE!! +boolean R_ThingVisibleWithinDist (mobj_t *thing, + fixed_t limit_dist, + fixed_t hoop_limit_dist) +{ + if (! R_ThingVisible(thing)) + return false; + + return R_ThingWithinDist(thing, limit_dist, hoop_limit_dist); +} + /* Check if precipitation may be drawn from our current view. */ boolean R_PrecipThingVisible (precipmobj_t *precipthing, fixed_t limit_dist) diff --git a/src/r_things.h b/src/r_things.h index 4ba649c30..f1855dfd8 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -67,10 +67,13 @@ void R_InitSprites(void); void R_ClearSprites(void); boolean R_ThingBoundingBoxVisible(mobj_t *thing); -void R_DrawThingBoundingBox(mobj_t *thing); boolean R_ThingVisible (mobj_t *thing); +boolean R_ThingWithinDist (mobj_t *thing, + fixed_t draw_dist, + fixed_t nights_draw_dist); + boolean R_ThingVisibleWithinDist (mobj_t *thing, fixed_t draw_dist, fixed_t nights_draw_dist); @@ -135,6 +138,7 @@ typedef enum SC_SHADOW = 1<<10, SC_SHEAR = 1<<11, SC_SPLAT = 1<<12, + SC_BBOX = 1<<13, // masks SC_CUTMASK = SC_TOP|SC_BOTTOM, SC_FLAGMASK = ~SC_CUTMASK @@ -224,6 +228,9 @@ void R_ClipSprites(drawseg_t* dsstart, portal_t* portal); void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, portal_t* portal); boolean R_SpriteIsFlashing(vissprite_t *vis); + +void R_DrawThingBoundingBox(vissprite_t *spr); + UINT8 *R_GetSpriteTranslation(vissprite_t *vis); // ----------