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/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 22abaeb88..d521d9f4d 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 @@ -26,11 +27,11 @@ 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 // 896 drawsegs! So too bad here's a limit removal a-la-Boom +drawseg_t *curdrawsegs = NULL; /**< This is used to handle multiple lists for masked drawsegs. */ drawseg_t *drawsegs = NULL; drawseg_t *ds_p = NULL; @@ -459,7 +460,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; } @@ -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 e3662e2e6..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; @@ -38,7 +39,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..273d13a56 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" @@ -65,37 +66,9 @@ 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; -// 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 // @@ -764,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; @@ -794,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 @@ -883,7 +855,6 @@ void R_SkyboxFrame(player_t *player) thiscam = &camera; // cut-away view stuff - viewsky = true; viewmobj = skyboxmo[0]; #ifdef PARANOIA if (!viewmobj) @@ -1010,17 +981,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,96 +991,37 @@ 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 = portalclipline->frontsector; } else { - portal_cap->next = portal; - portal_cap = portal; + portalclipline = NULL; + 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 // ================ @@ -1131,8 +1034,8 @@ void R_AddPortal(INT32 line1, INT32 line2, INT32 x1, INT32 x2) void R_RenderPlayerView(player_t *player) { - portal_pair *portal; - const boolean skybox = (skyboxmo[0] && cv_skybox.value); + UINT8 nummasks = 1; + maskcount_t* masks = malloc(sizeof(maskcount_t)); if (cv_homremoval.value && player == &players[displayplayer]) // if this is display player 1 { @@ -1142,38 +1045,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; - - portalrender = 0; - portal_base = portal_cap = NULL; - - 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++; @@ -1185,19 +1057,21 @@ void R_RenderPlayerView(player_t *player) #ifdef FLOORSPLATS R_ClearVisibleFloorSplats(); #endif + Portal_InitList(); // check for new console commands. NetUpdate(); // The head node is the last node output. + Mask_Pre(&masks[nummasks - 1]); + curdrawsegs = ds_p; //profile stuff --------------------------------------------------------- #ifdef TIMING mytotal = 0; ProfZeroTimer(); #endif R_RenderBSPNode((INT32)numnodes - 1); - R_ClipSprites(); #ifdef TIMING RDMSR(0x10, &mycount); mytotal += mycount; // 64bit add @@ -1205,54 +1079,66 @@ 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]); - // PORTAL RENDERING - for(portal = portal_base; portal; portal = portal_base) + R_ClipSprites(drawsegs, NULL); + + + // Add skybox portals caused by sky visplanes. + if (cv_skybox.value && skyboxmo[0]) + Portal_AddSkyboxPortals(); + + // 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; + portal_t *portal; - R_PortalFrame(&lines[portal->line1], &lines[portal->line2], portal); + for(portal = portal_base; portal; portal = portal_base) + { + portalrender = portal->pass; // Recursiveness depth. - R_PortalClearClipSegs(portal->start, portal->end); + R_ClearFFloorClips(); - R_PortalRestoreClipValues(portal->start, portal->end, portal->ceilingclip, portal->floorclip, portal->frontscale); + // Apply the viewpoint stored for the portal. + R_PortalFrame(portal); - validcount++; + // Hack in the clipsegs to delimit the starting + // clipping for sprites and possibly other similar + // future items. + R_PortalClearClipSegs(portal->start, portal->end); - R_RenderBSPNode((INT32)numnodes - 1); - R_ClipSprites(); - //R_DrawPlanes(); - //R_DrawMasked(); + // Hack in the top/bottom clip values for the window + // that were previously stored. + Portal_ClipApply(portal); - // 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); + validcount++; + + masks = realloc(masks, (++nummasks)*sizeof(maskcount_t)); + + Mask_Pre(&masks[nummasks - 1]); + curdrawsegs = ds_p; + + // Render the BSP from the new viewpoint, and clip + // any sprites with the new clipsegs and window. + R_RenderBSPNode((INT32)numnodes - 1); + Mask_Post(&masks[nummasks - 1]); + + R_ClipSprites(ds_p - (masks[nummasks - 1].drawsegs[1] - masks[nummasks - 1].drawsegs[0]), portal); + + Portal_Remove(portal); + } } - // END PORTAL RENDERING R_DrawPlanes(); #ifdef FLOORSPLATS R_DrawVisibleFloorSplats(); #endif + // draw mid texture and sprite // And now 3D floors/sides! - R_DrawMasked(); + R_DrawMasked(masks, nummasks); - // 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; + free(masks); } // ========================================================================= 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 0ef4c2c05..2f6f97240 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" @@ -43,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; @@ -112,50 +113,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 // @@ -348,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. @@ -370,8 +344,6 @@ void R_ClearPlanes(void) } } - numffloors = 0; - for (i = 0; i < MAXVISPLANES; i++) for (*freehead = visplanes[i], visplanes[i] = NULL; freehead && *freehead ;) @@ -723,16 +695,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; diff --git a/src/r_plane.h b/src/r_plane.h index 6e6a6d49d..238fde182 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; @@ -72,9 +75,8 @@ 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_ClearFFloorClips (void); void R_MapPlane(INT32 y, INT32 x1, INT32 x2); void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2); @@ -122,4 +124,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 new file mode 100644 index 000000000..ea24cd91c --- /dev/null +++ b/src/r_portal.c @@ -0,0 +1,333 @@ +// 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" +#include "doomstat.h" +#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. */ + +// 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_ClipRange (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; + } +} + +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); + 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) + { + 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_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++) + { + // 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; + } +} + +extern INT32 viewwidth; + +static boolean TrimVisplaneBounds (const visplane_t* plane, INT16* start, INT16* end) +{ + *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 (!(*start < *end)) + return true; + + + /** 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)--; + } + + 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); + + 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; + angle_t ang = skyboxmo[0]->angle>>ANGLETOFINESHIFT; + + 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; + + // 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) + portal->viewz += viewz / mh->skybox_scalez; + else if (mh->skybox_scalez < 0) + portal->viewz += viewz * -mh->skybox_scalez; + + 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 new file mode 100644 index 000000000..e8f9119e8 --- /dev/null +++ b/src/r_portal.h @@ -0,0 +1,59 @@ +// 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. + +#ifndef __R_PORTAL__ +#define __R_PORTAL__ + +#include "r_data.h" +#include "r_plane.h" // visplanes + +/** Portal structure for the software renderer. + */ +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; + +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); +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 diff --git a/src/r_segs.c b/src/r_segs.c index 03c5fb6e5..6eb81ce7a 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" @@ -1737,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) @@ -1744,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; } diff --git a/src/r_state.h b/src/r_state.h index 9c8ce51d6..da9425bdf 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -80,14 +80,8 @@ 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; -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 e8d679b53..f5482683f 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" @@ -444,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}; @@ -1249,7 +1250,7 @@ static void R_ProjectSprite(mobj_t *thing) } // PORTAL SPRITE CLIPPING - if (portalrender) + if (portalrender && portalclipline) { if (x2 < portalclipstart || x1 > portalclipend) return; @@ -1351,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 @@ -1517,7 +1518,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) return; // PORTAL SPRITE CLIPPING - if (portalrender) + if (portalrender && portalclipline) { if (x2 < portalclipstart || x1 > portalclipend) return; @@ -1569,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 @@ -1696,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; @@ -1707,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; @@ -1798,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) @@ -1824,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; } } @@ -1837,28 +1833,28 @@ 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; 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; 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]; } @@ -1873,7 +1869,7 @@ static void R_CreateDrawNodes(void) ; else { // Put it in! - entry = R_CreateDrawNode(&nodehead); + entry = R_CreateDrawNode(head); entry->plane = plane; entry->seg = ds; } @@ -1882,7 +1878,7 @@ static void R_CreateDrawNodes(void) #endif if (ds->maskedtexturecol) { - entry = R_CreateDrawNode(&nodehead); + entry = R_CreateDrawNode(head); entry->seg = ds; } if (ds->numffloorplanes) @@ -1913,7 +1909,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; @@ -1924,6 +1920,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 @@ -1940,17 +1939,19 @@ 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; } #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) @@ -1958,7 +1959,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) { @@ -2097,9 +2098,9 @@ static void R_CreateDrawNodes(void) } } } - if (r2 == &nodehead) + if (r2 == head) { - entry = R_CreateDrawNode(&nodehead); + entry = R_CreateDrawNode(head); entry->sprite = rover; } } @@ -2141,25 +2142,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; } // @@ -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,20 +2370,29 @@ 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]; + } + } } } // // 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) { @@ -2432,7 +2444,38 @@ void R_DrawMasked(void) r2 = next; } } - R_ClearDrawNodes(); +} + +void R_DrawMasked(maskcount_t* masks, UINT8 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]; + + viewx = masks[i].viewx; + viewy = masks[i].viewy; + viewz = masks[i].viewz; + viewsector = masks[i].viewsector; + + 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 (; 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 1003103ca..d287df832 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') @@ -45,7 +46,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) @@ -55,8 +55,21 @@ 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_DrawMasked(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 + * drawnode lists. + */ +typedef struct +{ + size_t drawsegs[2]; + size_t vissprites[2]; + 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); // ----------- // SKINS STUFF @@ -207,6 +220,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