Add the debugrender_highlight command, highlight specific rendering in flat colors

Software mode only.

The command is used like this:

debugrender_highlight planes sprites
debugrender_highlight pl spr
debugrender_highlight none

(Abbreviations work.)

Supported rendering to flag:

planes      - sector floor/ceiling
fofplanes   - FOF top/bottom
fofsides    - FOF sides
midtextures - pegged midtexture
walls       - sector upper/lower texture, one-sided linedefs
sprites     - sprites
sky         - skybox
This commit is contained in:
James R 2023-03-06 05:10:58 -08:00
parent 1de5046623
commit 53b2922fbb
14 changed files with 380 additions and 11 deletions

View file

@ -65,6 +65,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
r_bsp.c
r_data.c
r_debug.cpp
r_debug_parser.cpp
r_draw.c
r_fps.c
r_main.c

View file

@ -12,11 +12,15 @@
#include <algorithm> // std::clamp
#include "cxxutil.hpp"
#include "r_debug_detail.hpp"
#include "command.h"
#include "m_fixed.h"
#include "r_draw.h"
#include "r_main.h"
using namespace srb2::r_debug;
namespace
{
@ -27,12 +31,68 @@ CV_PossibleValue_t contrast_cons_t[] = {{-FRACUNIT, "MIN"}, {FRACUNIT, "MAX"}, {
consvar_t cv_debugrender_contrast =
CVAR_INIT("debugrender_contrast", "0.0", CV_CHEAT | CV_FLOAT, contrast_cons_t, nullptr);
UINT32 debugrender_highlight;
void R_CheckDebugHighlight(debugrender_highlight_t k)
{
// If highlighting is enabled for anything, surfaces
// must be highlighted in one of two colors, depending on
// whether they fall under focus of the debug.
if (debugrender_highlight)
{
r8_flatcolor = (debugrender_highlight & (1 << k)) ? detail::kHighlightOptions[k].color : 0x1F;
}
}
INT32 R_AdjustLightLevel(INT32 light)
{
constexpr fixed_t kRange = (LIGHTLEVELS - 1) * FRACUNIT;
const fixed_t adjust = FixedMul(cv_debugrender_contrast.value, kRange);
if (debugrender_highlight)
{
light = (kRange / 2) - (adjust / 2);
SRB2_ASSERT(light >= 0);
SRB2_ASSERT(light <= kRange);
}
else
{
light = std::clamp((light * FRACUNIT) - adjust, 0, kRange);
}
return light / FRACUNIT;
}
void Command_Debugrender_highlight(void)
{
const bool changes = COM_Argc() > 1;
if (!CV_CheatsEnabled())
{
CONS_Printf("Cheats must be enabled.\n");
return;
}
if (changes)
{
const char* arg = COM_Argv(1);
debugrender_highlight = 0; // always reset
if (COM_Argc() > 2 ||
// approximate match "none"
strncasecmp(arg, "none", strlen(arg)))
{
char* p = COM_Args();
while (p)
{
p = detail::parse_highlight_arg(p);
}
}
}
detail::highlight_help(changes);
}

42
src/r_debug_detail.hpp Normal file
View file

@ -0,0 +1,42 @@
// RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by James Robert Roman.
//
// 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 r_debug_detail.cpp
/// \brief Software renderer debugging, internal header
#ifndef __R_DEBUG_DETAIL__
#define __R_DEBUG_DETAIL__
#include "r_main.h"
namespace srb2::r_debug::detail
{
struct HighlightDesc
{
uint8_t color;
const char* label;
const char* description;
};
constexpr HighlightDesc kHighlightOptions[NUM_SW_HI] = {
{0x96, "planes", "Sector floor/ceiling"},
{0x49, "fofplanes", "FOF top/bottom"},
{0xB6, "fofsides", "FOF sides"},
{0x7A, "midtextures", "Two-sided midtexture"},
{0xC9, "walls", "Sector upper/lower texture, one-sided midtexture"},
{0x23, "sprites", "Sprites"},
{0x0F, "sky", "Sky texture"}};
char* skip_alnum(char* p, int mode);
char* parse_highlight_arg(char* p);
void highlight_help(bool only_on);
}; // srb2::r_debug::detail
#endif // __R_DEBUG_DETAIL__

95
src/r_debug_parser.cpp Normal file
View file

@ -0,0 +1,95 @@
// RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by James Robert Roman.
//
// 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 r_debug_parser.cpp
/// \brief Helper functions for the debugrender_highlight command
#include "r_debug_detail.hpp"
#include "doomdef.h"
#include "r_main.h"
using namespace srb2::r_debug;
using namespace srb2::r_debug::detail;
char* detail::skip_alnum(char* p, int mode)
{
while (*p != '\0' && !isalnum(*p) == !mode)
{
p++;
}
return p;
}
char* detail::parse_highlight_arg(char* p)
{
INT32 k;
const HighlightDesc* key;
const auto old = static_cast<debugrender_highlight_t>(debugrender_highlight);
char* t;
int c;
p = skip_alnum(p, 0); // skip "whitespace"
if (*p == '\0')
{
return NULL;
}
t = skip_alnum(p, 1); // find end of word
c = *t; // save to restore afterward
*t = '\0'; // isolate word string
for (k = 0; (key = &kHighlightOptions[k]), k < NUM_SW_HI; ++k)
{
// allow an approximate match
if (!strncasecmp(p, key->label, (t - p)))
{
debugrender_highlight |= (1 << k);
// keep going to match multiple with same
// prefix
}
}
if (debugrender_highlight == old)
{
// no change? Foolish user
CONS_Alert(CONS_WARNING, "\"%s\" makes no sense\n", p);
}
*t = c; // restore
return t; // skip to end of word
}
void detail::highlight_help(bool only_on)
{
int32_t k;
const HighlightDesc* key;
for (k = 0; (key = &kHighlightOptions[k]), k < NUM_SW_HI; ++k)
{
const bool on = (debugrender_highlight & (1 << k)) != 0;
if (!only_on || on)
{
CONS_Printf("%s\x80 \x87%s\x80 - %s\n", on ? "\x83 ON" : "\x85OFF", key->label, key->description);
}
}
if (!only_on)
{
CONS_Printf("\nYou can change the highlights by using a command like:\n\n"
"\x87 debugrender_highlight planes sprites\n"
"\x87 debugrender_highlight none\n");
}
}

View file

@ -68,6 +68,8 @@ INT32 columnofs[MAXVIDWIDTH*4];
UINT8 *topleft;
UINT8 r8_flatcolor;
// =========================================================================
// COLUMN DRAWING CODE STUFF
// =========================================================================
@ -81,6 +83,7 @@ UINT8 dc_hires; // under MSVC boolean is a byte, while on other systems, it a bi
// soo lets make it a byte on all system for the ASM code
UINT8 *dc_source;
UINT8 *dc_brightmap;
UINT8 *dc_lightmap;
// -----------------------
// translucency stuff here
@ -638,6 +641,7 @@ void R_DrawViewBorder(void)
#include "r_draw8.c"
#include "r_draw8_npo2.c"
#include "r_draw8_flat.c"
// ==========================================================================
// INCLUDE 16bpp DRAWING CODE HERE

View file

@ -30,6 +30,7 @@ extern UINT8 *ylookup3[MAXVIDHEIGHT*4];
extern UINT8 *ylookup4[MAXVIDHEIGHT*4];
extern INT32 columnofs[MAXVIDWIDTH*4];
extern UINT8 *topleft;
extern UINT8 r8_flatcolor;
// -------------------------
// COLUMN DRAWING CODE STUFF
@ -43,6 +44,7 @@ extern UINT8 dc_hires;
extern UINT8 *dc_source; // first pixel in a column
extern UINT8 *dc_brightmap; // brightmap texture column, can be NULL
extern UINT8 *dc_lightmap; // lighting only
// translucency stuff here
extern UINT8 *dc_transmap;
@ -76,6 +78,8 @@ extern UINT8 *ds_source;
extern UINT8 *ds_brightmap;
extern UINT8 *ds_transmap;
extern UINT8 ds_flatcolor;
struct floatv3_t {
float x, y, z;
};
@ -232,6 +236,11 @@ void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void);
void R_DrawTranslucentWaterSpan_NPO2_8(void);
void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void);
// Debugging - highlight surfaces in flat colors
void R_DrawColumn_Flat_8(void);
void R_DrawSpan_Flat_8(void);
void R_DrawTiltedSpan_Flat_8(void);
#ifdef USEASM
void ASMCALL R_DrawColumn_8_ASM(void);
void ASMCALL R_DrawShadeColumn_8_ASM(void);

79
src/r_draw8_flat.c Normal file
View file

@ -0,0 +1,79 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2020 by Sonic Team Junior.
// Copyright (C) 2023 by Kart Krew.
//
// 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 r_draw8_flat.c
/// \brief 8bpp span/column drawer functions for debugging (draws in flat colors only)
/// \note no includes because this is included as part of r_draw.c
void R_DrawColumn_Flat_8 (void)
{
INT32 count;
UINT8 color = dc_lightmap[r8_flatcolor];
register UINT8 *dest;
count = dc_yh - dc_yl;
if (count < 0) // Zero length, column does not exceed a pixel.
return;
#ifdef RANGECHECK
if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height)
return;
#endif
// Framebuffer destination address.
// Use ylookup LUT to avoid multiply with ScreenWidth.
// Use columnofs LUT for subwindows?
//dest = ylookup[dc_yl] + columnofs[dc_x];
dest = &topleft[dc_yl*vid.width + dc_x];
count++;
do
{
*dest = color;
dest += vid.width;
} while (--count);
}
void R_DrawSpan_Flat_8 (void)
{
UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1];
memset(dest, ds_colormap[r8_flatcolor], (ds_x2 - ds_x1) + 1);
}
void R_DrawTiltedSpan_Flat_8 (void)
{
// x1, x2 = ds_x1, ds_x2
int width = ds_x2 - ds_x1;
double iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
UINT8 *dest = ylookup[ds_y];
// Lighting is simple. It's just linear interpolation from start to end
{
float planelightfloat = PLANELIGHTFLOAT;
float lightstart, lightend;
lightend = (iz + ds_szp->x*width) * planelightfloat;
lightstart = iz * planelightfloat;
R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
}
while (ds_x1 <= ds_x2)
{
dest[ds_x1] = planezlight[tiltlighting[ds_x1]][r8_flatcolor];
ds_x1++;
}
}

