From 264386f84257a47fe5480bb6300df02d039a2491 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Sat, 1 Jun 2019 21:26:25 +0200 Subject: [PATCH] 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;