Refactor hitbox renderer to project vissprites

Properly accounts for portals (skyboxes).
This commit is contained in:
James R 2022-09-10 21:27:37 -07:00
parent 082d9206e8
commit 5a58b3ca3a
3 changed files with 169 additions and 61 deletions

View file

@ -14,7 +14,6 @@
#include "doomdef.h" #include "doomdef.h"
#include "command.h" #include "command.h"
#include "r_fps.h"
#include "r_local.h" #include "r_local.h"
#include "screen.h" // cv_renderhitbox #include "screen.h" // cv_renderhitbox
#include "v_video.h" // V_DrawFill #include "v_video.h" // V_DrawFill
@ -166,11 +165,11 @@ draw_bbox_row
} }
static UINT8 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 return 255; // 0FF
if (flags & (MF_NOCLIPTHING)) if (flags & (MF_NOCLIPTHING))
@ -188,39 +187,21 @@ get_bbox_color (mobj_t *thing)
return 0; // FFF return 0; // FFF
} }
void R_DrawThingBoundingBox(mobj_t *thing) void R_DrawThingBoundingBox(vissprite_t *vis)
{ {
fixed_t rs, rc; // radius offsets // radius offsets
fixed_t gx, gy; // origin fixed_t rs = vis->scale;
fixed_t tx, ty; // translated coordinates fixed_t rc = vis->xscale;
// uncapped/interpolation // translated coordinates
interpmobjstate_t interp = {0}; fixed_t tx = vis->gx;
fixed_t ty = vis->gy;
struct bbox_config bb = {0}; struct bbox_config bb = {
.height = vis->thingheight,
// do interpolation .tz = vis->texturemid,
if (R_UsingFrameInterpolation() && !paused) .color = get_bbox_color(vis),
{ };
R_InterpolateMobjState(thing, rendertimefrac, &interp);
}
else
{
R_InterpolateMobjState(thing, FRACUNIT, &interp);
}
rs = FixedMul(thing->radius, viewsin);
rc = FixedMul(thing->radius, viewcos);
gx = interp.x - viewx;
gy = interp.y - viewy;
tx = FixedMul(gx, viewsin) - FixedMul(gy, viewcos);
ty = FixedMul(gx, viewcos) + FixedMul(gy, viewsin);
bb.height = thing->height;
bb.tz = (interp.z + bb.height) - viewz;
bb.color = get_bbox_color(thing);
// 1--3 // 1--3
// | | // | |
@ -228,18 +209,15 @@ void R_DrawThingBoundingBox(mobj_t *thing)
// left // left
tx -= rs; draw_bbox_col(&bb, 0, tx, ty); // bottom
ty -= rc;
draw_bbox_col(&bb, 0, tx + rc, ty - rs); // bottom
draw_bbox_col(&bb, 1, tx - rc, ty + rs); // top draw_bbox_col(&bb, 1, tx - rc, ty + rs); // top
// right // right
tx += rs + rs; tx += rs;
ty += rc + rc; 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 draw_bbox_col(&bb, 3, tx - rc, ty + rs); // top
// connect all four columns // connect all four columns

View file

@ -1449,6 +1449,104 @@ static void R_ProjectDropShadow(
objectsdrawn++; objectsdrawn++;
} }
static void R_ProjectBoundingBox(mobj_t *thing, vissprite_t *vis)
{
fixed_t gx, gy;
fixed_t tx, tz;
vissprite_t *box;
// uncapped/interpolation
interpmobjstate_t interp = {0};
if (!R_ThingBoundingBoxVisible(thing))
{
return;
}
// do interpolation
if (R_UsingFrameInterpolation() && !paused)
{
R_InterpolateMobjState(thing, rendertimefrac, &interp);
}
else
{
R_InterpolateMobjState(thing, FRACUNIT, &interp);
}
// 1--3
// | |
// 0--2
// start in the (0) corner
gx = interp.x - thing->radius - viewx;
gy = interp.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, interp.scale)))
{
return;
}
tx = FixedMul(gx, viewsin) - FixedMul(gy, viewcos);
// too far off the side?
if (!vis && abs(tx) > FixedMul(tz, fovtan[viewssnum])<<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 = interp.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[viewssnum], tz);
fixed_t yscale = FixedDiv(projectiony[viewssnum], 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 // R_ProjectSprite
// Generates a vissprite for a thing // Generates a vissprite for a thing
@ -2195,6 +2293,8 @@ static void R_ProjectSprite(mobj_t *thing)
R_ProjectDropShadow(oldthing, vis, oldthing->shadowscale, basetx, basetz); R_ProjectDropShadow(oldthing, vis, oldthing->shadowscale, basetx, basetz);
} }
R_ProjectBoundingBox(oldthing, vis);
// Debug // Debug
++objectsdrawn; ++objectsdrawn;
} }
@ -2429,10 +2529,28 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
limit_dist = (fixed_t)(cv_drawdist.value) * mapobjectscale; limit_dist = (fixed_t)(cv_drawdist.value) * mapobjectscale;
for (thing = sec->thinglist; thing; thing = thing->snext) for (thing = sec->thinglist; thing; thing = thing->snext)
{ {
if (R_ThingVisibleWithinDist(thing, limit_dist)) if (R_ThingWithinDist(thing, limit_dist))
{
const INT32 oldobjectsdrawn = objectsdrawn;
if (R_ThingVisible(thing))
{
R_ProjectSprite(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 // no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off
if ((limit_dist = (fixed_t)cv_drawdist_precip.value * mapobjectscale)) if ((limit_dist = (fixed_t)cv_drawdist_precip.value * mapobjectscale))
{ {
@ -2503,6 +2621,10 @@ static void R_SortVisSprites(vissprite_t* vsprsortedhead, UINT32 start, UINT32 e
if (dsfirst->cut & SC_SHADOW) if (dsfirst->cut & SC_SHADOW)
continue; continue;
// don't connect to your bounding box!
if (dsfirst->cut & SC_BBOX)
continue;
// don't connect if it's not the tracer // don't connect if it's not the tracer
if (dsfirst->mobj != ds->mobj) if (dsfirst->mobj != ds->mobj)
continue; continue;
@ -2946,18 +3068,12 @@ static void R_DrawSprite(vissprite_t *spr)
mfloorclip = spr->clipbot; mfloorclip = spr->clipbot;
mceilingclip = spr->cliptop; 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); R_DrawFloorSplat(spr);
else else
R_DrawVisSprite(spr); 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 // Special drawer for precipitation sprites Tails 08-18-2002
@ -3253,6 +3369,12 @@ void R_ClipSprites(drawseg_t* dsstart, portal_t* portal)
INT32 x1 = (spr->cut & SC_SPLAT) ? 0 : spr->x1; INT32 x1 = (spr->cut & SC_SPLAT) ? 0 : spr->x1;
INT32 x2 = (spr->cut & SC_SPLAT) ? viewwidth : spr->x2; INT32 x2 = (spr->cut & SC_SPLAT) ? viewwidth : spr->x2;
if (spr->cut & SC_BBOX)
{
// Do not clip bounding boxes
continue;
}
if (x2 < cx) if (x2 < cx)
{ {
drawsegs_xrange = drawsegs_xranges[1].items; drawsegs_xrange = drawsegs_xranges[1].items;
@ -3291,20 +3413,26 @@ boolean R_ThingVisible (mobj_t *thing)
return true; return true;
} }
boolean R_ThingWithinDist (mobj_t *thing, fixed_t limit_dist)
{
const fixed_t dist = R_PointToDist(thing->x, thing->y);
if (limit_dist && dist > limit_dist)
{
return false;
}
return true;
}
// For OpenGL, TODO: REMOVE!!
boolean R_ThingVisibleWithinDist (mobj_t *thing, boolean R_ThingVisibleWithinDist (mobj_t *thing,
fixed_t limit_dist) fixed_t limit_dist)
{ {
fixed_t approx_dist;
if (! R_ThingVisible(thing)) if (! R_ThingVisible(thing))
return false; return false;
approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); return R_ThingWithinDist(thing, limit_dist);
if (limit_dist && approx_dist > limit_dist)
return false;
return true;
} }
/* Check if precipitation may be drawn from our current view. */ /* Check if precipitation may be drawn from our current view. */

View file

@ -67,7 +67,6 @@ void R_InitSprites(void);
void R_ClearSprites(void); void R_ClearSprites(void);
boolean R_ThingBoundingBoxVisible(mobj_t *thing); boolean R_ThingBoundingBoxVisible(mobj_t *thing);
void R_DrawThingBoundingBox(mobj_t *thing);
boolean R_ThingVisible (mobj_t *thing); boolean R_ThingVisible (mobj_t *thing);
@ -140,6 +139,7 @@ typedef enum
SC_SPLAT = 1<<11, SC_SPLAT = 1<<11,
// srb2kart // srb2kart
SC_SEMIBRIGHT = 1<<12, SC_SEMIBRIGHT = 1<<12,
SC_BBOX = 1<<13,
// masks // masks
SC_CUTMASK = SC_TOP|SC_BOTTOM, SC_CUTMASK = SC_TOP|SC_BOTTOM,
SC_FLAGMASK = ~SC_CUTMASK SC_FLAGMASK = ~SC_CUTMASK
@ -226,6 +226,8 @@ extern UINT32 visspritecount;
void R_ClipSprites(drawseg_t* dsstart, portal_t* portal); void R_ClipSprites(drawseg_t* dsstart, portal_t* portal);
void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, portal_t* portal); void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, portal_t* portal);
void R_DrawThingBoundingBox(vissprite_t *spr);
UINT8 *R_GetSpriteTranslation(vissprite_t *vis); UINT8 *R_GetSpriteTranslation(vissprite_t *vis);
// ---------- // ----------