View file

@ -1660,4 +1660,6 @@ void R_RegisterEngineStuff(void)
// debugging
CV_RegisterVar(&cv_debugrender_contrast);
COM_AddCommand("debugrender_highlight", Command_Debugrender_highlight);
}

View file

@ -125,8 +125,25 @@ extern consvar_t cv_drawpickups;
// debugging
typedef enum {
SW_HI_PLANES,
SW_HI_FOFPLANES,
SW_HI_FOFSIDES,
SW_HI_MIDTEXTURES,
SW_HI_WALLS,
SW_HI_THINGS,
SW_HI_SKY,
NUM_SW_HI
} debugrender_highlight_t;
extern UINT32 debugrender_highlight;
void R_CheckDebugHighlight(debugrender_highlight_t type);
INT32 R_AdjustLightLevel(INT32 light);
void Command_Debugrender_highlight(void);
extern consvar_t
cv_debugrender_contrast;

View file

@ -208,6 +208,8 @@ static void R_MapPlane(INT32 y, INT32 x1, INT32 x2)
pindex = MAXLIGHTZ - 1;
ds_colormap = planezlight[pindex];
if (!debugrender_highlight)
{
if (currentplane->extra_colormap)
ds_colormap = currentplane->extra_colormap->colormap + (ds_colormap - colormaps);
@ -217,6 +219,7 @@ static void R_MapPlane(INT32 y, INT32 x1, INT32 x2)
ds_colormap += COLORMAP_REMAPOFFSET;
ds_fullbright += COLORMAP_REMAPOFFSET;
}
}
ds_y = y;
ds_x1 = x1;
@ -613,6 +616,8 @@ static void R_DrawSkyPlane(visplane_t *pl)
INT32 x;
INT32 angle;
R_CheckDebugHighlight(SW_HI_SKY);
// Reset column drawer function (note: couldn't we just call walldrawerfunc directly?)
// (that is, unless we'll need to switch drawers in future for some reason)
R_SetColumnFunc(BASEDRAWFUNC, false);
@ -631,6 +636,7 @@ static void R_DrawSkyPlane(visplane_t *pl)
dc_colormap += COLORMAP_REMAPOFFSET;
dc_fullbright += COLORMAP_REMAPOFFSET;
}
dc_lightmap = colormaps;
dc_texturemid = skytexturemid;
dc_texheight = textureheight[skytexture]
>>FRACBITS;
@ -831,6 +837,7 @@ void R_DrawSinglePlane(visplane_t *pl)
INT32 x, stop;
ffloor_t *rover;
INT32 type, spanfunctype = BASEDRAWFUNC;
debugrender_highlight_t debug = 0;
void (*mapfunc)(INT32, INT32, INT32) = R_MapPlane;
if (!(pl->minx <= pl->maxx))
@ -911,10 +918,16 @@ void R_DrawSinglePlane(visplane_t *pl)
light = (pl->lightlevel >> LIGHTSEGSHIFT);
}
else light = (pl->lightlevel >> LIGHTSEGSHIFT);
debug = SW_HI_FOFPLANES;
}
else
{
light = (pl->lightlevel >> LIGHTSEGSHIFT);
debug = SW_HI_PLANES;
}
#ifndef NOWATER
if (pl->ripple)
{
@ -1085,6 +1098,8 @@ void R_DrawSinglePlane(visplane_t *pl)
}
R_CheckDebugHighlight(debug);
// Use the correct span drawer depending on the powers-of-twoness
R_SetSpanFunc(spanfunctype, !ds_powersoftwo, ds_brightmap != NULL);

