diff --git a/src/cvars.cpp b/src/cvars.cpp index 82d0b12f1..4f4ab8e16 100644 --- a/src/cvars.cpp +++ b/src/cvars.cpp @@ -876,8 +876,10 @@ consvar_t cv_debugrank = PlayerCheat("debugrank", "Off").description("Show GP ra }); consvar_t cv_debugrender_contrast = PlayerCheat("debugrender_contrast", "0.0").floating_point().min_max(-FRACUNIT, FRACUNIT).description("Change level lighting"); +consvar_t cv_debugrender_freezebsp = PlayerCheat("debugrender_freezebsp", "Off").on_off().description("Freeze level culling so you can observe how much of the level is being rendered"); consvar_t cv_debugrender_portal = PlayerCheat("debugrender_portal", "Off").on_off().description("Highlight visual portals in red"); consvar_t cv_debugrender_spriteclip = PlayerCheat("debugrender_spriteclip", "Off").on_off().description("Let sprites draw through walls"); +consvar_t cv_debugrender_visplanes = PlayerCheat("debugrender_visplanes", "Off").on_off().description("Highlight the number of visplanes"); consvar_t cv_devmode_screen = PlayerCheat("devmode_screen", "1").min_max(1, 4).description("Choose which splitscreen player devmode applies to"); consvar_t cv_drawpickups = PlayerCheat("drawpickups", "Yes").yes_no().description("Hide rings, spheres, item capsules, prison capsules (visual only)"); consvar_t cv_drawinput = PlayerCheat("drawinput", "No").yes_no().description("Draw turn inputs outside of Record Attack (turn solver debugging)"); diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index e6a7c011a..736037dac 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -12,6 +12,7 @@ /// \brief BSP traversal, handling of LineSegs for rendering #include +#include #include @@ -31,7 +32,7 @@ #include "k_terrain.h" -extern "C" consvar_t cv_debugfinishline; +extern "C" consvar_t cv_debugfinishline, cv_debugrender_freezebsp; seg_t *curline; side_t *sidedef; @@ -53,6 +54,9 @@ INT32 doorclosed; // can block off the BSP across that seg. boolean g_walloffscreen; +static std::vector> node_cache; +static std::vector* current_node_cache; + boolean R_NoEncore(sector_t *sector, levelflat_t *flat, boolean ceiling) { const boolean invertEncore = (sector->flags & MSF_INVERTENCORE); @@ -1420,5 +1424,46 @@ void R_RenderBSPNode(INT32 bspnum) portalcullsector = NULL; } - R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); + bspnum = (bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); + R_Subsector(bspnum); + + if (current_node_cache) + { + current_node_cache->push_back(bspnum); + } +} + +static bool render_cache(size_t cachenum) +{ + if (node_cache.empty() && !cv_debugrender_freezebsp.value) + { + current_node_cache = nullptr; + return false; + } + + if (!cv_debugrender_freezebsp.value) + { + // free cache + node_cache = {}; + current_node_cache = nullptr; + return false; + } + + if (node_cache.size() <= cachenum) + { + node_cache.resize(cachenum + 1); + current_node_cache = &node_cache[cachenum]; + return false; + } + + for (INT32 bspnum : node_cache[cachenum]) + R_Subsector(bspnum); + + return true; +} + +void R_RenderFirstBSPNode(size_t cachenum) +{ + if (!render_cache(cachenum)) + R_RenderBSPNode((INT32)numnodes - 1); } diff --git a/src/r_bsp.h b/src/r_bsp.h index 5002a4d8a..17407f5e6 100644 --- a/src/r_bsp.h +++ b/src/r_bsp.h @@ -42,6 +42,7 @@ void R_ClearClipSegs(void); void R_PortalClearClipSegs(INT32 start, INT32 end); void R_ClearDrawSegs(void); void R_RenderBSPNode(INT32 bspnum); +void R_RenderFirstBSPNode(size_t cachenum); // determines when a given sector shouldn't abide by the encoremap's palette. // no longer a static since this is used for encore in hw_main.c as well now: diff --git a/src/r_main.cpp b/src/r_main.cpp index 7277c2ace..365bd6674 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -55,6 +55,8 @@ INT64 mytotal = 0; #endif //profile stuff --------------------------------------------------------- +extern "C" consvar_t cv_debugrender_visplanes; + // Fineangles in the SCREENWIDTH wide window. #define FIELDOFVIEW 2048 @@ -1454,13 +1456,13 @@ static void Mask_Post (maskcount_t* m) // ================ // viewx, viewy, viewangle, all that good stuff must be set -static void R_RenderViewpoint(maskcount_t* mask) +static void R_RenderViewpoint(maskcount_t* mask, INT32 cachenum) { Mask_Pre(mask); curdrawsegs = ds_p; - R_RenderBSPNode((INT32)numnodes - 1); + R_RenderFirstBSPNode(cachenum); R_AddPrecipitationSprites(); Mask_Post(mask); @@ -1516,7 +1518,7 @@ void R_RenderPlayerView(void) srb2::ThreadPool::Sema tp_sema; srb2::g_main_threadpool->begin_sema(); - R_RenderViewpoint(&masks[nummasks - 1]); + R_RenderViewpoint(&masks[nummasks - 1], nummasks - 1); ps_bsptime = I_GetPreciseTime() - ps_bsptime; #ifdef TIMING @@ -1574,7 +1576,7 @@ void R_RenderPlayerView(void) // Render the BSP from the new viewpoint, and clip // any sprites with the new clipsegs and window. - R_RenderViewpoint(&masks[nummasks - 1]); + R_RenderViewpoint(&masks[nummasks - 1], nummasks - 1); portalskipprecipmobjs = false; @@ -1603,6 +1605,58 @@ void R_RenderPlayerView(void) R_DrawMasked(masks, nummasks); ps_sw_maskedtime = I_GetPreciseTime() - ps_sw_maskedtime; + if (cv_debugrender_visplanes.value) + { + for (INT32 i = 0; i < MAXVISPLANES; i++) + { + for (visplane_t* pl = visplanes[i]; pl; pl = pl->next) + { + if (pl->minx > pl->maxx) + continue; + auto col = [](int x, int top, int bot) + { + if (top > bot) + std::swap(top, bot); + UINT8* p = &screens[0][x + top * vid.width]; + while (top <= bot) + { + *p = 35; + p += vid.width; + top++; + } + }; + auto span = [col](int x, int top, int bot) + { + if (top <= bot) + col(x, top, bot); + }; + INT32 top = pl->top[pl->minx]; + INT32 bottom = pl->bottom[pl->minx]; + span(pl->minx, top, bottom); + span(pl->maxx, pl->top[pl->maxx], pl->bottom[pl->maxx]); + for (INT32 x = pl->minx + 1; x < pl->maxx; ++x) + { + INT32 new_top = pl->top[x]; + INT32 new_bottom = pl->bottom[x]; + if (new_top > new_bottom) + continue; + if (top > bottom) + { + col(x, new_top, new_top); + col(x, new_bottom, new_bottom); + } + else + { + col(x, top, new_top); + col(x, bottom, new_bottom); + } + top = new_top; + bottom = new_bottom; + } + } + } + } + // debugrender_portal: fill portals with red, draw over everything if (portal_base && cv_debugrender_portal.value) {