From ac2a13fe574238c8fbf931a08b8d6e48a9171af7 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 11 Sep 2022 16:57:58 -0700 Subject: [PATCH] OpenGL hitbox renderer I apologize for that vertex array. --- src/hardware/hw_glob.h | 1 + src/hardware/hw_main.c | 130 +++++++++++++++++++++++++++++++++++++++-- src/r_bbox.c | 9 ++- src/r_things.h | 1 + 4 files changed, 132 insertions(+), 9 deletions(-) diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index 5b3f4654a..c13da6889 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -83,6 +83,7 @@ typedef struct gl_vissprite_s boolean flip, vflip; boolean precip; // Tails 08-25-2002 + boolean bbox; boolean rotated; UINT8 translucency; //alpha level 0-255 diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index a819171b4..3a4a0687f 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -70,6 +70,7 @@ static void HWR_ProjectSprite(mobj_t *thing); #ifdef HWPRECIP static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing); #endif +static void HWR_ProjectBoundingBox(mobj_t *thing); static void HWR_RollTransform(FTransform *tr, angle_t roll); void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap); @@ -4109,6 +4110,54 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) HWR_LinkDrawHackAdd(wallVerts, spr); } +static void HWR_DrawBoundingBox(gl_vissprite_t *vis) +{ + FOutVector v[24]; + FSurfaceInfo Surf = {0}; + + // + // create a cube (side view) + // + // 5--4 3 + // | + // | + // 0--1 2 + // + // repeat this 4 times (overhead) + // + // + // 17 20 21 11 + // 16 15 14 10 + // 27 22 *--* 07 12 + // | | + // 26 23 *--* 06 13 + // 24 00 01 02 + // 25 05 04 03 + // + + v[000].x = v[005].x = v[015].x = v[016].x = v[017].x = v[020].x = + v[022].x = v[023].x = v[024].x = v[025].x = v[026].x = v[027].x = vis->x1; // west + + v[001].x = v[002].x = v[003].x = v[004].x = v[006].x = v[007].x = + v[010].x = v[011].x = v[012].x = v[013].x = v[014].x = v[021].x = vis->x2; // east + + v[000].z = v[001].z = v[002].z = v[003].z = v[004].z = v[005].z = + v[006].z = v[013].z = v[023].z = v[024].z = v[025].z = v[026].z = vis->z1; // south + + v[007].z = v[010].z = v[011].z = v[012].z = v[014].z = v[015].z = + v[016].z = v[017].z = v[020].z = v[021].z = v[022].z = v[027].z = vis->z2; // north + + v[000].y = v[001].y = v[002].y = v[006].y = v[007].y = v[010].y = + v[014].y = v[015].y = v[016].y = v[022].y = v[023].y = v[024].y = vis->gz; // bottom + + v[003].y = v[004].y = v[005].y = v[011].y = v[012].y = v[013].y = + v[017].y = v[020].y = v[021].y = v[025].y = v[026].y = v[027].y = vis->gzt; // top + + Surf.PolyColor = V_GetColor(R_GetBoundingBoxColor(vis->mobj)); + + HWR_ProcessPolygon(&Surf, v, 24, PF_Modulated|PF_NoTexture|PF_WireFrame, SHADER_NONE, false); +} + // -----------------+ // HWR_DrawSprite : Draw flat sprites // : (monsters, bonuses, weapons, lights, ...) @@ -4562,9 +4611,16 @@ static int CompareVisSprites(const void *p1, const void *p2) int frame1; int frame2; + int linkdraw1; + int linkdraw2; + + // bbox doesn't need to be sorted + if (spr1->bbox || spr2->bbox) + return 0; + // check for precip first, because then sprX->mobj is actually a precipmobj_t and does not have flags2 or tracer - int linkdraw1 = !spr1->precip && (spr1->mobj->flags2 & MF2_LINKDRAW) && spr1->mobj->tracer; - int linkdraw2 = !spr2->precip && (spr2->mobj->flags2 & MF2_LINKDRAW) && spr2->mobj->tracer; + linkdraw1 = !spr1->precip && (spr1->mobj->flags2 & MF2_LINKDRAW) && spr1->mobj->tracer; + linkdraw2 = !spr2->precip && (spr2->mobj->flags2 & MF2_LINKDRAW) && spr2->mobj->tracer; // ^ is the XOR operation // if comparing a linkdraw and non-linkdraw sprite or 2 linkdraw sprites with different tracers, then use @@ -4954,6 +5010,9 @@ static void HWR_DrawSprites(void) for (i = 0; i < gl_visspritecount; i++) { gl_vissprite_t *spr = gl_vsprorder[i]; + if (spr->bbox) + HWR_DrawBoundingBox(spr); + else #ifdef HWPRECIP if (spr->precip) HWR_DrawPrecipitationSprite(spr); @@ -5052,8 +5111,15 @@ static void HWR_AddSprites(sector_t *sec) limit_dist = (fixed_t)(cv_drawdist.value) * mapobjectscale; for (thing = sec->thinglist; thing; thing = thing->snext) { - if (R_ThingVisibleWithinDist(thing, limit_dist)) - HWR_ProjectSprite(thing); + if (R_ThingWithinDist(thing, limit_dist)) + { + if (R_ThingVisible(thing)) + { + HWR_ProjectSprite(thing); + } + + HWR_ProjectBoundingBox(thing); + } } #ifdef HWPRECIP @@ -5552,6 +5618,7 @@ static void HWR_ProjectSprite(mobj_t *thing) vis->vflip = vflip; vis->precip = false; + vis->bbox = false; } #ifdef HWPRECIP @@ -5675,6 +5742,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) vis->gz = vis->gzt - (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height) * this_scale); vis->precip = true; + vis->bbox = false; // okay... this is a hack, but weather isn't networked, so it should be ok if (!(thing->precipflags & PCF_THUNK)) @@ -5685,6 +5753,60 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) } #endif +static void HWR_ProjectBoundingBox(mobj_t *thing) +{ + gl_vissprite_t *vis; + float tr_x, tr_y; + float tz; + float rad; + + // uncapped/interpolation + interpmobjstate_t interp = {0}; + + if (!thing) + return; + + if (!R_ThingBoundingBoxVisible(thing)) + return; + + if (R_UsingFrameInterpolation() && !paused) + { + R_InterpolateMobjState(thing, rendertimefrac, &interp); + } + else + { + R_InterpolateMobjState(thing, FRACUNIT, &interp); + } + + // transform the origin point + tr_x = FIXED_TO_FLOAT(interp.x) - gl_viewx; + tr_y = FIXED_TO_FLOAT(interp.y) - gl_viewy; + + // rotation around vertical axis + tz = (tr_x * gl_viewcos) + (tr_y * gl_viewsin); + + // thing is behind view plane? + if (tz < ZCLIP_PLANE) + return; + + tr_x += gl_viewx; + tr_y += gl_viewy; + + rad = FIXED_TO_FLOAT(thing->radius); + + vis = HWR_NewVisSprite(); + vis->x1 = tr_x - rad; + vis->x2 = tr_x + rad; + vis->z1 = tr_y - rad; + vis->z2 = tr_y + rad; + vis->gz = FIXED_TO_FLOAT(interp.z); + vis->gzt = vis->gz + FIXED_TO_FLOAT(thing->height); + vis->mobj = thing; + + vis->precip = false; + vis->bbox = true; +} + // ========================================================================== // Sky dome rendering, ported from PrBoom+ // ========================================================================== diff --git a/src/r_bbox.c b/src/r_bbox.c index 969aeacff..7c8887398 100644 --- a/src/r_bbox.c +++ b/src/r_bbox.c @@ -169,12 +169,11 @@ draw_bbox_row } } -static UINT8 -get_bbox_color (vissprite_t *vis) +UINT8 R_GetBoundingBoxColor(mobj_t *thing) { - UINT32 flags = vis->mobjflags; + UINT32 flags = thing->flags; - if (vis->mobj->player) + if (thing->player) return 255; // 0FF if (flags & (MF_NOCLIPTHING)) @@ -205,7 +204,7 @@ void R_DrawThingBoundingBox(vissprite_t *vis) struct bbox_config bb = { .height = vis->thingheight, .tz = vis->texturemid, - .color = get_bbox_color(vis), + .color = R_GetBoundingBoxColor(vis->mobj), }; // 1--3 diff --git a/src/r_things.h b/src/r_things.h index 085d15512..c6ad2a0e0 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -66,6 +66,7 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel); void R_InitSprites(void); void R_ClearSprites(void); +UINT8 R_GetBoundingBoxColor(mobj_t *thing); boolean R_ThingBoundingBoxVisible(mobj_t *thing); boolean R_ThingVisible (mobj_t *thing);