View file

@ -185,6 +185,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
transtable = 0;
}
R_CheckDebugHighlight(SW_HI_MIDTEXTURES);
if (blendmode == AST_FOG)
{
R_SetColumnFunc(COLDRAWFUNC_FOG, bmnum != 0);
@ -440,6 +442,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
if (height <= windowtop)
{
dc_colormap = rlight->rcolormap;
dc_lightmap = xwalllights[pindex];
dc_fullbright = colormaps;
if (encoremap && !(ldef->flags & ML_TFERLINE))
{
@ -465,6 +468,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
colfunc_2s(col, bmCol, -1);
windowtop = windowbottom + 1;
dc_colormap = rlight->rcolormap;
dc_lightmap = xwalllights[pindex];
dc_fullbright = colormaps;
if (encoremap && !(ldef->flags & ML_TFERLINE))
{
@ -487,6 +491,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
pindex = MAXLIGHTSCALE - 1;
dc_colormap = walllights[pindex];
dc_lightmap = walllights[pindex];
dc_fullbright = colormaps;
if (encoremap && !(ldef->flags & ML_TFERLINE))
{
@ -642,6 +647,8 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
texnum = R_GetTextureNum(sides[pfloor->master->sidenum[0]].midtexture);
bmnum = R_GetTextureBrightmap(texnum);
R_CheckDebugHighlight(SW_HI_FOFSIDES);
R_SetColumnFunc(BASEDRAWFUNC, bmnum != 0);
if (pfloor->master->flags & ML_TFERLINE)
@ -1033,6 +1040,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
if (lighteffect)
{
dc_colormap = rlight->rcolormap;
dc_lightmap = xwalllights[pindex];
dc_fullbright = colormaps;
if (encoremap && !(curline->linedef->flags & ML_TFERLINE))
{
@ -1069,6 +1077,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
if (lighteffect)
{
dc_colormap = rlight->rcolormap;
dc_lightmap = xwalllights[pindex];
dc_fullbright = colormaps;
if (encoremap && !(curline->linedef->flags & ML_TFERLINE))
{
@ -1093,6 +1102,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
pindex = MAXLIGHTSCALE - 1;
dc_colormap = walllights[pindex];
dc_lightmap = walllights[pindex];
dc_fullbright = colormaps;
if (encoremap && !(curline->linedef->flags & ML_TFERLINE))
@ -1359,6 +1369,7 @@ static void R_RenderSegLoop (void)
pindex = MAXLIGHTSCALE-1;
dc_colormap = walllights[pindex];
dc_lightmap = walllights[pindex];
dc_fullbright = colormaps;
if (encoremap && !(curline->linedef->flags & ML_TFERLINE))
{
@ -1626,6 +1637,8 @@ void R_StoreWallRange(INT32 start, INT32 stop)
memset(&segleft, 0x00, sizeof(segleft));
memset(&segright, 0x00, sizeof(segright));
R_CheckDebugHighlight(SW_HI_WALLS);
R_SetColumnFunc(BASEDRAWFUNC, false);
if (ds_p == drawsegs+maxdrawsegs)

View file

@ -939,6 +939,8 @@ static void R_DrawVisSprite(vissprite_t *vis)
if (!dc_colormap)
dc_colormap = colormaps;
dc_lightmap = colormaps;
dc_fullbright = colormaps;
if (encoremap && !vis->mobj->color && !(vis->mobj->flags & MF_DONTENCOREMAP))
@ -1143,6 +1145,8 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis)
dc_fullbright += COLORMAP_REMAPOFFSET;
}
dc_lightmap = colormaps;
dc_iscale = FixedDiv(FRACUNIT, vis->scale);
dc_texturemid = FixedDiv(vis->texturemid, this_scale);
dc_texheight = 0;
@ -3210,6 +3214,8 @@ static void R_DrawSprite(vissprite_t *spr)
mfloorclip = spr->clipbot;
mceilingclip = spr->cliptop;
R_CheckDebugHighlight(SW_HI_THINGS);
if (spr->cut & SC_BBOX)
R_DrawThingBoundingBox(spr);
else if (spr->cut & SC_SPLAT)

View file

@ -64,6 +64,7 @@ void (*spanfuncs_npo2[SPANDRAWFUNC_MAX])(void);
#ifdef USE_COL_SPAN_ASM
void (*spanfuncs_asm[SPANDRAWFUNC_MAX])(void);
#endif
void (*spanfuncs_flat[SPANDRAWFUNC_MAX])(void);
// ------------------
// global video state
@ -170,6 +171,22 @@ void SCR_SetDrawFuncs(void)
spanfuncs_npo2[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedTranslucentWaterSpan_NPO2_8;
spanfuncs_npo2[SPANDRAWFUNC_FOG] = NULL; // Not needed
// Debugging - highlight surfaces in flat colors
spanfuncs_flat[BASEDRAWFUNC] = R_DrawSpan_Flat_8;
spanfuncs_flat[SPANDRAWFUNC_TRANS] = R_DrawSpan_Flat_8;
spanfuncs_flat[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_Flat_8;
spanfuncs_flat[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedSpan_Flat_8;
spanfuncs_flat[SPANDRAWFUNC_SPLAT] = R_DrawSpan_Flat_8;
spanfuncs_flat[SPANDRAWFUNC_TRANSSPLAT] = R_DrawSpan_Flat_8;
spanfuncs_flat[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSpan_Flat_8;
spanfuncs_flat[SPANDRAWFUNC_SPRITE] = R_DrawSpan_Flat_8;
spanfuncs_flat[SPANDRAWFUNC_TRANSSPRITE] = R_DrawSpan_Flat_8;
spanfuncs_flat[SPANDRAWFUNC_TILTEDSPRITE] = R_DrawTiltedSpan_Flat_8;
spanfuncs_flat[SPANDRAWFUNC_TILTEDTRANSSPRITE] = R_DrawTiltedSpan_Flat_8;
spanfuncs_flat[SPANDRAWFUNC_WATER] = R_DrawSpan_Flat_8;
spanfuncs_flat[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedSpan_Flat_8;
spanfuncs_flat[SPANDRAWFUNC_FOG] = R_DrawSpan_Flat_8; // Not needed
#if (defined(RUSEASM) && defined(USE_COL_SPAN_ASM))
if (R_ASM)
{
@ -220,13 +237,17 @@ void R_SetColumnFunc(size_t id, boolean brightmapped)
colfunctype = id;
if (debugrender_highlight != 0)
{
colfunc = R_DrawColumn_Flat_8;
}
#ifdef USE_COL_SPAN_ASM
if (colfuncs_asm[id] != NULL && brightmapped == false)
else if (colfuncs_asm[id] != NULL && brightmapped == false)
{
colfunc = colfuncs_asm[id];
}
else
#endif
else
{
colfunc = colfuncs[id];
}
@ -236,7 +257,11 @@ void R_SetSpanFunc(size_t id, boolean npo2, boolean brightmapped)
{
I_Assert(id < SPANDRAWFUNC_MAX);
if (spanfuncs_npo2[id] != NULL && npo2 == true)
if (spanfuncs_flat[id] != NULL && debugrender_highlight != 0)
{
spanfunc = spanfuncs_flat[id];
}
else if (spanfuncs_npo2[id] != NULL && npo2 == true)
{
spanfunc = spanfuncs_npo2[id];
}

View file

@ -179,6 +179,7 @@ extern void (*spanfuncs_npo2[SPANDRAWFUNC_MAX])(void);
#ifdef USE_COL_SPAN_ASM
extern void (*spanfuncs_asm[SPANDRAWFUNC_MAX])(void);
#endif
extern void (*spanfuncs_flat[SPANDRAWFUNC_MAX])(void);
// -----
// CPUID