diff --git a/src/actionspecials.h b/src/actionspecials.h index 752ef77ebd..879f16a113 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 bc4cbdb758..e0eb524f1b 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 2ee2ae83a8..d9f2857bab 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 6b5d9403f0..8076e19a99 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 473cdcd814..cb9ed19f16 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 c562558880..e35c95f451 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 1b5af9805d..59a2753987 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 dd21365087..8f94db3f2e 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 bc3c4c7c02..c6af51533a 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 6572c1f0b1..dc13e95a3c 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 231fa3ad4c..5fd9b8eebf 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 15f736c932..9e20a3535a 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 c0475ee759..96afaa2166 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 3ce1a4d4dd..732ef95e3e 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 cabc6c84f1..15895c0a35 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -6632,6 +6632,18 @@ > + + + + + +