From 7e1bb4a370f8fa5b184db475419fc7460d674bc9 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Sat, 1 Jun 2019 13:07:23 +0200 Subject: [PATCH 01/17] Code refactoring to turn portal struct into a more generalized shape. Split portal-related code to its own source files. Most of the 2-line-specific setup has been moved to the function which adds a 2-line case. The portals should render as they used to so far, anyway. --- src/CMakeLists.txt | 2 + src/Makefile | 1 + src/r_bsp.c | 3 +- src/r_bsp.h | 1 - src/r_main.c | 170 ++++++++--------------------------------- src/r_plane.c | 44 ----------- src/r_plane.h | 2 - src/r_portal.c | 187 +++++++++++++++++++++++++++++++++++++++++++++ src/r_portal.h | 49 ++++++++++++ src/r_things.c | 4 +- 10 files changed, 273 insertions(+), 190 deletions(-) create mode 100644 src/r_portal.c create mode 100644 src/r_portal.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a6fab34ff..9e319d100 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -123,6 +123,7 @@ set(SRB2_CORE_RENDER_SOURCES r_sky.c r_splats.c r_things.c + r_portal.c r_bsp.h r_data.h @@ -136,6 +137,7 @@ set(SRB2_CORE_RENDER_SOURCES r_splats.h r_state.h r_things.h + r_portal.h ) set(SRB2_CORE_GAME_SOURCES diff --git a/src/Makefile b/src/Makefile index 5407a4d5e..b8d91fccc 100644 --- a/src/Makefile +++ b/src/Makefile @@ -455,6 +455,7 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/r_sky.o \ $(OBJDIR)/r_splats.o \ $(OBJDIR)/r_things.o \ + $(OBJDIR)/r_portal.o \ $(OBJDIR)/screen.o \ $(OBJDIR)/v_video.o \ $(OBJDIR)/s_sound.o \ diff --git a/src/r_bsp.c b/src/r_bsp.c index 22abaeb88..5643e777e 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -26,7 +26,6 @@ side_t *sidedef; line_t *linedef; sector_t *frontsector; sector_t *backsector; -boolean portalline; // is curline a portal seg? // very ugly realloc() of drawsegs at run-time, I upped it to 512 // instead of 256.. and someone managed to send me a level with @@ -459,7 +458,7 @@ static void R_AddLine(seg_t *line) line2 = P_FindSpecialLineFromTag(40, line->linedef->tag, line2); if (line2 >= 0) // found it! { - R_AddPortal(line->linedef-lines, line2, x1, x2); // Remember the lines for later rendering + Portal_Add2Lines(line->linedef-lines, line2, x1, x2); // Remember the lines for later rendering //return; // Don't fill in that space now! goto clipsolid; } diff --git a/src/r_bsp.h b/src/r_bsp.h index e3662e2e6..50fea6681 100644 --- a/src/r_bsp.h +++ b/src/r_bsp.h @@ -38,7 +38,6 @@ void R_ClearClipSegs(void); void R_PortalClearClipSegs(INT32 start, INT32 end); void R_ClearDrawSegs(void); void R_RenderBSPNode(INT32 bspnum); -void R_AddPortal(INT32 line1, INT32 line2, INT32 x1, INT32 x2); #ifdef POLYOBJECTS void R_SortPolyObjects(subsector_t *sub); diff --git a/src/r_main.c b/src/r_main.c index 23dc39d62..cab0490bf 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -30,6 +30,7 @@ #include "p_spec.h" // skyboxmo #include "z_zone.h" #include "m_random.h" // quake camera shake +#include "r_portal.h" #ifdef HWRENDER #include "hardware/hw_main.h" @@ -70,32 +71,6 @@ boolean skyVisible1, skyVisible2; // saved values of skyVisible for P1 and P2, f sector_t *viewsector; player_t *viewplayer; -// PORTALS! -// You can thank and/or curse JTE for these. -UINT8 portalrender; -sector_t *portalcullsector; -typedef struct portal_pair -{ - INT32 line1; - INT32 line2; - UINT8 pass; - struct portal_pair *next; - - fixed_t viewx; - fixed_t viewy; - fixed_t viewz; - angle_t viewangle; - - INT32 start; - INT32 end; - INT16 *ceilingclip; - INT16 *floorclip; - fixed_t *frontscale; -} portal_pair; -portal_pair *portal_base, *portal_cap; -line_t *portalclipline; -INT32 portalclipstart, portalclipend; - // // precalculated math tables // @@ -1010,17 +985,8 @@ void R_SkyboxFrame(player_t *player) R_SetupFreelook(); } -#define ANGLED_PORTALS - -static void R_PortalFrame(line_t *start, line_t *dest, portal_pair *portal) +static void R_PortalFrame(portal_t *portal) { - vertex_t dest_c, start_c; -#ifdef ANGLED_PORTALS - // delta angle - angle_t dangle = R_PointToAngle2(0,0,dest->dx,dest->dy) - R_PointToAngle2(start->dx,start->dy,0,0); -#endif - - //R_SetupFrame(player, false); viewx = portal->viewx; viewy = portal->viewy; viewz = portal->viewz; @@ -1029,93 +995,18 @@ static void R_PortalFrame(line_t *start, line_t *dest, portal_pair *portal) viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT); viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); - portalcullsector = dest->frontsector; - viewsector = dest->frontsector; - portalclipline = dest; portalclipstart = portal->start; portalclipend = portal->end; - // Offset the portal view by the linedef centers - - // looking glass center - start_c.x = (start->v1->x + start->v2->x) / 2; - start_c.y = (start->v1->y + start->v2->y) / 2; - - // other side center - dest_c.x = (dest->v1->x + dest->v2->x) / 2; - dest_c.y = (dest->v1->y + dest->v2->y) / 2; - - // Heights! - viewz += dest->frontsector->floorheight - start->frontsector->floorheight; - - // calculate the difference in position and rotation! -#ifdef ANGLED_PORTALS - if (dangle == 0) -#endif - { // the entrance goes straight opposite the exit, so we just need to mess with the offset. - viewx += dest_c.x - start_c.x; - viewy += dest_c.y - start_c.y; - return; - } - -#ifdef ANGLED_PORTALS - viewangle += dangle; - viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT); - viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); - //CONS_Printf("dangle == %u\n", AngleFixed(dangle)>>FRACBITS); - - // ???? + if (portal->clipline != -1) { - fixed_t disttopoint; - angle_t angtopoint; - - disttopoint = R_PointToDist2(start_c.x, start_c.y, viewx, viewy); - angtopoint = R_PointToAngle2(start_c.x, start_c.y, viewx, viewy); - angtopoint += dangle; - - viewx = dest_c.x+FixedMul(FINECOSINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); - viewy = dest_c.y+FixedMul(FINESINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); - } -#endif -} - -void R_AddPortal(INT32 line1, INT32 line2, INT32 x1, INT32 x2) -{ - portal_pair *portal = Z_Malloc(sizeof(portal_pair), PU_LEVEL, NULL); - INT16 *ceilingclipsave = Z_Malloc(sizeof(INT16)*(x2-x1), PU_LEVEL, NULL); - INT16 *floorclipsave = Z_Malloc(sizeof(INT16)*(x2-x1), PU_LEVEL, NULL); - fixed_t *frontscalesave = Z_Malloc(sizeof(fixed_t)*(x2-x1), PU_LEVEL, NULL); - - portal->line1 = line1; - portal->line2 = line2; - portal->pass = portalrender+1; - portal->next = NULL; - - R_PortalStoreClipValues(x1, x2, ceilingclipsave, floorclipsave, frontscalesave); - - portal->ceilingclip = ceilingclipsave; - portal->floorclip = floorclipsave; - portal->frontscale = frontscalesave; - - portal->start = x1; - portal->end = x2; - - portalline = true; // this tells R_StoreWallRange that curline is a portal seg - - portal->viewx = viewx; - portal->viewy = viewy; - portal->viewz = viewz; - portal->viewangle = viewangle; - - if (!portal_base) - { - portal_base = portal; - portal_cap = portal; + portalclipline = &lines[portal->clipline]; + viewsector = portalcullsector = portalclipline->frontsector; } else { - portal_cap->next = portal; - portal_cap = portal; + portalclipline = NULL; + viewsector = portalcullsector = R_PointInSubsector(viewx, viewy)->sector; } } @@ -1131,7 +1022,7 @@ void R_AddPortal(INT32 line1, INT32 line2, INT32 x1, INT32 x2) void R_RenderPlayerView(player_t *player) { - portal_pair *portal; + portal_t *portal; const boolean skybox = (skyboxmo[0] && cv_skybox.value); if (cv_homremoval.value && player == &players[displayplayer]) // if this is display player 1 @@ -1148,8 +1039,7 @@ void R_RenderPlayerView(player_t *player) else skyVisible = skyVisible1; - portalrender = 0; - portal_base = portal_cap = NULL; + Portal_InitList(); if (skybox && skyVisible) { @@ -1206,35 +1096,37 @@ void R_RenderPlayerView(player_t *player) #endif //profile stuff --------------------------------------------------------- - // PORTAL RENDERING - for(portal = portal_base; portal; portal = portal_base) + // Portal rendering. Hijacks the BSP traversal. + if (portal_base) { - // render the portal - CONS_Debug(DBG_RENDER, "Rendering portal from line %d to %d\n", portal->line1, portal->line2); - portalrender = portal->pass; + for(portal = portal_base; portal; portal = portal_base) + { + portalrender = portal->pass; // Recursiveness depth. - R_PortalFrame(&lines[portal->line1], &lines[portal->line2], portal); + // Apply the viewpoint stored for the portal. + R_PortalFrame(portal); - R_PortalClearClipSegs(portal->start, portal->end); + // Hack in the clipsegs to delimit the starting + // clipping for sprites and possibly other similar + // future items. + R_PortalClearClipSegs(portal->start, portal->end); - R_PortalRestoreClipValues(portal->start, portal->end, portal->ceilingclip, portal->floorclip, portal->frontscale); + // Hack in the top/bottom clip values for the window + // that were previously stored. + Portal_ClipApply(portal); - validcount++; + // Render the BSP from the new viewpoint, and clip + // any sprites with the new clipsegs and window. + R_RenderBSPNode((INT32)numnodes - 1); + R_ClipSprites(); - R_RenderBSPNode((INT32)numnodes - 1); - R_ClipSprites(); - //R_DrawPlanes(); - //R_DrawMasked(); + Portal_Remove(portal); + + validcount++; + } - // okay done. free it. portalcullsector = NULL; // Just in case... - portal_base = portal->next; - Z_Free(portal->ceilingclip); - Z_Free(portal->floorclip); - Z_Free(portal->frontscale); - Z_Free(portal); } - // END PORTAL RENDERING R_DrawPlanes(); #ifdef FLOORSPLATS diff --git a/src/r_plane.c b/src/r_plane.c index 0ef4c2c05..5cd9b26b5 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -112,50 +112,6 @@ void R_InitPlanes(void) // FIXME: unused } -// R_PortalStoreClipValues -// Saves clipping values for later. -Red -void R_PortalStoreClipValues(INT32 start, INT32 end, INT16 *ceil, INT16 *floor, fixed_t *scale) -{ - INT32 i; - for (i = 0; i < end-start; i++) - { - *ceil = ceilingclip[start+i]; - ceil++; - *floor = floorclip[start+i]; - floor++; - *scale = frontscale[start+i]; - scale++; - } -} - -// R_PortalRestoreClipValues -// Inverse of the above. Restores the old value! -void R_PortalRestoreClipValues(INT32 start, INT32 end, INT16 *ceil, INT16 *floor, fixed_t *scale) -{ - INT32 i; - for (i = 0; i < end-start; i++) - { - ceilingclip[start+i] = *ceil; - ceil++; - floorclip[start+i] = *floor; - floor++; - frontscale[start+i] = *scale; - scale++; - } - - // HACKS FOLLOW - for (i = 0; i < start; i++) - { - floorclip[i] = -1; - ceilingclip[i] = (INT16)viewheight; - } - for (i = end; i < vid.width; i++) - { - floorclip[i] = -1; - ceilingclip[i] = (INT16)viewheight; - } -} - // // R_MapPlane // diff --git a/src/r_plane.h b/src/r_plane.h index 6e6a6d49d..bdfc40058 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -72,8 +72,6 @@ extern fixed_t *yslope; extern lighttable_t **planezlight; void R_InitPlanes(void); -void R_PortalStoreClipValues(INT32 start, INT32 end, INT16 *ceil, INT16 *floor, fixed_t *scale); -void R_PortalRestoreClipValues(INT32 start, INT32 end, INT16 *ceil, INT16 *floor, fixed_t *scale); void R_ClearPlanes(void); void R_MapPlane(INT32 y, INT32 x1, INT32 x2); diff --git a/src/r_portal.c b/src/r_portal.c new file mode 100644 index 000000000..2675ae968 --- /dev/null +++ b/src/r_portal.c @@ -0,0 +1,187 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1993-1996 by id Software, Inc. +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2018 by Sonic Team Junior. +// +// 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_portal.c +/// \brief Software renderer portals. + +#include "r_portal.h" +#include "r_plane.h" +#include "r_main.h" // viewheight, viewwidth +#include "z_zone.h" + +UINT8 portalrender; /**< When rendering a portal, it establishes the depth of the current BSP traversal. */ +sector_t *portalcullsector; + +// Linked list for portals. +portal_t *portal_base, *portal_cap; + +line_t *portalclipline; +INT32 portalclipstart, portalclipend; + +boolean portalline; // is curline a portal seg? + +void Portal_InitList (void) +{ + portalrender = 0; + portal_base = portal_cap = NULL; +} + +/** Store the clipping window for a portal in its given range. + * + * The window is copied from the current window at the time + * the function is called, so it is useful for converting one-sided + * lines into portals. + */ +void Portal_ClipStoreFromRange (portal_t* portal) +{ + INT32 start = portal->start; + INT32 end = portal->end; + INT16 *ceil = portal->ceilingclip; + INT16 *floor = portal->floorclip; + fixed_t *scale = portal->frontscale; + + INT32 i; + for (i = 0; i < end-start; i++) + { + *ceil = ceilingclip[start+i]; + ceil++; + *floor = floorclip[start+i]; + floor++; + *scale = frontscale[start+i]; + scale++; + } +} + +/** Apply the clipping window from a portal. + */ +void Portal_ClipApply (const portal_t* portal) +{ + INT32 i; + INT32 start = portal->start; + INT32 end = portal->end; + INT16 *ceil = portal->ceilingclip; + INT16 *floor = portal->floorclip; + fixed_t *scale = portal->frontscale; + + for (i = 0; i < end-start; i++) + { + ceilingclip[start+i] = *ceil; + ceil++; + floorclip[start+i] = *floor; + floor++; + frontscale[start+i] = *scale; + scale++; + } + + // HACKS FOLLOW + for (i = 0; i < start; i++) + { + floorclip[i] = -1; + ceilingclip[i] = (INT16)viewheight; + } + for (i = end; i < vid.width; i++) + { + floorclip[i] = -1; + ceilingclip[i] = (INT16)viewheight; + } +} + +portal_t* Portal_Add (const INT16 x1, const INT16 x2) +{ + portal_t *portal = Z_Malloc(sizeof(portal_t), PU_LEVEL, NULL); + INT16 *ceilingclipsave = Z_Malloc(sizeof(INT16)*(x2-x1), PU_LEVEL, NULL); + INT16 *floorclipsave = Z_Malloc(sizeof(INT16)*(x2-x1), PU_LEVEL, NULL); + fixed_t *frontscalesave = Z_Malloc(sizeof(fixed_t)*(x2-x1), PU_LEVEL, NULL); + + // Linked list. + if (!portal_base) + { + portal_base = portal; + portal_cap = portal; + } + else + { + portal_cap->next = portal; + portal_cap = portal; + } + portal->next = NULL; + + // Store clipping values so they can be restored once the portal is rendered. + portal->ceilingclip = ceilingclipsave; + portal->floorclip = floorclipsave; + portal->frontscale = frontscalesave; + portal->start = x1; + portal->end = x2; + + // Increase recursion level. + portal->pass = portalrender+1; + + return portal; +} + +void Portal_Remove (portal_t* portal) +{ + portal_base = portal->next; + Z_Free(portal->ceilingclip); + Z_Free(portal->floorclip); + Z_Free(portal->frontscale); + Z_Free(portal); +} + +/** Creates a portal out of two lines and a determined screen range. + * + * line1 determines the entrance, and line2 the exit. + * x1 and x2 determine the screen's column bounds. + + * The view's offset from the entry line center is obtained, + * and then rotated&translated to the exit line's center. + * When the portal renders, it will create the illusion of + * the two lines being seamed together. + */ +void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, const INT32 x2) +{ + portal_t* portal = Portal_Add(x1, x2); + + // Offset the portal view by the linedef centers + line_t* start = &lines[line1]; + line_t* dest = &lines[line2]; + + angle_t dangle = R_PointToAngle2(0,0,dest->dx,dest->dy) - R_PointToAngle2(start->dx,start->dy,0,0); + + fixed_t disttopoint; + angle_t angtopoint; + + vertex_t dest_c, start_c; + + // looking glass center + start_c.x = (start->v1->x + start->v2->x) / 2; + start_c.y = (start->v1->y + start->v2->y) / 2; + + // other side center + dest_c.x = (dest->v1->x + dest->v2->x) / 2; + dest_c.y = (dest->v1->y + dest->v2->y) / 2; + + disttopoint = R_PointToDist2(start_c.x, start_c.y, viewx, viewy); + angtopoint = R_PointToAngle2(start_c.x, start_c.y, viewx, viewy); + angtopoint += dangle; + + portal->viewx = dest_c.x + FixedMul(FINECOSINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); + portal->viewy = dest_c.y + FixedMul(FINESINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); + portal->viewz = viewz + dest->frontsector->floorheight - start->frontsector->floorheight; + portal->viewangle = viewangle + dangle; + + portal->clipline = line2; + + Portal_ClipStoreFromRange(portal); + + portalline = true; // this tells R_StoreWallRange that curline is a portal seg +} + + diff --git a/src/r_portal.h b/src/r_portal.h new file mode 100644 index 000000000..8df3db415 --- /dev/null +++ b/src/r_portal.h @@ -0,0 +1,49 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1993-1996 by id Software, Inc. +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2018 by Sonic Team Junior. +// +// 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_portal.h +/// \brief Software renderer portal struct, functions, linked list extern. + +#include "r_data.h" + + +/** Portal structure. + */ +typedef struct portal_s +{ + struct portal_s *next; + + // Viewport. + fixed_t viewx; + fixed_t viewy; + fixed_t viewz; + angle_t viewangle; + + UINT8 pass; /**< Keeps track of the portal's recursion depth. */ + INT32 clipline; /**< Optional clipline for line-based portals. */ + + // Clipping information. + INT32 start; /**< First horizontal pixel coordinate to draw at. */ + INT32 end; /**< Last horizontal pixel coordinate to draw at. */ + INT16 *ceilingclip; /**< Temporary screen top clipping array. */ + INT16 *floorclip; /**< Temporary screen bottom clipping array. */ + fixed_t *frontscale;/**< Temporary screen bottom clipping array. */ +} portal_t; + +extern portal_t* portal_base; +extern portal_t* portal_cap; +extern UINT8 portalrender; + +void Portal_InitList (void); +void Portal_Remove (portal_t* portal); +void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, const INT32 x2); + +void Portal_ClipStoreFromRange (portal_t* portal); +void Portal_ClipApply (const portal_t* portal); diff --git a/src/r_things.c b/src/r_things.c index e8d679b53..f52ce7ca8 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1249,7 +1249,7 @@ static void R_ProjectSprite(mobj_t *thing) } // PORTAL SPRITE CLIPPING - if (portalrender) + if (portalrender && portalclipline) { if (x2 < portalclipstart || x1 > portalclipend) return; @@ -1517,7 +1517,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) return; // PORTAL SPRITE CLIPPING - if (portalrender) + if (portalrender && portalclipline) { if (x2 < portalclipstart || x1 > portalclipend) return; From ae1e3630f82b40b50f0f14c8a68bc04bd022f915 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Sat, 1 Jun 2019 21:26:25 +0200 Subject: [PATCH 02/17] Add visplane portal creation functionality and use it to replace the skybox rendering. The skybox rendering process has been replaced with portals instead. Those are generated after the first BSP tree pass by looking for existing sky visplanes at the time, and their windows are used to define new portals. The skybox portals are still incomplete and cause visual glitches when masked elements are involved. --- src/hardware/hw_main.c | 2 +- src/p_setup.c | 1 - src/r_bsp.c | 1 + src/r_main.c | 60 ++++++-------------------------- src/r_main.h | 2 +- src/r_plane.c | 40 +++++++++++++++------ src/r_plane.h | 2 ++ src/r_portal.c | 79 ++++++++++++++++++++++++++++++++++++++++-- src/r_portal.h | 7 ++-- src/r_state.h | 2 -- 10 files changed, 126 insertions(+), 70 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index b1811eb45..c79452bb5 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -6194,7 +6194,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) } // note: sets viewangle, viewx, viewy, viewz - R_SetupFrame(player, false); // This can stay false because it is only used to set viewsky in r_main.c, which isn't used here + R_SetupFrame(player); // copy view cam position for local use dup_viewx = viewx; diff --git a/src/p_setup.c b/src/p_setup.c index 0602865a9..af4f1f9dd 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3147,7 +3147,6 @@ boolean P_SetupLevel(boolean skipprecip) savedata.lives = 0; } - skyVisible = skyVisible1 = skyVisible2 = true; // assume the skybox is visible on level load. if (loadprecip) // uglier hack { // to make a newly loaded level start on the second frame. INT32 buf = gametic % BACKUPTICS; diff --git a/src/r_bsp.c b/src/r_bsp.c index 5643e777e..58d69ddf4 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -15,6 +15,7 @@ #include "g_game.h" #include "r_local.h" #include "r_state.h" +#include "r_portal.h" // Add seg portals #include "r_splats.h" #include "p_local.h" // camera diff --git a/src/r_main.c b/src/r_main.c index cab0490bf..c9513e390 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -66,8 +66,6 @@ size_t loopcount; fixed_t viewx, viewy, viewz; angle_t viewangle, aimingangle; fixed_t viewcos, viewsin; -boolean viewsky, skyVisible; -boolean skyVisible1, skyVisible2; // saved values of skyVisible for P1 and P2, for splitscreen sector_t *viewsector; player_t *viewplayer; @@ -739,7 +737,7 @@ static void R_SetupFreelook(void) #undef AIMINGTODY -void R_SetupFrame(player_t *player, boolean skybox) +void R_SetupFrame(player_t *player) { camera_t *thiscam; boolean chasecam = false; @@ -769,7 +767,6 @@ void R_SetupFrame(player_t *player, boolean skybox) else if (!chasecam) thiscam->chase = false; - viewsky = !skybox; if (player->awayviewtics) { // cut-away view stuff @@ -858,7 +855,6 @@ void R_SkyboxFrame(player_t *player) thiscam = &camera; // cut-away view stuff - viewsky = true; viewmobj = skyboxmo[0]; #ifdef PARANOIA if (!viewmobj) @@ -1022,9 +1018,6 @@ static void R_PortalFrame(portal_t *portal) void R_RenderPlayerView(player_t *player) { - portal_t *portal; - const boolean skybox = (skyboxmo[0] && cv_skybox.value); - if (cv_homremoval.value && player == &players[displayplayer]) // if this is display player 1 { if (cv_homremoval.value == 1) @@ -1033,37 +1026,7 @@ void R_RenderPlayerView(player_t *player) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 32+(timeinmap&15)); } - // load previous saved value of skyVisible for the player - if (splitscreen && player == &players[secondarydisplayplayer]) - skyVisible = skyVisible2; - else - skyVisible = skyVisible1; - - Portal_InitList(); - - if (skybox && skyVisible) - { - R_SkyboxFrame(player); - - R_ClearClipSegs(); - R_ClearDrawSegs(); - R_ClearPlanes(); - R_ClearSprites(); -#ifdef FLOORSPLATS - R_ClearVisibleFloorSplats(); -#endif - - R_RenderBSPNode((INT32)numnodes - 1); - R_ClipSprites(); - R_DrawPlanes(); -#ifdef FLOORSPLATS - R_DrawVisibleFloorSplats(); -#endif - R_DrawMasked(); - } - - R_SetupFrame(player, skybox); - skyVisible = false; + R_SetupFrame(player); framecount++; validcount++; @@ -1075,6 +1038,7 @@ void R_RenderPlayerView(player_t *player) #ifdef FLOORSPLATS R_ClearVisibleFloorSplats(); #endif + Portal_InitList(); // check for new console commands. NetUpdate(); @@ -1086,7 +1050,9 @@ void R_RenderPlayerView(player_t *player) mytotal = 0; ProfZeroTimer(); #endif + R_RenderBSPNode((INT32)numnodes - 1); + R_ClipSprites(); #ifdef TIMING RDMSR(0x10, &mycount); @@ -1096,9 +1062,15 @@ void R_RenderPlayerView(player_t *player) #endif //profile stuff --------------------------------------------------------- + // Add skybox portals caused by sky visplanes. + if (cv_skybox.value) + Portal_AddSkyboxPortals(); + // Portal rendering. Hijacks the BSP traversal. if (portal_base) { + portal_t *portal; + for(portal = portal_base; portal; portal = portal_base) { portalrender = portal->pass; // Recursiveness depth. @@ -1135,16 +1107,6 @@ void R_RenderPlayerView(player_t *player) // draw mid texture and sprite // And now 3D floors/sides! R_DrawMasked(); - - // Check for new console commands. - NetUpdate(); - - // save value to skyVisible1 or skyVisible2 - // this is so that P1 can't affect whether P2 can see a skybox or not, or vice versa - if (splitscreen && player == &players[secondarydisplayplayer]) - skyVisible2 = skyVisible; - else - skyVisible1 = skyVisible; } // ========================================================================= diff --git a/src/r_main.h b/src/r_main.h index 6ae5aa221..1d82a01b9 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -94,7 +94,7 @@ void R_ExecuteSetViewSize(void); void R_SkyboxFrame(player_t *player); -void R_SetupFrame(player_t *player, boolean skybox); +void R_SetupFrame(player_t *player); // Called by G_Drawer. void R_RenderPlayerView(player_t *player); diff --git a/src/r_plane.c b/src/r_plane.c index 5cd9b26b5..18e5fda52 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -23,6 +23,8 @@ #include "r_state.h" #include "r_splats.h" // faB(21jan):testing #include "r_sky.h" +#include "r_portal.h" + #include "v_video.h" #include "w_wad.h" #include "z_zone.h" @@ -679,16 +681,6 @@ static void R_DrawSkyPlane(visplane_t *pl) INT32 x; INT32 angle; - // If we're not supposed to draw the sky (e.g. for skyboxes), don't do anything! - // This probably utterly ruins sky rendering for FOFs and polyobjects, unfortunately - if (!viewsky) - { - // Mark that the sky was visible here for next tic - // (note: this is a hack and it sometimes can cause HOMs to appear for a tic IIRC) - skyVisible = true; - return; - } - // 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) wallcolfunc = walldrawerfunc; @@ -1186,3 +1178,31 @@ void R_PlaneBounds(visplane_t *plane) plane->high = hi; plane->low = low; } + +/** Creates portals for the currently existing sky visplanes. + * The visplanes are also removed and cleared from the list. + */ +void Portal_AddSkyboxPortals (void) +{ + visplane_t *pl; + INT32 i; + UINT16 count = 0; + + for (i = 0; i < MAXVISPLANES; i++, pl++) + { + for (pl = visplanes[i]; pl; pl = pl->next) + { + if (pl->picnum == skyflatnum) + { + Portal_AddSkybox(pl); + + pl->minx = 0; + pl->maxx = -1; + + count++; + } + } + } + + CONS_Debug(DBG_RENDER, "Skybox portals: %d\n", count); +} diff --git a/src/r_plane.h b/src/r_plane.h index bdfc40058..c101e3218 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -120,4 +120,6 @@ typedef struct planemgr_s extern visffloor_t ffloor[MAXFFLOORS]; extern INT32 numffloors; + +void Portal_AddSkyboxPortals (void); #endif diff --git a/src/r_portal.c b/src/r_portal.c index 2675ae968..15efc79ba 100644 --- a/src/r_portal.c +++ b/src/r_portal.c @@ -13,7 +13,9 @@ #include "r_portal.h" #include "r_plane.h" -#include "r_main.h" // viewheight, viewwidth +#include "r_main.h" +#include "doomstat.h" +#include "p_spec.h" // Skybox viewpoints #include "z_zone.h" UINT8 portalrender; /**< When rendering a portal, it establishes the depth of the current BSP traversal. */ @@ -39,7 +41,7 @@ void Portal_InitList (void) * the function is called, so it is useful for converting one-sided * lines into portals. */ -void Portal_ClipStoreFromRange (portal_t* portal) +void Portal_ClipRange (portal_t* portal) { INT32 start = portal->start; INT32 end = portal->end; @@ -179,9 +181,80 @@ void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, con portal->clipline = line2; - Portal_ClipStoreFromRange(portal); + Portal_ClipRange(portal); portalline = true; // this tells R_StoreWallRange that curline is a portal seg } +/** Store the clipping window for a portal using a visplane. + * + * Since visplanes top/bottom windows work in an identical way, + * it can just be copied almost directly. + */ +static void Portal_ClipVisplane (const visplane_t* plane, portal_t* portal) +{ + INT16 start = portal->start; + INT16 end = portal->end; + INT32 i; + for (i = 0; i < end - start; i++) + { + portal->ceilingclip[i] = plane->top[i + start]; + portal->floorclip[i] = plane->bottom[i + start] + 1; + } +} + +extern INT32 viewwidth; + +/** Creates a skybox portal out of a visplane. + * + * Applies the necessary offsets and rotation to give + * a depth illusion to the skybox. + */ +void Portal_AddSkybox (const visplane_t* plane) +{ + INT16 start = plane->minx; + INT16 end = plane->maxx + 1; + mapheader_t *mh; + portal_t* portal; + + if (!(start < end)) + return; + + portal = Portal_Add(start, end); + + Portal_ClipVisplane(plane, portal); + + portal->viewx = skyboxmo[0]->x; + portal->viewy = skyboxmo[0]->y; + portal->viewz = skyboxmo[0]->z; + portal->viewangle = viewangle + skyboxmo[0]->angle; + + mh = mapheaderinfo[gamemap-1]; + + // If a relative viewpoint exists, offset the viewpoint. + if (skyboxmo[1]) + { + fixed_t x = 0, y = 0; + + if (mh->skybox_scalex > 0) + x = (viewx - skyboxmo[1]->x) / mh->skybox_scalex; + else if (mh->skybox_scalex < 0) + x = (viewx - skyboxmo[1]->x) * -mh->skybox_scalex; + + if (mh->skybox_scaley > 0) + y = (viewy - skyboxmo[1]->y) / mh->skybox_scaley; + else if (mh->skybox_scaley < 0) + y = (viewy - skyboxmo[1]->y) * -mh->skybox_scaley; + + portal->viewx += x; + portal->viewy += y; + } + + if (mh->skybox_scalez > 0) + portal->viewz += viewz / mh->skybox_scalez; + else if (mh->skybox_scalez < 0) + portal->viewz += viewz * -mh->skybox_scalez; + + portal->clipline = -1; +} diff --git a/src/r_portal.h b/src/r_portal.h index 8df3db415..9426aaf6a 100644 --- a/src/r_portal.h +++ b/src/r_portal.h @@ -12,9 +12,9 @@ /// \brief Software renderer portal struct, functions, linked list extern. #include "r_data.h" +#include "r_plane.h" // visplanes - -/** Portal structure. +/** Portal structure for the software renderer. */ typedef struct portal_s { @@ -44,6 +44,7 @@ extern UINT8 portalrender; void Portal_InitList (void); void Portal_Remove (portal_t* portal); void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, const INT32 x2); +void Portal_AddSkybox (const visplane_t* plane); -void Portal_ClipStoreFromRange (portal_t* portal); +void Portal_ClipRange (portal_t* portal); void Portal_ClipApply (const portal_t* portal); diff --git a/src/r_state.h b/src/r_state.h index 9c8ce51d6..4959b55bc 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -80,8 +80,6 @@ extern side_t *sides; // extern fixed_t viewx, viewy, viewz; extern angle_t viewangle, aimingangle; -extern boolean viewsky, skyVisible; -extern boolean skyVisible1, skyVisible2; // saved values of skyVisible for P1 and P2, for splitscreen extern sector_t *viewsector; extern player_t *viewplayer; extern UINT8 portalrender; From c35769e5de99547fde91fb8d5d5cf46022f3ede7 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Mon, 3 Jun 2019 13:04:04 +0200 Subject: [PATCH 03/17] Moved validcount++ to where it used to be. It seems to screw up the portal rendering in odd ways if it's in the wrong position. I apologize for not even knowing what it's meant to do nor how it works. --- src/r_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/r_main.c b/src/r_main.c index c9513e390..2e43d8838 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1087,14 +1087,14 @@ void R_RenderPlayerView(player_t *player) // that were previously stored. Portal_ClipApply(portal); + validcount++; + // Render the BSP from the new viewpoint, and clip // any sprites with the new clipsegs and window. R_RenderBSPNode((INT32)numnodes - 1); R_ClipSprites(); Portal_Remove(portal); - - validcount++; } portalcullsector = NULL; // Just in case... From 84a52a0f80f8b1878d7ef27695ef6b7ae41ef237 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Mon, 3 Jun 2019 13:33:12 +0200 Subject: [PATCH 04/17] Moving away more portal-related global vars to r_portal. --- src/r_portal.h | 4 ++++ src/r_segs.c | 1 + src/r_state.h | 4 ---- src/r_things.c | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/r_portal.h b/src/r_portal.h index 9426aaf6a..fad62a298 100644 --- a/src/r_portal.h +++ b/src/r_portal.h @@ -41,6 +41,10 @@ extern portal_t* portal_base; extern portal_t* portal_cap; extern UINT8 portalrender; +extern sector_t *portalcullsector; +extern line_t *portalclipline; +extern INT32 portalclipstart, portalclipend; + void Portal_InitList (void); void Portal_Remove (portal_t* portal); void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, const INT32 x2); diff --git a/src/r_segs.c b/src/r_segs.c index 03c5fb6e5..36ed029ee 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -15,6 +15,7 @@ #include "r_local.h" #include "r_sky.h" +#include "r_portal.h" #include "r_splats.h" #include "w_wad.h" diff --git a/src/r_state.h b/src/r_state.h index 4959b55bc..da9425bdf 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -82,10 +82,6 @@ extern fixed_t viewx, viewy, viewz; extern angle_t viewangle, aimingangle; extern sector_t *viewsector; extern player_t *viewplayer; -extern UINT8 portalrender; -extern sector_t *portalcullsector; -extern line_t *portalclipline; -extern INT32 portalclipstart, portalclipend; extern consvar_t cv_allowmlook; extern consvar_t cv_maxportals; diff --git a/src/r_things.c b/src/r_things.c index f52ce7ca8..f3113b043 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -24,6 +24,7 @@ #include "i_video.h" // rendermode #include "r_things.h" #include "r_plane.h" +#include "r_portal.h" #include "p_tick.h" #include "p_local.h" #include "p_slopes.h" From 96cfecc41af6143149d2291aeec121ad60e5be06 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Tue, 4 Jun 2019 20:15:42 +0200 Subject: [PATCH 05/17] Created drawnode lists for each view/portal. Each shall eventually have its specific vissprites/drawsegs; currently only drawsegs are stored in their correct list, vissprites are stored in the first list as a placeholder. The idea is to sort each list individually, and then render their masked elements, starting from the last drawnode list. This retains a non-recursive function calling method while still rendering things in order. --- src/r_main.c | 18 ++++++++++++++- src/r_things.c | 62 +++++++++++++++++++++++++++++++++----------------- src/r_things.h | 14 +++++++++++- 3 files changed, 71 insertions(+), 23 deletions(-) diff --git a/src/r_main.c b/src/r_main.c index 2e43d8838..6e5784f58 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1018,6 +1018,9 @@ static void R_PortalFrame(portal_t *portal) void R_RenderPlayerView(player_t *player) { + UINT8 nummasks = 1; + maskcount_t* masks = malloc(sizeof(maskcount_t)); + if (cv_homremoval.value && player == &players[displayplayer]) // if this is display player 1 { if (cv_homremoval.value == 1) @@ -1051,7 +1054,12 @@ void R_RenderPlayerView(player_t *player) ProfZeroTimer(); #endif + masks[nummasks - 1].drawsegs[0] = 0; + masks[nummasks - 1].vissprites[0] = 0; R_RenderBSPNode((INT32)numnodes - 1); + masks[nummasks - 1].drawsegs[1] = ds_p - drawsegs; + masks[nummasks - 1].vissprites[1] = visspritecount; + R_ClipSprites(); #ifdef TIMING @@ -1091,7 +1099,13 @@ void R_RenderPlayerView(player_t *player) // Render the BSP from the new viewpoint, and clip // any sprites with the new clipsegs and window. + masks = realloc(masks, (++nummasks)*sizeof(maskcount_t)); + + masks[nummasks - 1].drawsegs[0] = ds_p - drawsegs; + masks[nummasks - 1].vissprites[0] = visspritecount; R_RenderBSPNode((INT32)numnodes - 1); + masks[nummasks - 1].drawsegs[1] = ds_p - drawsegs; + masks[nummasks - 1].vissprites[1] = visspritecount; R_ClipSprites(); Portal_Remove(portal); @@ -1106,7 +1120,9 @@ void R_RenderPlayerView(player_t *player) #endif // draw mid texture and sprite // And now 3D floors/sides! - R_DrawMasked(); + R_DrawMasked(masks, nummasks); + + free(masks); } // ========================================================================= diff --git a/src/r_things.c b/src/r_things.c index f3113b043..f984d75d7 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -445,7 +445,7 @@ void R_AddSpriteDefs(UINT16 wadnum) // // GAME FUNCTIONS // -static UINT32 visspritecount; +UINT32 visspritecount; static UINT32 clippedvissprites; static vissprite_t *visspritechunks[MAXVISSPRITES >> VISSPRITECHUNKBITS] = {NULL}; @@ -1838,9 +1838,8 @@ void R_SortVisSprites(void) static drawnode_t *R_CreateDrawNode(drawnode_t *link); static drawnode_t nodebankhead; -static drawnode_t nodehead; -static void R_CreateDrawNodes(void) +static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean tempskip) { drawnode_t *entry; drawseg_t *ds; @@ -1853,13 +1852,13 @@ static void R_CreateDrawNodes(void) fixed_t scale = 0; // Add the 3D floors, thicksides, and masked textures... - for (ds = ds_p; ds-- > drawsegs ;) + for (ds = drawsegs + mask->drawsegs[1]; ds-- > drawsegs + mask->drawsegs[0];) { if (ds->numthicksides) { for (i = 0; i < ds->numthicksides; i++) { - entry = R_CreateDrawNode(&nodehead); + entry = R_CreateDrawNode(head); entry->thickseg = ds; entry->ffloor = ds->thicksides[i]; } @@ -1874,7 +1873,7 @@ static void R_CreateDrawNodes(void) ; else { // Put it in! - entry = R_CreateDrawNode(&nodehead); + entry = R_CreateDrawNode(head); entry->plane = plane; entry->seg = ds; } @@ -1883,7 +1882,7 @@ static void R_CreateDrawNodes(void) #endif if (ds->maskedtexturecol) { - entry = R_CreateDrawNode(&nodehead); + entry = R_CreateDrawNode(head); entry->seg = ds; } if (ds->numffloorplanes) @@ -1914,7 +1913,7 @@ static void R_CreateDrawNodes(void) } if (best != -1) { - entry = R_CreateDrawNode(&nodehead); + entry = R_CreateDrawNode(head); entry->plane = ds->ffloorplanes[best]; entry->seg = ds; ds->ffloorplanes[best] = NULL; @@ -1925,6 +1924,9 @@ static void R_CreateDrawNodes(void) } } + if (tempskip) + return; + #ifdef POLYOBJECTS_PLANES // find all the remaining polyobject planes and add them on the end of the list // probably this is a terrible idea if we wanted them to be sorted properly @@ -1941,7 +1943,7 @@ static void R_CreateDrawNodes(void) PolyObjects[i].visplane = NULL; continue; } - entry = R_CreateDrawNode(&nodehead); + entry = R_CreateDrawNode(head); entry->plane = plane; // note: no seg is set, for what should be obvious reasons PolyObjects[i].visplane = NULL; @@ -1959,7 +1961,7 @@ static void R_CreateDrawNodes(void) sintersect = (rover->x1 + rover->x2) / 2; - for (r2 = nodehead.next; r2 != &nodehead; r2 = r2->next) + for (r2 = head->next; r2 != head; r2 = r2->next) { if (r2->plane) { @@ -2098,9 +2100,9 @@ static void R_CreateDrawNodes(void) } } } - if (r2 == &nodehead) + if (r2 == head) { - entry = R_CreateDrawNode(&nodehead); + entry = R_CreateDrawNode(head); entry->sprite = rover; } } @@ -2142,25 +2144,24 @@ static void R_DoneWithNode(drawnode_t *node) (node->prev = &nodebankhead)->next = node; } -static void R_ClearDrawNodes(void) +static void R_ClearDrawNodes(drawnode_t* head) { drawnode_t *rover; drawnode_t *next; - for (rover = nodehead.next; rover != &nodehead ;) + for (rover = head->next; rover != head;) { next = rover->next; R_DoneWithNode(rover); rover = next; } - nodehead.next = nodehead.prev = &nodehead; + head->next = head->prev = head; } void R_InitDrawNodes(void) { nodebankhead.next = nodebankhead.prev = &nodebankhead; - nodehead.next = nodehead.prev = &nodehead; } // @@ -2374,14 +2375,12 @@ void R_ClipSprites(void) // // R_DrawMasked // -void R_DrawMasked(void) +static void R_DrawMaskedList (drawnode_t* head) { drawnode_t *r2; drawnode_t *next; - R_CreateDrawNodes(); - - for (r2 = nodehead.next; r2 != &nodehead; r2 = r2->next) + for (r2 = head->next; r2 != head; r2 = r2->next) { if (r2->plane) { @@ -2433,7 +2432,28 @@ void R_DrawMasked(void) r2 = next; } } - R_ClearDrawNodes(); +} + +void R_DrawMasked(maskcount_t* masks, UINT8 nummasks) +{ + drawnode_t heads[nummasks]; + INT8 i; + + for (i = 0; i < nummasks; i++) + { + heads[i].next = heads[i].prev = &heads[i]; + + R_CreateDrawNodes(&masks[i], &heads[i], i != 0 ? true : false); + } + + for (i = 0; i < nummasks; i++) + CONS_Printf("Mask no.%d:\ndrawsegs: %d\n vissprites: %d\n\n", i, masks[i].drawsegs[1] - masks[i].drawsegs[0], masks[i].vissprites[1] - masks[i].vissprites[0]); + + for (; nummasks > 0; nummasks--) + { + R_DrawMaskedList(&heads[nummasks - 1]); + R_ClearDrawNodes(&heads[nummasks - 1]); + } } // ========================================================================== diff --git a/src/r_things.h b/src/r_things.h index 1003103ca..7aa594c79 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -56,7 +56,18 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel); void R_InitSprites(void); void R_ClearSprites(void); void R_ClipSprites(void); -void R_DrawMasked(void); + +/** Used to count the amount of masked elements + * per portal to later group them in separate + * drawnode lists. + */ +typedef struct +{ + size_t drawsegs[2]; + size_t vissprites[2]; +} maskcount_t; + +void R_DrawMasked(maskcount_t* masks, UINT8 nummasks); // ----------- // SKINS STUFF @@ -207,6 +218,7 @@ typedef struct drawnode_s extern INT32 numskins; extern skin_t skins[MAXSKINS]; +extern UINT32 visspritecount; void SetPlayerSkin(INT32 playernum,const char *skinname); void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002 From a1f429030ce24b5085014d5c25ecd0e62b1c59bb Mon Sep 17 00:00:00 2001 From: Nev3r Date: Tue, 4 Jun 2019 21:04:35 +0200 Subject: [PATCH 06/17] Set a default frontscale for visplane portals. I don't know whether this is necessary or not but I'm poking blindly trying to fix the sorting issues for now. --- src/r_portal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/r_portal.c b/src/r_portal.c index 15efc79ba..0a0f4777d 100644 --- a/src/r_portal.c +++ b/src/r_portal.c @@ -201,6 +201,7 @@ static void Portal_ClipVisplane (const visplane_t* plane, portal_t* portal) { portal->ceilingclip[i] = plane->top[i + start]; portal->floorclip[i] = plane->bottom[i + start] + 1; + portal->frontscale[i] = INT32_MAX; } } From 906b366e1bffe43340f9b0d4ecd560b6d40d92e8 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Wed, 5 Jun 2019 12:10:59 +0200 Subject: [PATCH 07/17] Masked elements are now fully grouped individually for each portal/view; fixed viewz-related glitches,. The drawnodes are now fully grouped in separate lists, and then sorted individually. This fixes sorting problems caused by portals belonging to differently perceived scales (skyboxes for example). Drawsegs and vissprite/drawnode sorting require the viewz, so the viewz is stored for each portal/view, and then restored when needed; without this, the rendering process erroneously sorts the elements, and draws some at wrong positions. --- src/r_main.c | 3 +++ src/r_portal.c | 10 +++++++++- src/r_things.c | 39 +++++++++++++++++++-------------------- src/r_things.h | 2 +- 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/r_main.c b/src/r_main.c index 6e5784f58..8e0989f3b 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1056,6 +1056,7 @@ void R_RenderPlayerView(player_t *player) masks[nummasks - 1].drawsegs[0] = 0; masks[nummasks - 1].vissprites[0] = 0; + masks[nummasks - 1].viewz = viewz; R_RenderBSPNode((INT32)numnodes - 1); masks[nummasks - 1].drawsegs[1] = ds_p - drawsegs; masks[nummasks - 1].vissprites[1] = visspritecount; @@ -1103,6 +1104,7 @@ void R_RenderPlayerView(player_t *player) masks[nummasks - 1].drawsegs[0] = ds_p - drawsegs; masks[nummasks - 1].vissprites[0] = visspritecount; + masks[nummasks - 1].viewz = viewz; R_RenderBSPNode((INT32)numnodes - 1); masks[nummasks - 1].drawsegs[1] = ds_p - drawsegs; masks[nummasks - 1].vissprites[1] = visspritecount; @@ -1118,6 +1120,7 @@ void R_RenderPlayerView(player_t *player) #ifdef FLOORSPLATS R_DrawVisibleFloorSplats(); #endif + // draw mid texture and sprite // And now 3D floors/sides! R_DrawMasked(masks, nummasks); diff --git a/src/r_portal.c b/src/r_portal.c index 0a0f4777d..b3d363f63 100644 --- a/src/r_portal.c +++ b/src/r_portal.c @@ -199,7 +199,15 @@ static void Portal_ClipVisplane (const visplane_t* plane, portal_t* portal) for (i = 0; i < end - start; i++) { - portal->ceilingclip[i] = plane->top[i + start]; + if (plane->bottom[i + start] == 0) + { + portal->ceilingclip[i] = 0; + portal->floorclip[i] = 0; + continue; + } + + + portal->ceilingclip[i] = plane->top[i + start] - 1; portal->floorclip[i] = plane->bottom[i + start] + 1; portal->frontscale[i] = INT32_MAX; } diff --git a/src/r_things.c b/src/r_things.c index f984d75d7..8be926adf 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1697,9 +1697,7 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) // // R_SortVisSprites // -static vissprite_t vsprsortedhead; - -void R_SortVisSprites(void) +static void R_SortVisSprites(vissprite_t* vsprsortedhead, UINT32 start, UINT32 end) { UINT32 i, linkedvissprites = 0; vissprite_t *ds, *dsprev, *dsnext, *dsfirst; @@ -1708,20 +1706,17 @@ void R_SortVisSprites(void) fixed_t bestscale; INT32 bestdispoffset; - if (!visspritecount) - return; - unsorted.next = unsorted.prev = &unsorted; - dsfirst = R_GetVisSprite(0); + dsfirst = R_GetVisSprite(start); // The first's prev and last's next will be set to // nonsense, but are fixed in a moment - for (i = 0, dsnext = dsfirst, ds = NULL; i < visspritecount; i++) + for (i = start, dsnext = dsfirst, ds = NULL; i < end; i++) { dsprev = ds; ds = dsnext; - if (i < visspritecount - 1) dsnext = R_GetVisSprite(i + 1); + if (i < end - 1) dsnext = R_GetVisSprite(i + 1); ds->next = dsnext; ds->prev = dsprev; @@ -1799,8 +1794,8 @@ void R_SortVisSprites(void) } // pull the vissprites out by scale - vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead; - for (i = 0; i < visspritecount-linkedvissprites; i++) + vsprsortedhead->next = vsprsortedhead->prev = vsprsortedhead; + for (i = start; i < end-linkedvissprites; i++) { bestscale = bestdispoffset = INT32_MAX; for (ds = unsorted.next; ds != &unsorted; ds = ds->next) @@ -1825,10 +1820,10 @@ void R_SortVisSprites(void) } best->next->prev = best->prev; best->prev->next = best->next; - best->next = &vsprsortedhead; - best->prev = vsprsortedhead.prev; - vsprsortedhead.prev->next = best; - vsprsortedhead.prev = best; + best->next = vsprsortedhead; + best->prev = vsprsortedhead->prev; + vsprsortedhead->prev->next = best; + vsprsortedhead->prev = best; } } @@ -1846,6 +1841,7 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps INT32 i, p, best, x1, x2; fixed_t bestdelta, delta; vissprite_t *rover; + static vissprite_t vsprsortedhead; drawnode_t *r2; visplane_t *plane; INT32 sintersect; @@ -1950,10 +1946,12 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps } #endif - if (visspritecount == 0) + // No vissprites in this mask? + if (mask->vissprites[1] - mask->vissprites[0] == 0) return; - R_SortVisSprites(); + R_SortVisSprites(&vsprsortedhead, mask->vissprites[0], mask->vissprites[1]); + for (rover = vsprsortedhead.prev; rover != &vsprsortedhead; rover = rover->prev) { if (rover->szt > vid.height || rover->sz < 0) @@ -2436,14 +2434,14 @@ static void R_DrawMaskedList (drawnode_t* head) void R_DrawMasked(maskcount_t* masks, UINT8 nummasks) { - drawnode_t heads[nummasks]; + drawnode_t heads[nummasks]; /**< Drawnode lists; as many as number of views/portals. */ INT8 i; for (i = 0; i < nummasks; i++) { heads[i].next = heads[i].prev = &heads[i]; - - R_CreateDrawNodes(&masks[i], &heads[i], i != 0 ? true : false); + viewz = masks[i].viewz; + R_CreateDrawNodes(&masks[i], &heads[i], false); } for (i = 0; i < nummasks; i++) @@ -2451,6 +2449,7 @@ void R_DrawMasked(maskcount_t* masks, UINT8 nummasks) for (; nummasks > 0; nummasks--) { + viewz = masks[nummasks - 1].viewz; R_DrawMaskedList(&heads[nummasks - 1]); R_ClearDrawNodes(&heads[nummasks - 1]); } diff --git a/src/r_things.h b/src/r_things.h index 7aa594c79..08a13c1ce 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -45,7 +45,6 @@ extern fixed_t windowbottom; void R_DrawMaskedColumn(column_t *column); void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight); -void R_SortVisSprites(void); //faB: find sprites in wadfile, replace existing, add new ones // (only sprites from namelist are added or replaced) @@ -65,6 +64,7 @@ typedef struct { size_t drawsegs[2]; size_t vissprites[2]; + fixed_t viewz; /**< View z stored at the time of the BSP traversal for the view/portal. Masked sorting/drawing needs it. */ } maskcount_t; void R_DrawMasked(maskcount_t* masks, UINT8 nummasks); From 819169f3789d5306e7352929141a8e79e742318b Mon Sep 17 00:00:00 2001 From: Nev3r Date: Wed, 5 Jun 2019 16:35:48 +0200 Subject: [PATCH 08/17] Vissprite clipping improvements. Vissprites are now only clipped against their respective portal's geometry obtained from their BSP run. Additionally, if a portal is provided, they're clipped to the portal's clip boundaries. The work on this branch should conclude after a pair of remaining glitches are fixed. --- src/r_main.c | 6 ++--- src/r_portal.c | 36 ++++++++++++++++--------- src/r_portal.h | 5 ++++ src/r_things.c | 71 ++++++++++++++++++++++++++++++-------------------- src/r_things.h | 3 ++- 5 files changed, 77 insertions(+), 44 deletions(-) diff --git a/src/r_main.c b/src/r_main.c index 8e0989f3b..6104b7ca3 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1061,8 +1061,7 @@ void R_RenderPlayerView(player_t *player) masks[nummasks - 1].drawsegs[1] = ds_p - drawsegs; masks[nummasks - 1].vissprites[1] = visspritecount; - - R_ClipSprites(); + R_ClipSprites(drawsegs, NULL); #ifdef TIMING RDMSR(0x10, &mycount); mytotal += mycount; // 64bit add @@ -1108,7 +1107,8 @@ void R_RenderPlayerView(player_t *player) R_RenderBSPNode((INT32)numnodes - 1); masks[nummasks - 1].drawsegs[1] = ds_p - drawsegs; masks[nummasks - 1].vissprites[1] = visspritecount; - R_ClipSprites(); + + R_ClipSprites(ds_p - (masks[nummasks - 1].drawsegs[1] - masks[nummasks - 1].drawsegs[0]), portal); Portal_Remove(portal); } diff --git a/src/r_portal.c b/src/r_portal.c index b3d363f63..4825bb511 100644 --- a/src/r_portal.c +++ b/src/r_portal.c @@ -17,6 +17,7 @@ #include "doomstat.h" #include "p_spec.h" // Skybox viewpoints #include "z_zone.h" +#include "r_things.h" UINT8 portalrender; /**< When rendering a portal, it establishes the depth of the current BSP traversal. */ sector_t *portalcullsector; @@ -98,9 +99,9 @@ void Portal_ClipApply (const portal_t* portal) portal_t* Portal_Add (const INT16 x1, const INT16 x2) { portal_t *portal = Z_Malloc(sizeof(portal_t), PU_LEVEL, NULL); - INT16 *ceilingclipsave = Z_Malloc(sizeof(INT16)*(x2-x1), PU_LEVEL, NULL); - INT16 *floorclipsave = Z_Malloc(sizeof(INT16)*(x2-x1), PU_LEVEL, NULL); - fixed_t *frontscalesave = Z_Malloc(sizeof(fixed_t)*(x2-x1), PU_LEVEL, NULL); + INT16 *ceilingclipsave = Z_Malloc(sizeof(INT16)*(x2-x1 + 1), PU_LEVEL, NULL); + INT16 *floorclipsave = Z_Malloc(sizeof(INT16)*(x2-x1 + 1), PU_LEVEL, NULL); + fixed_t *frontscalesave = Z_Malloc(sizeof(fixed_t)*(x2-x1 + 1), PU_LEVEL, NULL); // Linked list. if (!portal_base) @@ -199,15 +200,7 @@ static void Portal_ClipVisplane (const visplane_t* plane, portal_t* portal) for (i = 0; i < end - start; i++) { - if (plane->bottom[i + start] == 0) - { - portal->ceilingclip[i] = 0; - portal->floorclip[i] = 0; - continue; - } - - - portal->ceilingclip[i] = plane->top[i + start] - 1; + portal->ceilingclip[i] = plane->top[i + start]; portal->floorclip[i] = plane->bottom[i + start] + 1; portal->frontscale[i] = INT32_MAX; } @@ -230,6 +223,25 @@ void Portal_AddSkybox (const visplane_t* plane) if (!(start < end)) return; + /** Trims a visplane's horizontal gap to match its render area. + * + * Visplanes' minx/maxx may sometimes exceed the area they're + * covering. This merely adjusts the boundaries to the next + * valid area. + */ + + while (plane->bottom[start] == 0 && plane->top[start] == 65535 && start < end) + { + start++; + } + + + while (plane->bottom[end - 1] == 0 && plane->top[start] == 65535 && end > start) + { + end--; + } + + portal = Portal_Add(start, end); Portal_ClipVisplane(plane, portal); diff --git a/src/r_portal.h b/src/r_portal.h index fad62a298..f7d2fb2fe 100644 --- a/src/r_portal.h +++ b/src/r_portal.h @@ -11,6 +11,9 @@ /// \file r_portal.h /// \brief Software renderer portal struct, functions, linked list extern. +#ifndef __R_PORTAL__ +#define __R_PORTAL__ + #include "r_data.h" #include "r_plane.h" // visplanes @@ -52,3 +55,5 @@ void Portal_AddSkybox (const visplane_t* plane); void Portal_ClipRange (portal_t* portal); void Portal_ClipApply (const portal_t* portal); + +#endif diff --git a/src/r_things.c b/src/r_things.c index 8be926adf..e0cf34dba 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2185,7 +2185,7 @@ static void R_DrawPrecipitationSprite(vissprite_t *spr) // R_ClipSprites // Clips vissprites without drawing, so that portals can work. -Red -void R_ClipSprites(void) +void R_ClipSprites(drawseg_t* dsstart, portal_t* portal) { vissprite_t *spr; for (; clippedvissprites < visspritecount; clippedvissprites++) @@ -2211,7 +2211,7 @@ void R_ClipSprites(void) // and buggy, by going past LEFT end of array: // for (ds = ds_p-1; ds >= drawsegs; ds--) old buggy code - for (ds = ds_p; ds-- > drawsegs ;) + for (ds = ds_p; ds-- > dsstart;) { // determine if the drawseg obscures the sprite if (ds->x1 > spr->x2 || @@ -2223,34 +2223,37 @@ void R_ClipSprites(void) continue; } - if (ds->portalpass > 0 && ds->portalpass <= portalrender) - continue; // is a portal + if (ds->portalpass != 66) + { + if (ds->portalpass > 0 && ds->portalpass <= portalrender) + continue; // is a portal + + if (ds->scale1 > ds->scale2) + { + lowscale = ds->scale2; + scale = ds->scale1; + } + else + { + lowscale = ds->scale1; + scale = ds->scale2; + } + + if (scale < spr->sortscale || + (lowscale < spr->sortscale && + !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) + { + // masked mid texture? + /*if (ds->maskedtexturecol) + R_RenderMaskedSegRange (ds, r1, r2);*/ + // seg is behind sprite + continue; + } + } r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1; r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2; - if (ds->scale1 > ds->scale2) - { - lowscale = ds->scale2; - scale = ds->scale1; - } - else - { - lowscale = ds->scale1; - scale = ds->scale2; - } - - if (scale < spr->sortscale || - (lowscale < spr->sortscale && - !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) - { - // masked mid texture? - /*if (ds->maskedtexturecol) - R_RenderMaskedSegRange (ds, r1, r2);*/ - // seg is behind sprite - continue; - } - // clip this piece of the sprite silhouette = ds->silhouette; @@ -2367,6 +2370,17 @@ void R_ClipSprites(void) //Fab : 26-04-98: was -1, now clips against console bottom spr->cliptop[x] = (INT16)con_clipviewtop; } + + if (portal) + { + for (x = spr->x1; x <= spr->x2; x++) + { + if (spr->clipbot[x] > portal->floorclip[x - portal->start]) + spr->clipbot[x] = portal->floorclip[x - portal->start]; + if (spr->cliptop[x] < portal->ceilingclip[x - portal->start]) + spr->cliptop[x] = portal->ceilingclip[x - portal->start]; + } + } } } @@ -2444,12 +2458,13 @@ void R_DrawMasked(maskcount_t* masks, UINT8 nummasks) R_CreateDrawNodes(&masks[i], &heads[i], false); } - for (i = 0; i < nummasks; i++) - CONS_Printf("Mask no.%d:\ndrawsegs: %d\n vissprites: %d\n\n", i, masks[i].drawsegs[1] - masks[i].drawsegs[0], masks[i].vissprites[1] - masks[i].vissprites[0]); + //for (i = 0; i < nummasks; i++) + // CONS_Printf("Mask no.%d:\ndrawsegs: %d\n vissprites: %d\n\n", i, masks[i].drawsegs[1] - masks[i].drawsegs[0], masks[i].vissprites[1] - masks[i].vissprites[0]); for (; nummasks > 0; nummasks--) { viewz = masks[nummasks - 1].viewz; + R_DrawMaskedList(&heads[nummasks - 1]); R_ClearDrawNodes(&heads[nummasks - 1]); } diff --git a/src/r_things.h b/src/r_things.h index 08a13c1ce..27c45def4 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -16,6 +16,7 @@ #include "sounds.h" #include "r_plane.h" +#include "r_portal.h" // "Left" and "Right" character symbols for additional rotation functionality #define ROT_L ('L' - '0') @@ -54,7 +55,7 @@ void R_AddSpriteDefs(UINT16 wadnum); void R_AddSprites(sector_t *sec, INT32 lightlevel); void R_InitSprites(void); void R_ClearSprites(void); -void R_ClipSprites(void); +void R_ClipSprites(drawseg_t* dsstart, portal_t* portal); /** Used to count the amount of masked elements * per portal to later group them in separate From f0b79697e5529f4e29ac0267ceeeb045e5f28da1 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Wed, 5 Jun 2019 18:45:36 +0200 Subject: [PATCH 09/17] Fix sigsegv when there is no main skybox viewpoint. --- src/r_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_main.c b/src/r_main.c index 6104b7ca3..b1a14fe0b 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1071,7 +1071,7 @@ void R_RenderPlayerView(player_t *player) //profile stuff --------------------------------------------------------- // Add skybox portals caused by sky visplanes. - if (cv_skybox.value) + if (cv_skybox.value && skyboxmo[0]) Portal_AddSkyboxPortals(); // Portal rendering. Hijacks the BSP traversal. From ebe0586993722fad086abe6a251930206ac513eb Mon Sep 17 00:00:00 2001 From: Nev3r Date: Thu, 6 Jun 2019 11:26:13 +0200 Subject: [PATCH 10/17] Add pad checks for visplanes; invalidate invalid columns from visplanes (visplane renderer and column renderers don't speak exactly the same language). The visplane portal top boundary offset has been restored since all known bugs involving it have been fixed. --- src/r_portal.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/r_portal.c b/src/r_portal.c index 4825bb511..0c0a34b7d 100644 --- a/src/r_portal.c +++ b/src/r_portal.c @@ -200,7 +200,14 @@ static void Portal_ClipVisplane (const visplane_t* plane, portal_t* portal) for (i = 0; i < end - start; i++) { - portal->ceilingclip[i] = plane->top[i + start]; + // Invalid column. + if (plane->top[i + start] == 65535) + { + portal->ceilingclip[i] = -1; + portal->floorclip[i] = -1; + continue; + } + portal->ceilingclip[i] = plane->top[i + start] - 1; portal->floorclip[i] = plane->bottom[i + start] + 1; portal->frontscale[i] = INT32_MAX; } @@ -220,6 +227,11 @@ void Portal_AddSkybox (const visplane_t* plane) mapheader_t *mh; portal_t* portal; + // Visplanes have 1-px pads on their sides (extra columns). + // Trim them, else it may render out of bounds. + if (end > viewwidth) + end = viewwidth; + if (!(start < end)) return; From da09a07e6e59a825972e3b90b1118857abcaed24 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Thu, 6 Jun 2019 13:30:50 +0200 Subject: [PATCH 11/17] viewx/viewy also need to be stored/restored. --- src/r_bsp.c | 9 +-------- src/r_bsp.h | 1 + src/r_main.c | 9 +++++++++ src/r_segs.c | 4 +++- src/r_things.c | 8 ++++++++ src/r_things.h | 3 ++- 6 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/r_bsp.c b/src/r_bsp.c index 58d69ddf4..1e3c94a03 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -31,6 +31,7 @@ sector_t *backsector; // very ugly realloc() of drawsegs at run-time, I upped it to 512 // instead of 256.. and someone managed to send me a level with // 896 drawsegs! So too bad here's a limit removal a-la-Boom +drawseg_t *curdrawsegs = NULL; drawseg_t *drawsegs = NULL; drawseg_t *ds_p = NULL; @@ -1377,13 +1378,5 @@ void R_RenderBSPNode(INT32 bspnum) bspnum = bsp->children[side^1]; } - // PORTAL CULLING - if (portalcullsector) { - sector_t *sect = subsectors[bspnum & ~NF_SUBSECTOR].sector; - if (sect != portalcullsector) - return; - portalcullsector = NULL; - } - R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); } diff --git a/src/r_bsp.h b/src/r_bsp.h index 50fea6681..825be6064 100644 --- a/src/r_bsp.h +++ b/src/r_bsp.h @@ -29,6 +29,7 @@ extern boolean portalline; // is curline a portal seg? extern INT32 checkcoord[12][4]; +extern drawseg_t *curdrawsegs; extern drawseg_t *drawsegs; extern drawseg_t *ds_p; extern INT32 doorclosed; diff --git a/src/r_main.c b/src/r_main.c index b1a14fe0b..244b96cae 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1056,7 +1056,11 @@ void R_RenderPlayerView(player_t *player) masks[nummasks - 1].drawsegs[0] = 0; masks[nummasks - 1].vissprites[0] = 0; + masks[nummasks - 1].viewx = viewx; + masks[nummasks - 1].viewy = viewy; masks[nummasks - 1].viewz = viewz; + masks[nummasks - 1].viewsector = viewsector; + curdrawsegs = ds_p; R_RenderBSPNode((INT32)numnodes - 1); masks[nummasks - 1].drawsegs[1] = ds_p - drawsegs; masks[nummasks - 1].vissprites[1] = visspritecount; @@ -1103,7 +1107,12 @@ void R_RenderPlayerView(player_t *player) masks[nummasks - 1].drawsegs[0] = ds_p - drawsegs; masks[nummasks - 1].vissprites[0] = visspritecount; + masks[nummasks - 1].viewx = viewx; + masks[nummasks - 1].viewy = viewy; masks[nummasks - 1].viewz = viewz; + masks[nummasks - 1].viewsector = viewsector; + curdrawsegs = ds_p; + R_RenderBSPNode((INT32)numnodes - 1); masks[nummasks - 1].drawsegs[1] = ds_p - drawsegs; masks[nummasks - 1].vissprites[1] = visspritecount; diff --git a/src/r_segs.c b/src/r_segs.c index 36ed029ee..f5f314e6f 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -1738,6 +1738,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (ds_p == drawsegs+maxdrawsegs) { + size_t curpos = curdrawsegs - drawsegs; size_t pos = ds_p - drawsegs; size_t newmax = maxdrawsegs ? maxdrawsegs*2 : 128; if (firstseg) @@ -1745,6 +1746,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) drawsegs = Z_Realloc(drawsegs, newmax*sizeof (*drawsegs), PU_STATIC, NULL); ds_p = drawsegs + pos; maxdrawsegs = newmax; + curdrawsegs = drawsegs + curpos; if (firstseg) firstseg = drawsegs + (size_t)firstseg; } @@ -1794,7 +1796,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) // borrowed fix from *cough* zdoom *cough* // [RH] We also need to adjust the openings pointers that // were already stored in drawsegs. - for (ds = drawsegs; ds < ds_p; ds++) + for (ds = curdrawsegs; ds < ds_p; ds++) { #define ADJUST(p) if (ds->p + ds->x1 >= oldopenings && ds->p + ds->x1 <= oldlast) ds->p = ds->p - oldopenings + openings; ADJUST(maskedtexturecol); diff --git a/src/r_things.c b/src/r_things.c index e0cf34dba..27b4f15c1 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2454,7 +2454,12 @@ void R_DrawMasked(maskcount_t* masks, UINT8 nummasks) for (i = 0; i < nummasks; i++) { heads[i].next = heads[i].prev = &heads[i]; + + viewx = masks[i].viewx; + viewy = masks[i].viewy; viewz = masks[i].viewz; + viewsector = masks[i].viewsector; + R_CreateDrawNodes(&masks[i], &heads[i], false); } @@ -2463,7 +2468,10 @@ void R_DrawMasked(maskcount_t* masks, UINT8 nummasks) for (; nummasks > 0; nummasks--) { + viewx = masks[nummasks - 1].viewx; + viewy = masks[nummasks - 1].viewy; viewz = masks[nummasks - 1].viewz; + viewsector = masks[nummasks - 1].viewsector; R_DrawMaskedList(&heads[nummasks - 1]); R_ClearDrawNodes(&heads[nummasks - 1]); diff --git a/src/r_things.h b/src/r_things.h index 27c45def4..d287df832 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -65,7 +65,8 @@ typedef struct { size_t drawsegs[2]; size_t vissprites[2]; - fixed_t viewz; /**< View z stored at the time of the BSP traversal for the view/portal. Masked sorting/drawing needs it. */ + fixed_t viewx, viewy, viewz; /**< View z stored at the time of the BSP traversal for the view/portal. Masked sorting/drawing needs it. */ + sector_t* viewsector; } maskcount_t; void R_DrawMasked(maskcount_t* masks, UINT8 nummasks); From b8d2e017b48b7c82053cacd9cc8f9e4346a4a27d Mon Sep 17 00:00:00 2001 From: Nev3r Date: Fri, 7 Jun 2019 13:10:12 +0200 Subject: [PATCH 12/17] Refactored a bit of code regarding visplane bound trimming for portals; reset ffloor's f_clip/c_clip so that FOFs on portals don't interfere with previously acquired bounds. --- src/r_main.c | 11 ++++++++ src/r_plane.c | 31 +-------------------- src/r_plane.h | 3 ++ src/r_portal.c | 75 ++++++++++++++++++++++++++++++++++++++------------ src/r_portal.h | 1 + 5 files changed, 73 insertions(+), 48 deletions(-) diff --git a/src/r_main.c b/src/r_main.c index 244b96cae..70c271f5d 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1081,6 +1081,7 @@ void R_RenderPlayerView(player_t *player) // Portal rendering. Hijacks the BSP traversal. if (portal_base) { + INT32 i, p; portal_t *portal; for(portal = portal_base; portal; portal = portal_base) @@ -1113,6 +1114,16 @@ void R_RenderPlayerView(player_t *player) masks[nummasks - 1].viewsector = viewsector; curdrawsegs = ds_p; + // opening / clipping determination + for (i = 0; i < viewwidth; i++) + { + for (p = 0; p < MAXFFLOORS; p++) + { + ffloor[p].f_clip[i] = (INT16)viewheight; + ffloor[p].c_clip[i] = -1; + } + } + R_RenderBSPNode((INT32)numnodes - 1); masks[nummasks - 1].drawsegs[1] = ds_p - drawsegs; masks[nummasks - 1].vissprites[1] = visspritecount; diff --git a/src/r_plane.c b/src/r_plane.c index 18e5fda52..2c2fe3432 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -45,9 +45,8 @@ //#define QUINCUNX //SoM: 3/23/2000: Use Boom visplane hashing. -#define MAXVISPLANES 512 -static visplane_t *visplanes[MAXVISPLANES]; +visplane_t *visplanes[MAXVISPLANES]; static visplane_t *freetail; static visplane_t **freehead = &freetail; @@ -1178,31 +1177,3 @@ void R_PlaneBounds(visplane_t *plane) plane->high = hi; plane->low = low; } - -/** Creates portals for the currently existing sky visplanes. - * The visplanes are also removed and cleared from the list. - */ -void Portal_AddSkyboxPortals (void) -{ - visplane_t *pl; - INT32 i; - UINT16 count = 0; - - for (i = 0; i < MAXVISPLANES; i++, pl++) - { - for (pl = visplanes[i]; pl; pl = pl->next) - { - if (pl->picnum == skyflatnum) - { - Portal_AddSkybox(pl); - - pl->minx = 0; - pl->maxx = -1; - - count++; - } - } - } - - CONS_Debug(DBG_RENDER, "Skybox portals: %d\n", count); -} diff --git a/src/r_plane.h b/src/r_plane.h index c101e3218..a269fed6a 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -18,6 +18,8 @@ #include "r_data.h" #include "p_polyobj.h" +#define MAXVISPLANES 512 + // // Now what is a visplane, anyway? // Simple: kinda floor/ceiling polygon optimised for SRB2 rendering. @@ -53,6 +55,7 @@ typedef struct visplane_s #endif } visplane_t; +extern visplane_t *visplanes[MAXVISPLANES]; extern visplane_t *floorplane; extern visplane_t *ceilingplane; diff --git a/src/r_portal.c b/src/r_portal.c index 0c0a34b7d..ad5d32e70 100644 --- a/src/r_portal.c +++ b/src/r_portal.c @@ -18,6 +18,7 @@ #include "p_spec.h" // Skybox viewpoints #include "z_zone.h" #include "r_things.h" +#include "r_sky.h" UINT8 portalrender; /**< When rendering a portal, it establishes the depth of the current BSP traversal. */ sector_t *portalcullsector; @@ -215,25 +216,19 @@ static void Portal_ClipVisplane (const visplane_t* plane, portal_t* portal) extern INT32 viewwidth; -/** Creates a skybox portal out of a visplane. - * - * Applies the necessary offsets and rotation to give - * a depth illusion to the skybox. - */ -void Portal_AddSkybox (const visplane_t* plane) +static boolean TrimVisplaneBounds (const visplane_t* plane, INT16* start, INT16* end) { - INT16 start = plane->minx; - INT16 end = plane->maxx + 1; - mapheader_t *mh; - portal_t* portal; + *start = plane->minx; + *end = plane->maxx + 1; // Visplanes have 1-px pads on their sides (extra columns). // Trim them, else it may render out of bounds. - if (end > viewwidth) - end = viewwidth; + if (*end > viewwidth) + *end = viewwidth; + + if (!(*start < *end)) + return true; - if (!(start < end)) - return; /** Trims a visplane's horizontal gap to match its render area. * @@ -242,17 +237,33 @@ void Portal_AddSkybox (const visplane_t* plane) * valid area. */ - while (plane->bottom[start] == 0 && plane->top[start] == 65535 && start < end) + while (plane->bottom[*start] == 0 && plane->top[*start] == 65535 && *start < *end) { - start++; + (*start)++; } - while (plane->bottom[end - 1] == 0 && plane->top[start] == 65535 && end > start) + while (plane->bottom[*end - 1] == 0 && plane->top[*start] == 65535 && *end > *start) { - end--; + (*end)--; } + return false; +} + +/** Creates a skybox portal out of a visplane. + * + * Applies the necessary offsets and rotation to give + * a depth illusion to the skybox. + */ +void Portal_AddSkybox (const visplane_t* plane) +{ + INT16 start, end; + mapheader_t *mh; + portal_t* portal; + + if (TrimVisplaneBounds(plane, &start, &end)) + return; portal = Portal_Add(start, end); @@ -291,3 +302,31 @@ void Portal_AddSkybox (const visplane_t* plane) portal->clipline = -1; } + +/** Creates portals for the currently existing sky visplanes. + * The visplanes are also removed and cleared from the list. + */ +void Portal_AddSkyboxPortals (void) +{ + visplane_t *pl; + INT32 i; + UINT16 count = 0; + + for (i = 0; i < MAXVISPLANES; i++, pl++) + { + for (pl = visplanes[i]; pl; pl = pl->next) + { + if (pl->picnum == skyflatnum) + { + Portal_AddSkybox(pl); + + pl->minx = 0; + pl->maxx = -1; + + count++; + } + } + } + + CONS_Debug(DBG_RENDER, "Skybox portals: %d\n", count); +} diff --git a/src/r_portal.h b/src/r_portal.h index f7d2fb2fe..e5ff0fb9f 100644 --- a/src/r_portal.h +++ b/src/r_portal.h @@ -56,4 +56,5 @@ void Portal_AddSkybox (const visplane_t* plane); void Portal_ClipRange (portal_t* portal); void Portal_ClipApply (const portal_t* portal); +void Portal_AddSkyboxPortals (void); #endif From d62268ffd0a6179768f7b1b1e47ce649a55b4838 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Sun, 9 Jun 2019 20:04:07 +0200 Subject: [PATCH 13/17] Fixed crash regarding opening reallocating. A thousand thanks go for MonsterIestyn for figuring this out. I carelessly changed the line's drawsegs to curdrawsegs without researching what that piece of code did. --- src/r_segs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_segs.c b/src/r_segs.c index f5f314e6f..6eb81ce7a 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -1796,7 +1796,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) // borrowed fix from *cough* zdoom *cough* // [RH] We also need to adjust the openings pointers that // were already stored in drawsegs. - for (ds = curdrawsegs; ds < ds_p; ds++) + for (ds = drawsegs; ds < ds_p; ds++) { #define ADJUST(p) if (ds->p + ds->x1 >= oldopenings && ds->p + ds->x1 <= oldlast) ds->p = ds->p - oldopenings + openings; ADJUST(maskedtexturecol); From b7e2b5612cecd917927d55734ce9c65b52327178 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Sun, 9 Jun 2019 22:48:54 +0200 Subject: [PATCH 14/17] Made Portal_Add static; move ffloors clip reset from R_RenderPlayerView to r_plane. --- src/r_main.c | 10 +--------- src/r_plane.c | 19 +++++++++++++++++-- src/r_plane.h | 1 + src/r_portal.c | 2 +- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/r_main.c b/src/r_main.c index 70c271f5d..b2eb1890c 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1114,15 +1114,7 @@ void R_RenderPlayerView(player_t *player) masks[nummasks - 1].viewsector = viewsector; curdrawsegs = ds_p; - // opening / clipping determination - for (i = 0; i < viewwidth; i++) - { - for (p = 0; p < MAXFFLOORS; p++) - { - ffloor[p].f_clip[i] = (INT16)viewheight; - ffloor[p].c_clip[i] = -1; - } - } + R_ClearFFloorClips(); R_RenderBSPNode((INT32)numnodes - 1); masks[nummasks - 1].drawsegs[1] = ds_p - drawsegs; diff --git a/src/r_plane.c b/src/r_plane.c index 2c2fe3432..2f6f97240 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -305,6 +305,23 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) #endif } +void R_ClearFFloorClips (void) +{ + INT32 i, p; + + // opening / clipping determination + for (i = 0; i < viewwidth; i++) + { + for (p = 0; p < MAXFFLOORS; p++) + { + ffloor[p].f_clip[i] = (INT16)viewheight; + ffloor[p].c_clip[i] = -1; + } + } + + numffloors = 0; +} + // // R_ClearPlanes // At begining of frame. @@ -327,8 +344,6 @@ void R_ClearPlanes(void) } } - numffloors = 0; - for (i = 0; i < MAXVISPLANES; i++) for (*freehead = visplanes[i], visplanes[i] = NULL; freehead && *freehead ;) diff --git a/src/r_plane.h b/src/r_plane.h index a269fed6a..238fde182 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -76,6 +76,7 @@ extern lighttable_t **planezlight; void R_InitPlanes(void); void R_ClearPlanes(void); +void R_ClearFFloorClips (void); void R_MapPlane(INT32 y, INT32 x1, INT32 x2); void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2); diff --git a/src/r_portal.c b/src/r_portal.c index ad5d32e70..a1dcfe335 100644 --- a/src/r_portal.c +++ b/src/r_portal.c @@ -97,7 +97,7 @@ void Portal_ClipApply (const portal_t* portal) } } -portal_t* Portal_Add (const INT16 x1, const INT16 x2) +static portal_t* Portal_Add (const INT16 x1, const INT16 x2) { portal_t *portal = Z_Malloc(sizeof(portal_t), PU_LEVEL, NULL); INT16 *ceilingclipsave = Z_Malloc(sizeof(INT16)*(x2-x1 + 1), PU_LEVEL, NULL); From c5c474465233503913379f3903ac9b6b66bb9b5b Mon Sep 17 00:00:00 2001 From: Nev3r Date: Mon, 10 Jun 2019 17:12:18 +0200 Subject: [PATCH 15/17] Remove remnants of portalcullsector. --- src/r_bsp.c | 2 +- src/r_main.c | 59 +++++++++++++++++++++++++------------------------- src/r_portal.c | 1 - src/r_portal.h | 1 - 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/r_bsp.c b/src/r_bsp.c index 1e3c94a03..d521d9f4d 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -31,7 +31,7 @@ sector_t *backsector; // very ugly realloc() of drawsegs at run-time, I upped it to 512 // instead of 256.. and someone managed to send me a level with // 896 drawsegs! So too bad here's a limit removal a-la-Boom -drawseg_t *curdrawsegs = NULL; +drawseg_t *curdrawsegs = NULL; /**< This is used to handle multiple lists for masked drawsegs. */ drawseg_t *drawsegs = NULL; drawseg_t *ds_p = NULL; diff --git a/src/r_main.c b/src/r_main.c index b2eb1890c..273d13a56 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -997,15 +997,31 @@ static void R_PortalFrame(portal_t *portal) if (portal->clipline != -1) { portalclipline = &lines[portal->clipline]; - viewsector = portalcullsector = portalclipline->frontsector; + viewsector = portalclipline->frontsector; } else { portalclipline = NULL; - viewsector = portalcullsector = R_PointInSubsector(viewx, viewy)->sector; + viewsector = R_PointInSubsector(viewx, viewy)->sector; } } +static void Mask_Pre (maskcount_t* m) +{ + m->drawsegs[0] = ds_p - drawsegs; + m->vissprites[0] = visspritecount; + m->viewx = viewx; + m->viewy = viewy; + m->viewz = viewz; + m->viewsector = viewsector; +} + +static void Mask_Post (maskcount_t* m) +{ + m->drawsegs[1] = ds_p - drawsegs; + m->vissprites[1] = visspritecount; +} + // ================ // R_RenderView // ================ @@ -1048,24 +1064,14 @@ void R_RenderPlayerView(player_t *player) // The head node is the last node output. + Mask_Pre(&masks[nummasks - 1]); + curdrawsegs = ds_p; //profile stuff --------------------------------------------------------- #ifdef TIMING mytotal = 0; ProfZeroTimer(); #endif - - masks[nummasks - 1].drawsegs[0] = 0; - masks[nummasks - 1].vissprites[0] = 0; - masks[nummasks - 1].viewx = viewx; - masks[nummasks - 1].viewy = viewy; - masks[nummasks - 1].viewz = viewz; - masks[nummasks - 1].viewsector = viewsector; - curdrawsegs = ds_p; R_RenderBSPNode((INT32)numnodes - 1); - masks[nummasks - 1].drawsegs[1] = ds_p - drawsegs; - masks[nummasks - 1].vissprites[1] = visspritecount; - - R_ClipSprites(drawsegs, NULL); #ifdef TIMING RDMSR(0x10, &mycount); mytotal += mycount; // 64bit add @@ -1073,6 +1079,10 @@ void R_RenderPlayerView(player_t *player) CONS_Debug(DBG_RENDER, "RenderBSPNode: 0x%d %d\n", *((INT32 *)&mytotal + 1), (INT32)mytotal); #endif //profile stuff --------------------------------------------------------- + Mask_Post(&masks[nummasks - 1]); + + R_ClipSprites(drawsegs, NULL); + // Add skybox portals caused by sky visplanes. if (cv_skybox.value && skyboxmo[0]) @@ -1081,13 +1091,14 @@ void R_RenderPlayerView(player_t *player) // Portal rendering. Hijacks the BSP traversal. if (portal_base) { - INT32 i, p; portal_t *portal; for(portal = portal_base; portal; portal = portal_base) { portalrender = portal->pass; // Recursiveness depth. + R_ClearFFloorClips(); + // Apply the viewpoint stored for the portal. R_PortalFrame(portal); @@ -1102,30 +1113,20 @@ void R_RenderPlayerView(player_t *player) validcount++; - // Render the BSP from the new viewpoint, and clip - // any sprites with the new clipsegs and window. masks = realloc(masks, (++nummasks)*sizeof(maskcount_t)); - masks[nummasks - 1].drawsegs[0] = ds_p - drawsegs; - masks[nummasks - 1].vissprites[0] = visspritecount; - masks[nummasks - 1].viewx = viewx; - masks[nummasks - 1].viewy = viewy; - masks[nummasks - 1].viewz = viewz; - masks[nummasks - 1].viewsector = viewsector; + Mask_Pre(&masks[nummasks - 1]); curdrawsegs = ds_p; - R_ClearFFloorClips(); - + // Render the BSP from the new viewpoint, and clip + // any sprites with the new clipsegs and window. R_RenderBSPNode((INT32)numnodes - 1); - masks[nummasks - 1].drawsegs[1] = ds_p - drawsegs; - masks[nummasks - 1].vissprites[1] = visspritecount; + Mask_Post(&masks[nummasks - 1]); R_ClipSprites(ds_p - (masks[nummasks - 1].drawsegs[1] - masks[nummasks - 1].drawsegs[0]), portal); Portal_Remove(portal); } - - portalcullsector = NULL; // Just in case... } R_DrawPlanes(); diff --git a/src/r_portal.c b/src/r_portal.c index a1dcfe335..8456a50b5 100644 --- a/src/r_portal.c +++ b/src/r_portal.c @@ -21,7 +21,6 @@ #include "r_sky.h" UINT8 portalrender; /**< When rendering a portal, it establishes the depth of the current BSP traversal. */ -sector_t *portalcullsector; // Linked list for portals. portal_t *portal_base, *portal_cap; diff --git a/src/r_portal.h b/src/r_portal.h index e5ff0fb9f..e8f9119e8 100644 --- a/src/r_portal.h +++ b/src/r_portal.h @@ -44,7 +44,6 @@ extern portal_t* portal_base; extern portal_t* portal_cap; extern UINT8 portalrender; -extern sector_t *portalcullsector; extern line_t *portalclipline; extern INT32 portalclipstart, portalclipend; From 52618bf895fea0e9bfd3665616e0efdfca05488e Mon Sep 17 00:00:00 2001 From: Nev3r Date: Mon, 10 Jun 2019 17:59:12 +0200 Subject: [PATCH 16/17] Fix 1 extra column rendering on portal-clipped vissprites. --- src/r_things.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/r_things.c b/src/r_things.c index 27b4f15c1..f5482683f 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1352,8 +1352,8 @@ static void R_ProjectSprite(mobj_t *thing) { if (vis->x1 < portalclipstart) vis->x1 = portalclipstart; - if (vis->x2 > portalclipend) - vis->x2 = portalclipend; + if (vis->x2 >= portalclipend) + vis->x2 = portalclipend-1; } vis->xscale = xscale; //SoM: 4/17/2000 @@ -1570,8 +1570,8 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) { if (vis->x1 < portalclipstart) vis->x1 = portalclipstart; - if (vis->x2 > portalclipend) - vis->x2 = portalclipend; + if (vis->x2 >= portalclipend) + vis->x2 = portalclipend-1; } vis->xscale = xscale; //SoM: 4/17/2000 From 0c3f273745d03a75ee25100cbd6245d94da25c98 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Tue, 11 Jun 2019 14:47:58 +0200 Subject: [PATCH 17/17] Properly take skybox viewpoint angle into account. --- src/r_portal.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/r_portal.c b/src/r_portal.c index 8456a50b5..ea24cd91c 100644 --- a/src/r_portal.c +++ b/src/r_portal.c @@ -279,6 +279,7 @@ void Portal_AddSkybox (const visplane_t* plane) if (skyboxmo[1]) { fixed_t x = 0, y = 0; + angle_t ang = skyboxmo[0]->angle>>ANGLETOFINESHIFT; if (mh->skybox_scalex > 0) x = (viewx - skyboxmo[1]->x) / mh->skybox_scalex; @@ -290,8 +291,9 @@ void Portal_AddSkybox (const visplane_t* plane) else if (mh->skybox_scaley < 0) y = (viewy - skyboxmo[1]->y) * -mh->skybox_scaley; - portal->viewx += x; - portal->viewy += y; + // Apply transform to account for the skybox viewport angle. + portal->viewx += FixedMul(x,FINECOSINE(ang)) - FixedMul(y, FINESINE(ang)); + portal->viewy += FixedMul(x, FINESINE(ang)) + FixedMul(y,FINECOSINE(ang)); } if (mh->skybox_scalez > 0)