From 2df45598d8f816aa9e504fd31ba72256b503830b Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 16 Dec 2014 18:08:48 +0200 Subject: [PATCH 1/6] Merged mirrors with portals; Render part of mirrors done, render part of portals needs further testing --- src/actionspecials.h | 5 +- src/p_acs.cpp | 4 ++ src/p_buildmap.cpp | 6 ++ src/p_setup.cpp | 6 ++ src/p_udmf.cpp | 6 ++ src/r_bsp.cpp | 15 +++- src/r_bsp.h | 5 +- src/r_defs.h | 4 ++ src/r_main.cpp | 163 ++++++++++++++++++++++++++++++------------- src/r_plane.cpp | 10 +-- src/r_plane.h | 2 +- src/r_segs.cpp | 130 +++++++++++++++++++--------------- src/r_things.cpp | 110 ++++++++++++++++++++++++++--- src/r_things.h | 1 + zdoom.vcproj | 12 ++++ 15 files changed, 352 insertions(+), 127 deletions(-) diff --git a/src/actionspecials.h b/src/actionspecials.h index 752ef77eb..879f16a11 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -140,7 +140,7 @@ DEFINE_SPECIAL(Teleport_NoStop, 154, 2, 3, 3) // Although ZDoom doesn't support them it's better to have them defined so that // WADs using them somewhere can at least be started without aborting due // to an error message. -DEFINE_SPECIAL(SetGlobalFogParameter, 157, 2, 2, 2) +DEFINE_SPECIAL(SetGlobalFogParameter, 157, 2, 2, 2) // vavoom? interferes with Line_SetVisualPortal DEFINE_SPECIAL(FS_Execute, 158, 1, 4, 4) DEFINE_SPECIAL(Sector_SetPlaneReflection, 159, 3, 3, 3) DEFINE_SPECIAL(Sector_Set3DFloor, 160, -1, -1, 5) @@ -236,4 +236,7 @@ DEFINE_SPECIAL(Ceiling_LowerToLowest, 253, 2, 2, 2) DEFINE_SPECIAL(Ceiling_LowerToFloor, 254, 2, 2, 2) DEFINE_SPECIAL(Ceiling_CrushRaiseAndStaySilA, 255, 4, 5, 5) +DEFINE_SPECIAL(Line_SetVisualPortal, 155, -1, -1, 3) +DEFINE_SPECIAL(Line_SetPortal, 156, -1, -1, 3) + #undef DEFINE_SPECIAL diff --git a/src/p_acs.cpp b/src/p_acs.cpp index bc4cbdb75..e0eb524f1 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -75,6 +75,7 @@ #include "actorptrselect.h" #include "farchive.h" #include "decallib.h" +#include "portal.h" #include "g_shared/a_pickups.h" @@ -7902,6 +7903,9 @@ scriptwait: line->args[4] = STACK(1); DPrintf("Set special on line %d (id %d) to %d(%d,%d,%d,%d,%d)\n", linenum, STACK(7), specnum, arg0, STACK(4), STACK(3), STACK(2), STACK(1)); + + // [ZZ] re-link with portals (in case this was something related to portal specials) + P_CheckPortal(line); } sp -= 7; } diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp index 2ee2ae83a..d9f2857ba 100644 --- a/src/p_buildmap.cpp +++ b/src/p_buildmap.cpp @@ -17,6 +17,7 @@ #include "g_level.h" #include "r_data/colormaps.h" #include "gi.h" +#include "portal.h" // MACROS ------------------------------------------------------------------ @@ -628,6 +629,11 @@ static void LoadWalls (walltype *walls, int numwalls, sectortype *bsec) } } + // [ZZ] set initial line portal link + // (even though this is rather hard to happen... build doesn't have portals in our sense and it's walls don't get translated into anything like this) + for (int i = 0; i < numlines; i++) + P_CheckPortal(&lines[i]); + // Finish setting sector properties that depend on walls for (i = 0; i < numsectors; ++i, ++bsec) { diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 6b5d9403f..8076e19a9 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -68,6 +68,7 @@ #include "po_man.h" #include "r_renderer.h" #include "r_data/colormaps.h" +#include "portal.h" #include "fragglescript/t_fs.h" @@ -2161,6 +2162,11 @@ void P_LoadLineDefs (MapData * map) if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX; if (level.flags2 & LEVEL2_CHECKSWITCHRANGE) ld->flags |= ML_CHECKSWITCHRANGE; } + + // [ZZ] check initial portal link + for (int i = 0; i < numlines; i++) + P_CheckPortal(&lines[i]); + delete[] mldf; } diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 473cdcd81..cb9ed19f1 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -46,6 +46,7 @@ #include "r_state.h" #include "r_data/colormaps.h" #include "w_wad.h" +#include "portal.h" //=========================================================================== // @@ -1704,6 +1705,11 @@ public: P_AdjustLine(&lines[line]); P_FinishLoadingLineDef(&lines[line], tempalpha[0]); } + + // [ZZ] check initial portal link + for (int i = 0; i < numlines; i++) + P_CheckPortal(&lines[i]); + assert(side <= numsides); if (side < numsides) { diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index c56255888..e35c95f45 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -56,6 +56,7 @@ #include "r_sky.h" #include "po_man.h" #include "r_data/colormaps.h" +#include "portal.h" seg_t* curline; side_t* sidedef; @@ -98,8 +99,8 @@ static BYTE FakeSide; int WindowLeft, WindowRight; WORD MirrorFlags; -seg_t *ActiveWallMirror; -TArray WallMirrors; +TArray WallPortals; + static subsector_t *InSubsector; @@ -553,6 +554,10 @@ void R_AddLine (seg_t *line) return; } + // reject lines that aren't seen from the portal (if any) + if (CurrentPortal && P_ClipLineToPortal(line->linedef, CurrentPortal->dst, viewx, viewy)) + return; + vertex_t *v1, *v2; v1 = line->linedef->v1; @@ -583,6 +588,8 @@ void R_AddLine (seg_t *line) rw_mustmarkfloor = rw_mustmarkceiling = false; rw_havehigh = rw_havelow = false; + bool is_portal = (line->linedef && line->linedef->special == Line_Mirror); + // Single sided line? if (backsector == NULL) { @@ -649,7 +656,9 @@ void R_AddLine (seg_t *line) // Window. solid = false; } - else if (backsector->lightlevel != frontsector->lightlevel + else if (is_portal + + || backsector->lightlevel != frontsector->lightlevel || backsector->GetTexture(sector_t::floor) != frontsector->GetTexture(sector_t::floor) || backsector->GetTexture(sector_t::ceiling) != frontsector->GetTexture(sector_t::ceiling) || curline->sidedef->GetTexture(side_t::mid).isValid() diff --git a/src/r_bsp.h b/src/r_bsp.h index 1b5af9805..59a275398 100644 --- a/src/r_bsp.h +++ b/src/r_bsp.h @@ -25,6 +25,7 @@ #include "tarray.h" #include +#include "portal.h" // The 3072 below is just an arbitrary value picked to avoid // drawing lines the player is too close to that would overflow @@ -88,6 +89,7 @@ struct drawseg_t // backups ptrdiff_t bkup; // sprtopclip backup, for mid and fake textures FWallTmapVals tmapvals; + int CurrentPortalUniq; // [ZZ] to identify the portal that this drawseg is in. used for sprite clipping. }; @@ -106,9 +108,8 @@ extern size_t FirstInterestingDrawseg; extern int WindowLeft, WindowRight; extern WORD MirrorFlags; -extern seg_t* ActiveWallMirror; -extern TArray WallMirrors; +extern TArray WallPortals; typedef void (*drawfunc_t) (int start, int stop); diff --git a/src/r_defs.h b/src/r_defs.h index dd2136508..8f94db3f2 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -899,6 +899,10 @@ struct line_t sector_t *frontsector, *backsector; int validcount; // if == validcount, already checked int locknumber; // [Dusk] lock number for special + bool portal; + bool portal_mirror; + bool portal_passive; + line_t *portal_dst; }; // phares 3/14/98 diff --git a/src/r_main.cpp b/src/r_main.cpp index bc3c4c7c0..c6af51533 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -57,6 +57,7 @@ #include "v_font.h" #include "r_data/colormaps.h" #include "farchive.h" +#include "portal.h" // MACROS ------------------------------------------------------------------ @@ -610,52 +611,91 @@ void R_SetupFreelook() //========================================================================== // -// R_EnterMirror +// R_EnterPortal // // [RH] Draw the reflection inside a mirror +// [ZZ] Merged with portal code, originally called R_EnterMirror // //========================================================================== -void R_EnterMirror (drawseg_t *ds, int depth) +void R_EnterPortal (PortalDrawseg* pds, int depth) { + // [ZZ] check depth. fill portal with black if it's exceeding the visual recursion limit, and continue like nothing happened. + if (depth > 4) + { + BYTE color = (BYTE)BestColor((DWORD *)GPalette.BaseColors, 0, 0, 0, 0, 255); + int spacing = RenderTarget->GetPitch(); + for (int x = pds->x1; x <= pds->x2; x++) + { + int Ytop = pds->ceilingclip[x-pds->x1]; + int Ybottom = pds->floorclip[x-pds->x1]; + + BYTE *dest = RenderTarget->GetBuffer() + x + Ytop * spacing; + + if (Ytop < 0) Ytop = 0; + if (Ybottom >= RenderTarget->GetHeight()) + Ybottom = RenderTarget->GetHeight()-1; + + for (int y = Ytop; y <= Ybottom; y++) + { + *dest = color; + dest += spacing; + } + } + + return; + } + angle_t startang = viewangle; fixed_t startx = viewx; fixed_t starty = viewy; - CurrentMirror++; + int prevuniq = CurrentPortalUniq; + CurrentPortalUniq++; - unsigned int mirrorsAtStart = WallMirrors.Size (); + unsigned int portalsAtStart = WallPortals.Size (); - vertex_t *v1 = ds->curline->v1; + if (pds->mirror) + { + //vertex_t *v1 = ds->curline->v1; + vertex_t *v1 = pds->src->v1; + + // Reflect the current view behind the mirror. + if (pds->src->dx == 0) + { // vertical mirror + viewx = v1->x - startx + v1->x; + } + else if (pds->src->dy == 0) + { // horizontal mirror + viewy = v1->y - starty + v1->y; + } + else + { // any mirror--use floats to avoid integer overflow + vertex_t *v2 = pds->src->v2; + + float dx = FIXED2FLOAT(v2->x - v1->x); + float dy = FIXED2FLOAT(v2->y - v1->y); + float x1 = FIXED2FLOAT(v1->x); + float y1 = FIXED2FLOAT(v1->y); + float x = FIXED2FLOAT(startx); + float y = FIXED2FLOAT(starty); + + // the above two cases catch len == 0 + float r = ((x - x1)*dx + (y - y1)*dy) / (dx*dx + dy*dy); + + viewx = FLOAT2FIXED((x1 + r * dx)*2 - x); + viewy = FLOAT2FIXED((y1 + r * dy)*2 - y); + } + viewangle = 2*R_PointToAngle2 (pds->src->v1->x, pds->src->v1->y, + pds->src->v2->x, pds->src->v2->y) - startang; - // Reflect the current view behind the mirror. - if (ds->curline->linedef->dx == 0) - { // vertical mirror - viewx = v1->x - startx + v1->x; - } - else if (ds->curline->linedef->dy == 0) - { // horizontal mirror - viewy = v1->y - starty + v1->y; } else - { // any mirror--use floats to avoid integer overflow - vertex_t *v2 = ds->curline->v2; - - float dx = FIXED2FLOAT(v2->x - v1->x); - float dy = FIXED2FLOAT(v2->y - v1->y); - float x1 = FIXED2FLOAT(v1->x); - float y1 = FIXED2FLOAT(v1->y); - float x = FIXED2FLOAT(startx); - float y = FIXED2FLOAT(starty); - - // the above two cases catch len == 0 - float r = ((x - x1)*dx + (y - y1)*dy) / (dx*dx + dy*dy); - - viewx = FLOAT2FIXED((x1 + r * dx)*2 - x); - viewy = FLOAT2FIXED((y1 + r * dy)*2 - y); + { + P_TranslatePortalXY(pds->src, pds->dst, viewx, viewy); + P_TranslatePortalZ(pds->src, pds->dst, viewz); + P_TranslatePortalAngle(pds->src, pds->dst, viewangle); } - viewangle = 2*R_PointToAngle2 (ds->curline->v1->x, ds->curline->v1->y, - ds->curline->v2->x, ds->curline->v2->y) - startang; viewsin = finesine[viewangle>>ANGLETOFINESHIFT]; viewcos = finecosine[viewangle>>ANGLETOFINESHIFT]; @@ -666,35 +706,57 @@ void R_EnterMirror (drawseg_t *ds, int depth) R_CopyStackedViewParameters(); validcount++; - ActiveWallMirror = ds->curline; + PortalDrawseg* prevpds = CurrentPortal; + CurrentPortal = pds; R_ClearPlanes (false); - R_ClearClipSegs (ds->x1, ds->x2 + 1); + R_ClearClipSegs (pds->x1, pds->x2 + 1); // todo: check if this "+1" is actually needed - memcpy (ceilingclip + ds->x1, openings + ds->sprtopclip, (ds->x2 - ds->x1 + 1)*sizeof(*ceilingclip)); - memcpy (floorclip + ds->x1, openings + ds->sprbottomclip, (ds->x2 - ds->x1 + 1)*sizeof(*floorclip)); + // some portals have height differences, account for this here + R_3D_EnterSkybox(); // push 3D floor height map - WindowLeft = ds->x1; - WindowRight = ds->x2; - MirrorFlags = (depth + 1) & 1; + memcpy (ceilingclip + pds->x1, &pds->ceilingclip[0], pds->ceilingclip.Size()*sizeof(*ceilingclip)); + memcpy (floorclip + pds->x1, &pds->floorclip[0], pds->floorclip.Size()*sizeof(*floorclip)); + + WindowLeft = pds->x1; + WindowRight = pds->x2; + + // RF_XFLIP should be removed before calling the root function + int prevmf = MirrorFlags; + if (pds->mirror) + { + if (MirrorFlags & RF_XFLIP) + MirrorFlags &= ~RF_XFLIP; + else MirrorFlags |= RF_XFLIP; + } R_RenderBSPNode (nodes + numnodes - 1); R_3D_ResetClip(); // reset clips (floor/ceiling) + PlaneCycles.Clock(); R_DrawPlanes (); R_DrawSkyBoxes (); + PlaneCycles.Unclock(); - // Allow up to 4 recursions through a mirror - if (depth < 4) + // depth check is in another place right now + unsigned int portalsAtEnd = WallPortals.Size (); + for (; portalsAtStart < portalsAtEnd; portalsAtStart++) { - unsigned int mirrorsAtEnd = WallMirrors.Size (); - - for (; mirrorsAtStart < mirrorsAtEnd; mirrorsAtStart++) - { - R_EnterMirror (drawsegs + WallMirrors[mirrorsAtStart], depth + 1); - } + R_EnterPortal (&WallPortals[portalsAtStart], depth + 1); } + NetUpdate(); + + MaskedCycles.Clock(); // [ZZ] count sprites in portals/mirrors along with normal ones. + R_DrawMasked (); // this is required since with portals there often will be cases when more than 80% of the view is inside a portal. + MaskedCycles.Unclock(); + + NetUpdate(); + + R_3D_LeaveSkybox(); // pop 3D floor height map + CurrentPortal = prevpds; + MirrorFlags = prevmf; + CurrentPortalUniq = prevuniq; viewangle = startang; viewx = startx; viewy = starty; @@ -781,7 +843,7 @@ void R_RenderActorView (AActor *actor, bool dontmaplines) WindowLeft = 0; WindowRight = viewwidth - 1; MirrorFlags = 0; - ActiveWallMirror = NULL; + CurrentPortal = NULL; r_dontmaplines = dontmaplines; @@ -815,10 +877,11 @@ void R_RenderActorView (AActor *actor, bool dontmaplines) PlaneCycles.Unclock(); // [RH] Walk through mirrors - size_t lastmirror = WallMirrors.Size (); - for (unsigned int i = 0; i < lastmirror; i++) + // [ZZ] Merged with portals + size_t lastportal = WallPortals.Size(); + for (unsigned int i = 0; i < lastportal; i++) { - R_EnterMirror (drawsegs + WallMirrors[i], 0); + R_EnterPortal(&WallPortals[i], 0); } NetUpdate (); @@ -829,7 +892,7 @@ void R_RenderActorView (AActor *actor, bool dontmaplines) NetUpdate (); } - WallMirrors.Clear (); + WallPortals.Clear (); interpolator.RestoreInterpolations (); R_SetupBuffer (); diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 6572c1f0b..dc13e95a3 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -58,6 +58,7 @@ #include "r_3dfloors.h" #include "v_palette.h" #include "r_data/colormaps.h" +#include "portal.h" #ifdef _MSC_VER #pragma warning(disable:4244) @@ -687,7 +688,7 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl yscale == check->yscale && angle == check->angle && sky == check->sky && - CurrentMirror == check->CurrentMirror && + CurrentPortalUniq == check->CurrentPortalUniq && MirrorFlags == check->MirrorFlags && CurrentSkybox == check->CurrentSkybox ) @@ -719,7 +720,7 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl check->viewangle = stacked_angle; check->Alpha = alpha; check->Additive = additive; - check->CurrentMirror = CurrentMirror; + check->CurrentPortalUniq = CurrentPortalUniq; check->MirrorFlags = MirrorFlags; check->CurrentSkybox = CurrentSkybox; @@ -808,7 +809,7 @@ visplane_t *R_CheckPlane (visplane_t *pl, int start, int stop) new_pl->sky = pl->sky; new_pl->Alpha = pl->Alpha; new_pl->Additive = pl->Additive; - new_pl->CurrentMirror = pl->CurrentMirror; + new_pl->CurrentPortalUniq = pl->CurrentPortalUniq; new_pl->MirrorFlags = pl->MirrorFlags; new_pl->CurrentSkybox = pl->CurrentSkybox; pl = new_pl; @@ -1044,7 +1045,7 @@ int R_DrawPlanes () for (pl = visplanes[i]; pl; pl = pl->next) { // kg3D - draw only correct planes - if(pl->CurrentMirror != CurrentMirror || pl->CurrentSkybox != CurrentSkybox) + if(pl->CurrentPortalUniq != CurrentPortalUniq || pl->CurrentSkybox != CurrentSkybox) continue; // kg3D - draw only real planes now if(pl->sky >= 0) { @@ -1270,6 +1271,7 @@ void R_DrawSkyBoxes () // Create a drawseg to clip sprites to the sky plane R_CheckDrawSegs (); + ds_p->CurrentPortalUniq = CurrentPortalUniq; ds_p->siz1 = INT_MAX; ds_p->siz2 = INT_MAX; ds_p->sz1 = 0; diff --git a/src/r_plane.h b/src/r_plane.h index 231fa3ad4..5fd9b8eeb 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -58,7 +58,7 @@ struct visplane_s // kg3D - keep track of mirror and skybox owner int CurrentSkybox; - int CurrentMirror; // mirror counter, counts all of them + int CurrentPortalUniq; // mirror counter, counts all of them int MirrorFlags; // this is not related to CurrentMirror unsigned short *bottom; // [RH] bottom and top arrays are dynamically diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 15f736c93..9e20a3535 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -52,6 +52,7 @@ #include "r_3dfloors.h" #include "v_palette.h" #include "r_data/colormaps.h" +#include "portal.h" #define WALLYREPEAT 8 @@ -103,7 +104,7 @@ extern fixed_t rw_frontfz1, rw_frontfz2; int rw_ceilstat, rw_floorstat; bool rw_mustmarkfloor, rw_mustmarkceiling; bool rw_prepped; -bool rw_markmirror; +bool rw_markportal; bool rw_havehigh; bool rw_havelow; @@ -1948,7 +1949,7 @@ void R_NewWall (bool needlights) { fixed_t rowoffset, yrepeat; - rw_markmirror = false; + rw_markportal = false; sidedef = curline->sidedef; linedef = curline->linedef; @@ -1958,65 +1959,64 @@ void R_NewWall (bool needlights) midtexture = toptexture = bottomtexture = 0; - if (backsector == NULL) + if (sidedef == linedef->sidedef[0] && + linedef->portal && + (!linedef->portal_mirror || r_drawmirrors)) // [ZZ] compatibility with r_drawmirrors cvar that existed way before portals + { + markfloor = markceiling = true; // act like an one-sided wall here (todo: check how does this work with transparency) + rw_markportal = true; + } + else if (backsector == NULL) { // single sided line // a single sided line is terminal, so it must mark ends markfloor = markceiling = true; - // [RH] Render mirrors later, but mark them now. - if (linedef->special != Line_Mirror || !r_drawmirrors) + // [RH] Horizon lines do not need to be textured + if (linedef->special != Line_Horizon) { - // [RH] Horizon lines do not need to be textured - if (linedef->special != Line_Horizon) - { - midtexture = TexMan(sidedef->GetTexture(side_t::mid), true); - rw_offset_mid = sidedef->GetTextureXOffset(side_t::mid); - rowoffset = sidedef->GetTextureYOffset(side_t::mid); - rw_midtexturescalex = sidedef->GetTextureXScale(side_t::mid); - rw_midtexturescaley = sidedef->GetTextureYScale(side_t::mid); - yrepeat = FixedMul(midtexture->yScale, rw_midtexturescaley); - if (yrepeat >= 0) - { // normal orientation - if (linedef->flags & ML_DONTPEGBOTTOM) - { // bottom of texture at bottom - rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::floor) - viewz, yrepeat) + (midtexture->GetHeight() << FRACBITS); - } - else - { // top of texture at top - rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat); - if (rowoffset < 0 && midtexture != NULL) - { - rowoffset += midtexture->GetHeight() << FRACBITS; - } - } + midtexture = TexMan(sidedef->GetTexture(side_t::mid), true); + rw_offset_mid = sidedef->GetTextureXOffset(side_t::mid); + rowoffset = sidedef->GetTextureYOffset(side_t::mid); + rw_midtexturescalex = sidedef->GetTextureXScale(side_t::mid); + rw_midtexturescaley = sidedef->GetTextureYScale(side_t::mid); + yrepeat = FixedMul(midtexture->yScale, rw_midtexturescaley); + if (yrepeat >= 0) + { // normal orientation + if (linedef->flags & ML_DONTPEGBOTTOM) + { // bottom of texture at bottom + rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::floor) - viewz, yrepeat) + (midtexture->GetHeight() << FRACBITS); } else - { // upside down - rowoffset = -rowoffset; - if (linedef->flags & ML_DONTPEGBOTTOM) - { // top of texture at bottom - rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::floor) - viewz, yrepeat); + { // top of texture at top + rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat); + if (rowoffset < 0 && midtexture != NULL) + { + rowoffset += midtexture->GetHeight() << FRACBITS; } - else - { // bottom of texture at top - rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat) + (midtexture->GetHeight() << FRACBITS); - } - } - if (midtexture->bWorldPanning) - { - rw_midtexturemid += MulScale16(rowoffset, yrepeat); - } - else - { - // rowoffset is added outside the multiply so that it positions the texture - // by texels instead of world units. - rw_midtexturemid += rowoffset; } } - } - else - { - rw_markmirror = true; + else + { // upside down + rowoffset = -rowoffset; + if (linedef->flags & ML_DONTPEGBOTTOM) + { // top of texture at bottom + rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::floor) - viewz, yrepeat); + } + else + { // bottom of texture at top + rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat) + (midtexture->GetHeight() << FRACBITS); + } + } + if (midtexture->bWorldPanning) + { + rw_midtexturemid += MulScale16(rowoffset, yrepeat); + } + else + { + // rowoffset is added outside the multiply so that it positions the texture + // by texels instead of world units. + rw_midtexturemid += rowoffset; + } } } else @@ -2339,6 +2339,7 @@ void R_StoreWallRange (int start, int stop) rw_offset = sidedef->GetTextureXOffset(side_t::mid); rw_light = rw_lightleft + rw_lightstep * (start - WallC.sx1); + ds_p->CurrentPortalUniq = CurrentPortalUniq; ds_p->sx1 = WallC.sx1; ds_p->sx2 = WallC.sx2; ds_p->sz1 = WallC.sz1; @@ -2362,10 +2363,8 @@ void R_StoreWallRange (int start, int stop) // killough 1/6/98, 2/1/98: remove limit on openings ds_p->sprtopclip = ds_p->sprbottomclip = ds_p->maskedtexturecol = ds_p->bkup = ds_p->swall = -1; - if (rw_markmirror) + if (rw_markportal) { - size_t drawsegnum = ds_p - drawsegs; - WallMirrors.Push (drawsegnum); ds_p->silhouette = SIL_BOTH; } else if (backsector == NULL) @@ -2576,9 +2575,28 @@ void R_StoreWallRange (int start, int stop) } // [RH] Draw any decals bound to the seg - for (DBaseDecal *decal = curline->sidedef->AttachedDecals; decal != NULL; decal = decal->WallNext) + // [ZZ] Only if not an active mirror + if (!rw_markportal) { - R_RenderDecal (curline->sidedef, decal, ds_p, 0); + for (DBaseDecal *decal = curline->sidedef->AttachedDecals; decal != NULL; decal = decal->WallNext) + { + R_RenderDecal (curline->sidedef, decal, ds_p, 0); + } + } + + if (rw_markportal) + { + PortalDrawseg pds; + pds.src = curline->linedef; + pds.dst = curline->linedef->portal_dst; + pds.x1 = ds_p->x1; + pds.x2 = ds_p->x2; + pds.ceilingclip.Resize((pds.x2-pds.x1)+1); + memcpy(&pds.ceilingclip[0], openings + ds_p->sprtopclip, pds.ceilingclip.Size()*sizeof(*openings)); + pds.floorclip.Resize((pds.x2-pds.x1)+1); + memcpy(&pds.floorclip[0], openings + ds_p->sprbottomclip, pds.floorclip.Size()*sizeof(*openings)); + pds.mirror = curline->linedef->portal_mirror; + WallPortals.Push(pds); } ds_p++; diff --git a/src/r_things.cpp b/src/r_things.cpp index c0475ee75..96afaa216 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -316,6 +316,44 @@ nextpost: } } +// [ZZ] +// R_ClipSpriteColumnWithPortals +// +bool R_ClipSpriteColumnWithPortals (fixed_t x, fixed_t y, vissprite_t* spr) +{ + size_t numdrawsegs = ds_p-firstdrawseg; + for (int i = (int)numdrawsegs-1; i >= 0; i--) + { + drawseg_t* seg = &firstdrawseg[i]; + + // ignore segs from other portals + if (seg->CurrentPortalUniq != CurrentPortalUniq) + continue; + + line_t* line = seg->curline->linedef; + // divline? wtf, anyway, divlines aren't supposed to be drawn. But I definitely saw NULL linedefs in drawsegs. + if (!line) continue; + + // check if this line will clip sprites to itself + if (!line->portal) + continue; + + // don't clip sprites with portal's back side (it's transparent) + if (seg->curline->sidedef != line->sidedef[0]) + continue; + + // don't clip if the sprite is in front of the portal + if (!P_PointOnLineSide(x, y, line)) + continue; + + // now if current column is covered by this drawseg, we clip it away + if ((dc_x >= seg->x1) && (dc_x <= seg->x2)) + return true; + } + + return false; +} + // // R_DrawVisSprite // mfloorclip and mceilingclip should also be set. @@ -329,6 +367,7 @@ void R_DrawVisSprite (vissprite_t *vis) int x2, stop4; fixed_t xiscale; ESPSResult mode; + bool ispsprite = (!vis->sector && !vis->gx && !vis->gy && !vis->gz); dc_colormap = vis->Style.colormap; @@ -372,7 +411,8 @@ void R_DrawVisSprite (vissprite_t *vis) while ((dc_x < stop4) && (dc_x & 3)) { pixels = tex->GetColumn (frac >> FRACBITS, &spans); - R_DrawMaskedColumn (pixels, spans); + if (ispsprite || !R_ClipSpriteColumnWithPortals(vis->gx, vis->gy, vis)) + R_DrawMaskedColumn (pixels, spans); dc_x++; frac += xiscale; } @@ -383,7 +423,8 @@ void R_DrawVisSprite (vissprite_t *vis) for (int zz = 4; zz; --zz) { pixels = tex->GetColumn (frac >> FRACBITS, &spans); - R_DrawMaskedColumnHoriz (pixels, spans); + if (ispsprite || !R_ClipSpriteColumnWithPortals(vis->gx, vis->gy, vis)) + R_DrawMaskedColumnHoriz (pixels, spans); dc_x++; frac += xiscale; } @@ -393,7 +434,8 @@ void R_DrawVisSprite (vissprite_t *vis) while (dc_x < x2) { pixels = tex->GetColumn (frac >> FRACBITS, &spans); - R_DrawMaskedColumn (pixels, spans); + if (ispsprite || !R_ClipSpriteColumnWithPortals(vis->gx, vis->gy, vis)) + R_DrawMaskedColumn (pixels, spans); dc_x++; frac += xiscale; } @@ -503,7 +545,8 @@ void R_DrawWallSprite(vissprite_t *spr) { // calculate lighting dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, shade) << COLORMAPSHIFT); } - R_WallSpriteColumn(R_DrawMaskedColumn); + if (!R_ClipSpriteColumnWithPortals(spr->gx, spr->gy, spr)) + R_WallSpriteColumn(R_DrawMaskedColumn); dc_x++; } @@ -516,7 +559,8 @@ void R_DrawWallSprite(vissprite_t *spr) rt_initcols(); for (int zz = 4; zz; --zz) { - R_WallSpriteColumn(R_DrawMaskedColumnHoriz); + if (!R_ClipSpriteColumnWithPortals(spr->gx, spr->gy, spr)) + R_WallSpriteColumn(R_DrawMaskedColumnHoriz); dc_x++; } rt_draw4cols(dc_x - 4); @@ -528,7 +572,8 @@ void R_DrawWallSprite(vissprite_t *spr) { // calculate lighting dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, shade) << COLORMAPSHIFT); } - R_WallSpriteColumn(R_DrawMaskedColumn); + if (!R_ClipSpriteColumnWithPortals(spr->gx, spr->gy, spr)) + R_WallSpriteColumn(R_DrawMaskedColumn); dc_x++; } } @@ -668,6 +713,10 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor return; } + // [ZZ] Or less definitely not visible (hue) + if (CurrentPortal && !!P_PointOnLineSide(thing->x, thing->y, CurrentPortal->dst)) + return; + // [RH] Interpolate the sprite's position to make it look smooth fx = thing->PrevX + FixedMul (r_TicFrac, thing->x - thing->PrevX); fy = thing->PrevY + FixedMul (r_TicFrac, thing->y - thing->PrevY); @@ -885,6 +934,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor // store information in a vissprite vis = R_NewVisSprite(); + vis->CurrentPortalUniq = CurrentPortalUniq; vis->xscale = xscale; vis->yscale = Scale(InvZtoScale, yscale, tz << 4); vis->idepth = (unsigned)DivScale32(1, tz) >> 1; // tz is 20.12, so idepth ought to be 12.20, but signed math makes it 13.19 @@ -912,6 +962,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor { vis = R_NewVisSprite(); + vis->CurrentPortalUniq = CurrentPortalUniq; vis->xscale = xscale; vis->yscale = yscale; vis->x1 = WindowLeft; @@ -1073,6 +1124,7 @@ static void R_ProjectWallSprite(AActor *thing, fixed_t fx, fixed_t fy, fixed_t f gzb = fz + yscale * scaled_bo; vis = R_NewVisSprite(); + vis->CurrentPortalUniq = CurrentPortalUniq; vis->x1 = wallc.sx1 < WindowLeft ? WindowLeft : wallc.sx1; vis->x2 = wallc.sx2 >= WindowRight ? WindowRight : wallc.sx2-1; vis->yscale = yscale; @@ -1767,7 +1819,6 @@ void R_SortVisSprites (bool (*compare)(vissprite_t *, vissprite_t *), size_t fir std::stable_sort(&spritesorter[0], &spritesorter[vsprcount], compare); } - // // R_DrawSprite // @@ -2062,8 +2113,11 @@ void R_DrawSprite (vissprite_t *spr) for (ds = ds_p; ds-- > firstdrawseg; ) // new -- killough { + // [ZZ] portal handling here + if (ds->CurrentPortalUniq != spr->CurrentPortalUniq) + continue; // kg3D - no clipping on fake segs - if(ds->fake) continue; + if (ds->fake) continue; // determine if the drawseg obscures the sprite if (ds->x1 > x2 || ds->x2 < x1 || (!(ds->silhouette & SIL_BOTH) && ds->maskedtexturecol == -1 && @@ -2198,6 +2252,8 @@ void R_DrawMaskedSingle (bool renew) for (i = vsprcount; i > 0; i--) { + if (spritesorter[i-1]->CurrentPortalUniq != CurrentPortalUniq) + continue; // probably another time R_DrawSprite (spritesorter[i-1]); } @@ -2215,6 +2271,9 @@ void R_DrawMaskedSingle (bool renew) } for (ds = ds_p; ds-- > firstdrawseg; ) // new -- killough { + // [ZZ] the same as above + if (ds->CurrentPortalUniq != CurrentPortalUniq) + continue; // kg3D - no fake segs if (ds->fake) continue; if (ds->maskedtexturecol != -1 || ds->bFogBoundary) @@ -2294,6 +2353,10 @@ void R_ProjectParticle (particle_t *particle, const sector_t *sector, int shade, sector_t* heightsec = NULL; BYTE* map; + // [ZZ] Particle not visible through the portal plane + if (CurrentPortal && !!P_PointOnLineSide(particle->x, particle->y, CurrentPortal->dst)) + return; + // transform the origin point tr_x = particle->x - viewx; tr_y = particle->y - viewy; @@ -2397,6 +2460,7 @@ void R_ProjectParticle (particle_t *particle, const sector_t *sector, int shade, // store information in a vissprite vis = R_NewVisSprite (); + vis->CurrentPortalUniq = CurrentPortalUniq; vis->heightsec = heightsec; vis->xscale = xscale; // vis->yscale = FixedMul (xscale, InvZtoScale); @@ -2449,8 +2513,11 @@ static void R_DrawMaskedSegsBehindParticle (const vissprite_t *vis) for (unsigned int p = InterestingDrawsegs.Size(); p-- > FirstInterestingDrawseg; ) { drawseg_t *ds = &drawsegs[InterestingDrawsegs[p]]; + // [ZZ] only draw stuff that's inside the same portal as the particle, other portals will care for themselves + if (ds->CurrentPortalUniq != vis->CurrentPortalUniq) + continue; // kg3D - no fake segs - if(ds->fake) continue; + if (ds->fake) continue; if (ds->x1 >= x2 || ds->x2 < x1) { continue; @@ -2488,6 +2555,8 @@ void R_DrawParticle (vissprite_t *vis) fg = fg2rgb[color]; } + /* + spacing = RenderTarget->GetPitch() - countbase; dest = ylookup[yl] + x1 + dc_destorg; @@ -2501,7 +2570,28 @@ void R_DrawParticle (vissprite_t *vis) *dest++ = RGB32k[0][0][bg & (bg>>15)]; } while (--count); dest += spacing; - } while (--ycount); + } while (--ycount);*/ + + // original was row-wise + // width = countbase + // height = ycount + + spacing = RenderTarget->GetPitch(); + + for (int x = x1; x < (x1+countbase); x++) + { + dc_x = x; + if (R_ClipSpriteColumnWithPortals(vis->gx, vis->gy, vis)) + continue; + dest = ylookup[yl] + x + dc_destorg; + for (int y = 0; y < ycount; y++) + { + DWORD bg = bg2rgb[*dest]; + bg = (fg+bg) | 0x1f07c1f; + *dest = RGB32k[0][0][bg & (bg>>15)]; + dest += spacing; + } + } } extern fixed_t baseyaspectmul; diff --git a/src/r_things.h b/src/r_things.h index 3ce1a4d4d..732ef95e3 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -80,6 +80,7 @@ struct vissprite_t short renderflags; DWORD Translation; // [RH] for color translation visstyle_t Style; + int CurrentPortalUniq; // [ZZ] to identify the portal that this thing is in. used for clipping. }; struct particle_t; diff --git a/zdoom.vcproj b/zdoom.vcproj index cabc6c84f..15895c0a3 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -6632,6 +6632,18 @@ > + + + + + + From cac266b5dfbe329be5161a8b259bcf1e8b2a5536 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 16 Dec 2014 18:13:20 +0200 Subject: [PATCH 2/6] Put line ID from args[1] for Hexen maps --- src/p_setup.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 8076e19a9..361832323 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1956,6 +1956,11 @@ void P_SetLineID (line_t *ld) case Static_Init: if (ld->args[1] == Init_SectorLink) ld->id = ld->args[0]; break; + + case Line_SetPortal: + case Line_SetVisualPortal: + ld->id = ld->args[1]; // 0 = target id, 1 = this id, 2 = plane anchor + break; } } } From e04a3c094af5c324674bf657fc8806b511feb54f Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 16 Dec 2014 18:46:26 +0200 Subject: [PATCH 3/6] Fixed portal detection in R_AddLine --- src/r_bsp.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index e35c95f45..4d4399810 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -588,8 +588,6 @@ void R_AddLine (seg_t *line) rw_mustmarkfloor = rw_mustmarkceiling = false; rw_havehigh = rw_havelow = false; - bool is_portal = (line->linedef && line->linedef->special == Line_Mirror); - // Single sided line? if (backsector == NULL) { @@ -656,7 +654,7 @@ void R_AddLine (seg_t *line) // Window. solid = false; } - else if (is_portal + else if (line->linedef->portal // [ZZ] portals are always drawn, even if there's exactly same sector on both sides || backsector->lightlevel != frontsector->lightlevel || backsector->GetTexture(sector_t::floor) != frontsector->GetTexture(sector_t::floor) From 5d3c2f17506813c3ff0b4d51ff763f7b655c42f9 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 16 Dec 2014 19:48:06 +0200 Subject: [PATCH 4/6] Made a CVar to limit recursions; Made a CVar to highlight portal borders; Fixed slight logical bug in unique portal identifiers --- src/r_main.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/src/r_main.cpp b/src/r_main.cpp index c6af51533..94a0cce10 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -618,15 +618,63 @@ void R_SetupFreelook() // //========================================================================== +CVAR(Int, r_portal_recursions, 4, CVAR_ARCHIVE) +CVAR(Bool, r_highlight_portals, false, CVAR_ARCHIVE) + +void R_HighlightPortal (PortalDrawseg* pds) +{ + // [ZZ] NO OVERFLOW CHECKS HERE + // I believe it won't break. if it does, blame me. :( + + BYTE color = (BYTE)BestColor((DWORD *)GPalette.BaseColors, 255, 0, 0, 0, 255); + RenderTarget->DrawLine(pds->x1, pds->ceilingclip[0], pds->x1, pds->floorclip[0], color, 0); + RenderTarget->DrawLine(pds->x2, pds->ceilingclip[pds->ceilingclip.Size()-1], pds->x2, pds->floorclip[pds->floorclip.Size()-1], color, 0); + + BYTE* pixels = RenderTarget->GetBuffer(); + // top edge + for (int x = pds->x1+1; x < pds->x2; x++) + { + if (x < 0 || x >= RenderTarget->GetWidth()) + continue; + + int p = x - pds->x1; + + int Ytop = pds->ceilingclip[p]; + int Ybottom = pds->floorclip[p]; + + int YtopPrev = pds->ceilingclip[p-1]; + int YbottomPrev = pds->floorclip[p-1]; + + if (Ytop < 0) Ytop = 0; + if (Ybottom >= RenderTarget->GetHeight()) + Ybottom = RenderTarget->GetHeight()-1; + + if (YtopPrev < 0) YtopPrev = 0; + if (YbottomPrev >= RenderTarget->GetHeight()) + YbottomPrev = RenderTarget->GetHeight()-1; + + if (abs(Ytop-YtopPrev) > 1) + RenderTarget->DrawLine(x, YtopPrev, x, Ytop, color, 0); + else *(pixels + Ytop * RenderTarget->GetPitch() + x) = color; + + if (abs(Ybottom-YbottomPrev) > 1) + RenderTarget->DrawLine(x, YbottomPrev, x, Ybottom, color, 0); + else *(pixels + Ybottom * RenderTarget->GetPitch() + x) = color; + } +} + void R_EnterPortal (PortalDrawseg* pds, int depth) { // [ZZ] check depth. fill portal with black if it's exceeding the visual recursion limit, and continue like nothing happened. - if (depth > 4) + if (depth > r_portal_recursions) { BYTE color = (BYTE)BestColor((DWORD *)GPalette.BaseColors, 0, 0, 0, 0, 255); int spacing = RenderTarget->GetPitch(); for (int x = pds->x1; x <= pds->x2; x++) { + if (x < 0 || x >= RenderTarget->GetWidth()) + continue; + int Ytop = pds->ceilingclip[x-pds->x1]; int Ybottom = pds->floorclip[x-pds->x1]; @@ -643,6 +691,9 @@ void R_EnterPortal (PortalDrawseg* pds, int depth) } } + if (r_highlight_portals) + R_HighlightPortal(pds); + return; } @@ -650,7 +701,6 @@ void R_EnterPortal (PortalDrawseg* pds, int depth) fixed_t startx = viewx; fixed_t starty = viewy; - int prevuniq = CurrentPortalUniq; CurrentPortalUniq++; unsigned int portalsAtStart = WallPortals.Size (); @@ -738,12 +788,14 @@ void R_EnterPortal (PortalDrawseg* pds, int depth) R_DrawSkyBoxes (); PlaneCycles.Unclock(); + int prevuniq = CurrentPortalUniq; // depth check is in another place right now unsigned int portalsAtEnd = WallPortals.Size (); for (; portalsAtStart < portalsAtEnd; portalsAtStart++) { R_EnterPortal (&WallPortals[portalsAtStart], depth + 1); } + CurrentPortalUniq = prevuniq; NetUpdate(); @@ -753,10 +805,13 @@ void R_EnterPortal (PortalDrawseg* pds, int depth) NetUpdate(); + // draw a red line around a portal if it's being highlighted + if (r_highlight_portals) + R_HighlightPortal(pds); + R_3D_LeaveSkybox(); // pop 3D floor height map CurrentPortal = prevpds; MirrorFlags = prevmf; - CurrentPortalUniq = prevuniq; viewangle = startang; viewx = startx; viewy = starty; From 322ecae93f1b5788bd48f66b18d009059165283f Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 16 Dec 2014 21:31:21 +0200 Subject: [PATCH 5/6] Fixed sprite clipping with drawsegs (removed unnecessary portal check) --- src/r_main.cpp | 53 +++++++++++++++++++++++++----------------------- src/r_plane.cpp | 16 +++++++++++++-- src/r_segs.cpp | 22 ++++++++++++++++---- src/r_things.cpp | 6 ++++-- 4 files changed, 64 insertions(+), 33 deletions(-) diff --git a/src/r_main.cpp b/src/r_main.cpp index 94a0cce10..7314696be 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -627,32 +627,27 @@ void R_HighlightPortal (PortalDrawseg* pds) // I believe it won't break. if it does, blame me. :( BYTE color = (BYTE)BestColor((DWORD *)GPalette.BaseColors, 255, 0, 0, 0, 255); - RenderTarget->DrawLine(pds->x1, pds->ceilingclip[0], pds->x1, pds->floorclip[0], color, 0); - RenderTarget->DrawLine(pds->x2, pds->ceilingclip[pds->ceilingclip.Size()-1], pds->x2, pds->floorclip[pds->floorclip.Size()-1], color, 0); BYTE* pixels = RenderTarget->GetBuffer(); // top edge - for (int x = pds->x1+1; x < pds->x2; x++) + for (int x = pds->x1; x <= pds->x2; x++) { if (x < 0 || x >= RenderTarget->GetWidth()) continue; int p = x - pds->x1; - int Ytop = pds->ceilingclip[p]; int Ybottom = pds->floorclip[p]; + if (x == pds->x1 || x == pds->x2) + { + RenderTarget->DrawLine(x, Ytop, x, Ybottom, color, 0); + continue; + } + int YtopPrev = pds->ceilingclip[p-1]; int YbottomPrev = pds->floorclip[p-1]; - if (Ytop < 0) Ytop = 0; - if (Ybottom >= RenderTarget->GetHeight()) - Ybottom = RenderTarget->GetHeight()-1; - - if (YtopPrev < 0) YtopPrev = 0; - if (YbottomPrev >= RenderTarget->GetHeight()) - YbottomPrev = RenderTarget->GetHeight()-1; - if (abs(Ytop-YtopPrev) > 1) RenderTarget->DrawLine(x, YtopPrev, x, Ytop, color, 0); else *(pixels + Ytop * RenderTarget->GetPitch() + x) = color; @@ -680,10 +675,6 @@ void R_EnterPortal (PortalDrawseg* pds, int depth) BYTE *dest = RenderTarget->GetBuffer() + x + Ytop * spacing; - if (Ytop < 0) Ytop = 0; - if (Ybottom >= RenderTarget->GetHeight()) - Ybottom = RenderTarget->GetHeight()-1; - for (int y = Ytop; y <= Ybottom; y++) { *dest = color; @@ -700,6 +691,7 @@ void R_EnterPortal (PortalDrawseg* pds, int depth) angle_t startang = viewangle; fixed_t startx = viewx; fixed_t starty = viewy; + fixed_t startz = viewz; CurrentPortalUniq++; @@ -760,17 +752,11 @@ void R_EnterPortal (PortalDrawseg* pds, int depth) CurrentPortal = pds; R_ClearPlanes (false); - R_ClearClipSegs (pds->x1, pds->x2 + 1); // todo: check if this "+1" is actually needed - - // some portals have height differences, account for this here - R_3D_EnterSkybox(); // push 3D floor height map - - memcpy (ceilingclip + pds->x1, &pds->ceilingclip[0], pds->ceilingclip.Size()*sizeof(*ceilingclip)); - memcpy (floorclip + pds->x1, &pds->floorclip[0], pds->floorclip.Size()*sizeof(*floorclip)); + R_ClearClipSegs (pds->x1, pds->x2+1); // todo: check if this "+1" is actually needed WindowLeft = pds->x1; WindowRight = pds->x2; - + // RF_XFLIP should be removed before calling the root function int prevmf = MirrorFlags; if (pds->mirror) @@ -780,6 +766,13 @@ void R_EnterPortal (PortalDrawseg* pds, int depth) else MirrorFlags |= RF_XFLIP; } + // some portals have height differences, account for this here + R_3D_EnterSkybox(); // push 3D floor height map + + // first pass, set clipping + memcpy (ceilingclip + pds->x1, &pds->ceilingclip[0], pds->len*sizeof(*ceilingclip)); + memcpy (floorclip + pds->x1, &pds->floorclip[0], pds->len*sizeof(*floorclip)); + R_RenderBSPNode (nodes + numnodes - 1); R_3D_ResetClip(); // reset clips (floor/ceiling) @@ -788,6 +781,8 @@ void R_EnterPortal (PortalDrawseg* pds, int depth) R_DrawSkyBoxes (); PlaneCycles.Unclock(); + fixed_t vzp = viewz; + int prevuniq = CurrentPortalUniq; // depth check is in another place right now unsigned int portalsAtEnd = WallPortals.Size (); @@ -795,6 +790,7 @@ void R_EnterPortal (PortalDrawseg* pds, int depth) { R_EnterPortal (&WallPortals[portalsAtStart], depth + 1); } + int prevuniq2 = CurrentPortalUniq; CurrentPortalUniq = prevuniq; NetUpdate(); @@ -805,16 +801,19 @@ void R_EnterPortal (PortalDrawseg* pds, int depth) NetUpdate(); + R_3D_LeaveSkybox(); // pop 3D floor height map + CurrentPortalUniq = prevuniq2; + // draw a red line around a portal if it's being highlighted if (r_highlight_portals) R_HighlightPortal(pds); - R_3D_LeaveSkybox(); // pop 3D floor height map CurrentPortal = prevpds; MirrorFlags = prevmf; viewangle = startang; viewx = startx; viewy = starty; + viewz = startz; } //========================================================================== @@ -899,6 +898,7 @@ void R_RenderActorView (AActor *actor, bool dontmaplines) WindowRight = viewwidth - 1; MirrorFlags = 0; CurrentPortal = NULL; + CurrentPortalUniq = 0; r_dontmaplines = dontmaplines; @@ -939,6 +939,9 @@ void R_RenderActorView (AActor *actor, bool dontmaplines) R_EnterPortal(&WallPortals[i], 0); } + CurrentPortal = NULL; + CurrentPortalUniq = 0; + NetUpdate (); MaskedCycles.Clock(); diff --git a/src/r_plane.cpp b/src/r_plane.cpp index dc13e95a3..111954bcd 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -690,7 +690,10 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl sky == check->sky && CurrentPortalUniq == check->CurrentPortalUniq && MirrorFlags == check->MirrorFlags && - CurrentSkybox == check->CurrentSkybox + CurrentSkybox == check->CurrentSkybox && + viewx == check->viewx && + viewy == check->viewy && + viewz == check->viewz ) { return check; @@ -1065,22 +1068,31 @@ void R_DrawHeightPlanes(fixed_t height) ds_color = 3; + fixed_t oViewX = viewx, oViewY = viewy, oViewZ = viewz; + angle_t oViewAngle = viewangle; + for (i = 0; i < MAXVISPLANES; i++) { for (pl = visplanes[i]; pl; pl = pl->next) { // kg3D - draw only correct planes - if(pl->CurrentSkybox != CurrentSkybox) + if(pl->CurrentSkybox != CurrentSkybox || pl->CurrentPortalUniq != CurrentPortalUniq) continue; if(pl->sky < 0 && pl->height.Zat0() == height) { viewx = pl->viewx; viewy = pl->viewy; + viewz = pl->viewz; viewangle = pl->viewangle; MirrorFlags = pl->MirrorFlags; R_DrawSinglePlane (pl, pl->sky & 0x7FFFFFFF, pl->Additive, true); } } } + + viewx = oViewX; + viewy = oViewY; + viewz = oViewZ; + viewangle = oViewAngle; } diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 9e20a3535..9009240bc 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -2591,10 +2591,24 @@ void R_StoreWallRange (int start, int stop) pds.dst = curline->linedef->portal_dst; pds.x1 = ds_p->x1; pds.x2 = ds_p->x2; - pds.ceilingclip.Resize((pds.x2-pds.x1)+1); - memcpy(&pds.ceilingclip[0], openings + ds_p->sprtopclip, pds.ceilingclip.Size()*sizeof(*openings)); - pds.floorclip.Resize((pds.x2-pds.x1)+1); - memcpy(&pds.floorclip[0], openings + ds_p->sprbottomclip, pds.floorclip.Size()*sizeof(*openings)); + pds.len = (pds.x2 - pds.x1) + 1; + pds.ceilingclip.Resize(pds.len); + memcpy(&pds.ceilingclip[0], openings + ds_p->sprtopclip, pds.len*sizeof(*openings)); + pds.floorclip.Resize(pds.len); + memcpy(&pds.floorclip[0], openings + ds_p->sprbottomclip, pds.len*sizeof(*openings)); + + for (int i = 0; i < (pds.x2-pds.x1)+1; i++) + { + if (pds.ceilingclip[i] < 0) + pds.ceilingclip[i] = 0; + if (pds.ceilingclip[i] >= RenderTarget->GetHeight()) + pds.ceilingclip[i] = RenderTarget->GetHeight()-1; + if (pds.floorclip[i] < 0) + pds.floorclip[i] = 0; + if (pds.floorclip[i] >= RenderTarget->GetHeight()) + pds.floorclip[i] = RenderTarget->GetHeight()-1; + } + pds.mirror = curline->linedef->portal_mirror; WallPortals.Push(pds); } diff --git a/src/r_things.cpp b/src/r_things.cpp index 96afaa216..9cfedf068 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -2114,8 +2114,10 @@ void R_DrawSprite (vissprite_t *spr) for (ds = ds_p; ds-- > firstdrawseg; ) // new -- killough { // [ZZ] portal handling here - if (ds->CurrentPortalUniq != spr->CurrentPortalUniq) - continue; + //if (ds->CurrentPortalUniq != spr->CurrentPortalUniq) + // continue; + // [ZZ] WARNING: uncommenting the two above lines, totally breaks sprite clipping + // kg3D - no clipping on fake segs if (ds->fake) continue; // determine if the drawseg obscures the sprite From 45c97c3ac55f3e6432b84d75539c455e4308c33c Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 16 Dec 2014 22:54:49 +0200 Subject: [PATCH 6/6] Fixed trivial bug with two-sided portals not clipping stuff correctly --- src/r_bsp.cpp | 6 ++---- src/r_main.cpp | 2 +- src/r_things.cpp | 10 +++++----- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index 4d4399810..0fc33c042 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -589,7 +589,7 @@ void R_AddLine (seg_t *line) rw_havehigh = rw_havelow = false; // Single sided line? - if (backsector == NULL) + if (backsector == NULL || (line->linedef->portal && line->sidedef == line->linedef->sidedef[0])) { solid = true; } @@ -654,9 +654,7 @@ void R_AddLine (seg_t *line) // Window. solid = false; } - else if (line->linedef->portal // [ZZ] portals are always drawn, even if there's exactly same sector on both sides - - || backsector->lightlevel != frontsector->lightlevel + else if (backsector->lightlevel != frontsector->lightlevel || backsector->GetTexture(sector_t::floor) != frontsector->GetTexture(sector_t::floor) || backsector->GetTexture(sector_t::ceiling) != frontsector->GetTexture(sector_t::ceiling) || curline->sidedef->GetTexture(side_t::mid).isValid() diff --git a/src/r_main.cpp b/src/r_main.cpp index 7314696be..7c15cefb0 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -641,7 +641,7 @@ void R_HighlightPortal (PortalDrawseg* pds) if (x == pds->x1 || x == pds->x2) { - RenderTarget->DrawLine(x, Ytop, x, Ybottom, color, 0); + RenderTarget->DrawLine(x, Ytop, x, Ybottom+1, color, 0); continue; } diff --git a/src/r_things.cpp b/src/r_things.cpp index 9cfedf068..92cd84155 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -2150,7 +2150,8 @@ void R_DrawSprite (vissprite_t *spr) ds->curline->v1->x - spr->gx, ds->curline->v2->y - ds->curline->v1->y) <= 0)) { // seg is behind sprite, so draw the mid texture if it has one - if (ds->maskedtexturecol != -1 || ds->bFogBoundary) + if (ds->CurrentPortalUniq == CurrentPortalUniq && // [ZZ] instead, portal uniq check is made here + (ds->maskedtexturecol != -1 || ds->bFogBoundary)) R_RenderMaskedSegRange (ds, r1, r2); continue; } @@ -2515,9 +2516,6 @@ static void R_DrawMaskedSegsBehindParticle (const vissprite_t *vis) for (unsigned int p = InterestingDrawsegs.Size(); p-- > FirstInterestingDrawseg; ) { drawseg_t *ds = &drawsegs[InterestingDrawsegs[p]]; - // [ZZ] only draw stuff that's inside the same portal as the particle, other portals will care for themselves - if (ds->CurrentPortalUniq != vis->CurrentPortalUniq) - continue; // kg3D - no fake segs if (ds->fake) continue; if (ds->x1 >= x2 || ds->x2 < x1) @@ -2526,7 +2524,9 @@ static void R_DrawMaskedSegsBehindParticle (const vissprite_t *vis) } if (Scale (ds->siz2 - ds->siz1, (x2 + x1)/2 - ds->sx1, ds->sx2 - ds->sx1) + ds->siz1 < vis->idepth) { - R_RenderMaskedSegRange (ds, MAX (ds->x1, x1), MIN (ds->x2, x2-1)); + // [ZZ] only draw stuff that's inside the same portal as the particle, other portals will care for themselves + if (ds->CurrentPortalUniq == vis->CurrentPortalUniq) + R_RenderMaskedSegRange (ds, MAX (ds->x1, x1), MIN (ds->x2, x2-1)); } } }