mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-29 15:22:08 +00:00
Merge branch 'portals2_visual'
This commit is contained in:
commit
ba54d73e07
18 changed files with 889 additions and 130 deletions
|
@ -979,6 +979,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
|
||||||
p_xlat.cpp
|
p_xlat.cpp
|
||||||
parsecontext.cpp
|
parsecontext.cpp
|
||||||
po_man.cpp
|
po_man.cpp
|
||||||
|
portal.cpp
|
||||||
r_swrenderer.cpp
|
r_swrenderer.cpp
|
||||||
r_utility.cpp
|
r_utility.cpp
|
||||||
r_3dfloors.cpp
|
r_3dfloors.cpp
|
||||||
|
|
|
@ -138,6 +138,9 @@ DEFINE_SPECIAL(Thing_SpawnFacing, 139, 2, 4, 4)
|
||||||
DEFINE_SPECIAL(Sector_ChangeSound, 140, 2, 2, 2)
|
DEFINE_SPECIAL(Sector_ChangeSound, 140, 2, 2, 2)
|
||||||
|
|
||||||
DEFINE_SPECIAL(Teleport_NoStop, 154, 2, 3, 3)
|
DEFINE_SPECIAL(Teleport_NoStop, 154, 2, 3, 3)
|
||||||
|
// portal specials
|
||||||
|
DEFINE_SPECIAL(Line_SetVisualPortal, 155, -1, -1, 3)
|
||||||
|
DEFINE_SPECIAL(Line_SetPortal, 156, -1, -1, 3)
|
||||||
// GZDoom/Vavoom specials
|
// GZDoom/Vavoom specials
|
||||||
// Although ZDoom doesn't support them it's better to have them defined so that
|
// 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
|
// WADs using them somewhere can at least be started without aborting due
|
||||||
|
|
|
@ -75,6 +75,7 @@
|
||||||
#include "actorptrselect.h"
|
#include "actorptrselect.h"
|
||||||
#include "farchive.h"
|
#include "farchive.h"
|
||||||
#include "decallib.h"
|
#include "decallib.h"
|
||||||
|
#include "portal.h"
|
||||||
#include "p_terrain.h"
|
#include "p_terrain.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "p_effect.h"
|
#include "p_effect.h"
|
||||||
|
@ -8298,6 +8299,9 @@ scriptwait:
|
||||||
line->args[4] = STACK(1);
|
line->args[4] = STACK(1);
|
||||||
DPrintf("Set special on line %d (id %d) to %d(%d,%d,%d,%d,%d)\n",
|
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));
|
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;
|
sp -= 7;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "g_level.h"
|
#include "g_level.h"
|
||||||
#include "r_data/colormaps.h"
|
#include "r_data/colormaps.h"
|
||||||
#include "gi.h"
|
#include "gi.h"
|
||||||
|
#include "portal.h"
|
||||||
|
|
||||||
// MACROS ------------------------------------------------------------------
|
// MACROS ------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -629,6 +630,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
|
// Finish setting sector properties that depend on walls
|
||||||
for (i = 0; i < numsectors; ++i, ++bsec)
|
for (i = 0; i < numsectors; ++i, ++bsec)
|
||||||
{
|
{
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
#include "po_man.h"
|
#include "po_man.h"
|
||||||
#include "r_renderer.h"
|
#include "r_renderer.h"
|
||||||
#include "r_data/colormaps.h"
|
#include "r_data/colormaps.h"
|
||||||
|
#include "portal.h"
|
||||||
|
|
||||||
#include "fragglescript/t_fs.h"
|
#include "fragglescript/t_fs.h"
|
||||||
|
|
||||||
|
@ -1959,6 +1960,11 @@ void P_SetLineID (int i, line_t *ld)
|
||||||
case Static_Init:
|
case Static_Init:
|
||||||
if (ld->args[1] == Init_SectorLink) setid = ld->args[0];
|
if (ld->args[1] == Init_SectorLink) setid = ld->args[0];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Line_SetPortal:
|
||||||
|
case Line_SetVisualPortal:
|
||||||
|
setid = ld->args[1]; // 0 = target id, 1 = this id, 2 = plane anchor
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (setid != -1)
|
if (setid != -1)
|
||||||
{
|
{
|
||||||
|
@ -2059,6 +2065,9 @@ void P_FinishLoadingLineDef(line_t *ld, int alpha)
|
||||||
ld->special = 0;
|
ld->special = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [ZZ] check initial portal link
|
||||||
|
P_CheckPortal(ld);
|
||||||
}
|
}
|
||||||
// killough 4/4/98: delay using sidedefs until they are loaded
|
// killough 4/4/98: delay using sidedefs until they are loaded
|
||||||
void P_FinishLoadingLineDefs ()
|
void P_FinishLoadingLineDefs ()
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include "r_data/colormaps.h"
|
#include "r_data/colormaps.h"
|
||||||
#include "w_wad.h"
|
#include "w_wad.h"
|
||||||
#include "p_tags.h"
|
#include "p_tags.h"
|
||||||
|
#include "portal.h"
|
||||||
#include "p_terrain.h"
|
#include "p_terrain.h"
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
368
src/portal.cpp
Normal file
368
src/portal.cpp
Normal file
|
@ -0,0 +1,368 @@
|
||||||
|
#include "portal.h"
|
||||||
|
#include "p_local.h"
|
||||||
|
#include "p_lnspec.h"
|
||||||
|
#include "r_bsp.h"
|
||||||
|
#include "r_segs.h"
|
||||||
|
#include "c_cvars.h"
|
||||||
|
#include "m_bbox.h"
|
||||||
|
#include "p_tags.h"
|
||||||
|
|
||||||
|
// simulation recurions maximum
|
||||||
|
CVAR(Int, sv_portal_recursions, 4, CVAR_ARCHIVE|CVAR_SERVERINFO)
|
||||||
|
|
||||||
|
PortalDrawseg* CurrentPortal = NULL;
|
||||||
|
int CurrentPortalUniq = 0;
|
||||||
|
bool CurrentPortalInSkybox = false;
|
||||||
|
|
||||||
|
// [ZZ] lots of floats here to avoid overflowing a lot
|
||||||
|
bool R_IntersectLines(fixed_t o1x, fixed_t o1y, fixed_t p1x, fixed_t p1y,
|
||||||
|
fixed_t o2x, fixed_t o2y, fixed_t p2x, fixed_t p2y,
|
||||||
|
fixed_t& rx, fixed_t& ry)
|
||||||
|
{
|
||||||
|
float xx = FIXED2FLOAT(o2x) - FIXED2FLOAT(o1x);
|
||||||
|
float xy = FIXED2FLOAT(o2y) - FIXED2FLOAT(o1y);
|
||||||
|
|
||||||
|
float d1x = FIXED2FLOAT(p1x) - FIXED2FLOAT(o1x);
|
||||||
|
float d1y = FIXED2FLOAT(p1y) - FIXED2FLOAT(o1y);
|
||||||
|
|
||||||
|
if (d1x > d1y)
|
||||||
|
{
|
||||||
|
d1y = d1y / d1x * 32767.0f;
|
||||||
|
d1x = 32767.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d1x = d1x / d1y * 32767.0f;
|
||||||
|
d1y = 32767.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float d2x = FIXED2FLOAT(p2x) - FIXED2FLOAT(o2x);
|
||||||
|
float d2y = FIXED2FLOAT(p2y) - FIXED2FLOAT(o2y);
|
||||||
|
|
||||||
|
float cross = d1x*d2y - d1y*d2x;
|
||||||
|
if (fabs(cross) < 1e-8)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
float t1 = (xx * d2y - xy * d2x)/cross;
|
||||||
|
rx = o1x + FLOAT2FIXED(d1x * t1);
|
||||||
|
ry = o1y + FLOAT2FIXED(d1y * t1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int P_PointOnLineSideExplicit (fixed_t x, fixed_t y, fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
|
||||||
|
{
|
||||||
|
return DMulScale32 (y-y1, x2-x1, x1-x, y2-y1) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool P_ClipLineToPortal(line_t* line, line_t* portal, fixed_t viewx, fixed_t viewy, bool partial, bool samebehind)
|
||||||
|
{
|
||||||
|
// check if this line is between portal and the viewer. clip away if it is.
|
||||||
|
bool behind1 = !!P_PointOnLineSide(line->v1->x, line->v1->y, portal);
|
||||||
|
bool behind2 = !!P_PointOnLineSide(line->v2->x, line->v2->y, portal);
|
||||||
|
|
||||||
|
// [ZZ] update 16.12.2014: if a vertex equals to one of portal's vertices, it's treated as being behind the portal.
|
||||||
|
// this is required in order to clip away diagonal lines around the portal (example: 1-sided triangle shape with a mirror on it's side)
|
||||||
|
if ((line->v1->x == portal->v1->x && line->v1->y == portal->v1->y) ||
|
||||||
|
(line->v1->x == portal->v2->x && line->v1->y == portal->v2->y))
|
||||||
|
behind1 = samebehind;
|
||||||
|
if ((line->v2->x == portal->v1->x && line->v2->y == portal->v1->y) ||
|
||||||
|
(line->v2->x == portal->v2->x && line->v2->y == portal->v2->y))
|
||||||
|
behind2 = samebehind;
|
||||||
|
|
||||||
|
if (behind1 && behind2)
|
||||||
|
{
|
||||||
|
// line is behind the portal plane. now check if it's in front of two view plane borders (i.e. if it will get in the way of rendering)
|
||||||
|
fixed_t dummyx, dummyy;
|
||||||
|
bool infront1 = R_IntersectLines(line->v1->x, line->v1->y, line->v2->x, line->v2->y, viewx, viewy, portal->v1->x, portal->v1->y, dummyx, dummyy);
|
||||||
|
bool infront2 = R_IntersectLines(line->v1->x, line->v1->y, line->v2->x, line->v2->y, viewx, viewy, portal->v2->x, portal->v2->y, dummyx, dummyy);
|
||||||
|
if (infront1 && infront2)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool P_CheckPortal(line_t* line)
|
||||||
|
{
|
||||||
|
if (line->special == Line_Mirror)
|
||||||
|
{
|
||||||
|
line->portal = true;
|
||||||
|
line->portal_mirror = true;
|
||||||
|
line->portal_passive = true;
|
||||||
|
line->portal_dst = line;
|
||||||
|
}
|
||||||
|
else if (line->special == Line_SetPortal ||
|
||||||
|
line->special == Line_SetVisualPortal)
|
||||||
|
{
|
||||||
|
// portal destination is special argument #0
|
||||||
|
line_t* dst = NULL;
|
||||||
|
|
||||||
|
if (line->args[0] > 0)
|
||||||
|
{
|
||||||
|
int linenum = -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < numlines; i++)
|
||||||
|
{
|
||||||
|
if (&lines[i] == line)
|
||||||
|
continue;
|
||||||
|
if (tagManager.LineHasID(&lines[i], line->args[0]))
|
||||||
|
{
|
||||||
|
dst = &lines[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dst)
|
||||||
|
{
|
||||||
|
line->portal = true;
|
||||||
|
line->portal_mirror = false;
|
||||||
|
line->portal_passive = (line->special == Line_SetVisualPortal);
|
||||||
|
line->portal_dst = dst;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line->portal = false;
|
||||||
|
line->portal_mirror = false;
|
||||||
|
line->portal_passive = false;
|
||||||
|
line->portal_dst = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line->portal = false;
|
||||||
|
line->portal_mirror = false;
|
||||||
|
line->portal_passive = false;
|
||||||
|
line->portal_dst = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (line->portal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y)
|
||||||
|
{
|
||||||
|
if (!src || !dst)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fixed_t nposx, nposy; // offsets from line
|
||||||
|
|
||||||
|
// Get the angle between the two linedefs, for rotating
|
||||||
|
// orientation and velocity. Rotate 180 degrees, and flip
|
||||||
|
// the position across the exit linedef, if reversed.
|
||||||
|
angle_t angle =
|
||||||
|
R_PointToAngle2(0, 0, dst->dx, dst->dy) -
|
||||||
|
R_PointToAngle2(0, 0, src->dx, src->dy);
|
||||||
|
|
||||||
|
angle += ANGLE_180;
|
||||||
|
|
||||||
|
// Sine, cosine of angle adjustment
|
||||||
|
fixed_t s = finesine[angle>>ANGLETOFINESHIFT];
|
||||||
|
fixed_t c = finecosine[angle>>ANGLETOFINESHIFT];
|
||||||
|
|
||||||
|
fixed_t tx, ty;
|
||||||
|
|
||||||
|
nposx = x - src->v1->x;
|
||||||
|
nposy = y - src->v1->y;
|
||||||
|
|
||||||
|
// Rotate position along normal to match exit linedef
|
||||||
|
tx = FixedMul(nposx, c) - FixedMul(nposy, s);
|
||||||
|
ty = FixedMul(nposy, c) + FixedMul(nposx, s);
|
||||||
|
|
||||||
|
tx += dst->v2->x;
|
||||||
|
ty += dst->v2->y;
|
||||||
|
|
||||||
|
x = tx;
|
||||||
|
y = ty;
|
||||||
|
}
|
||||||
|
|
||||||
|
void P_TranslatePortalVXVY(line_t* src, line_t* dst, fixed_t& vx, fixed_t& vy)
|
||||||
|
{
|
||||||
|
angle_t angle =
|
||||||
|
R_PointToAngle2(0, 0, dst->dx, dst->dy) -
|
||||||
|
R_PointToAngle2(0, 0, src->dx, src->dy);
|
||||||
|
|
||||||
|
angle += ANGLE_180;
|
||||||
|
|
||||||
|
// Sine, cosine of angle adjustment
|
||||||
|
fixed_t s = finesine[angle>>ANGLETOFINESHIFT];
|
||||||
|
fixed_t c = finecosine[angle>>ANGLETOFINESHIFT];
|
||||||
|
|
||||||
|
fixed_t orig_velx = vx;
|
||||||
|
fixed_t orig_vely = vy;
|
||||||
|
vx = FixedMul(orig_velx, c) - FixedMul(orig_vely, s);
|
||||||
|
vy = FixedMul(orig_vely, c) + FixedMul(orig_velx, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle)
|
||||||
|
{
|
||||||
|
if (!src || !dst)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get the angle between the two linedefs, for rotating
|
||||||
|
// orientation and velocity. Rotate 180 degrees, and flip
|
||||||
|
// the position across the exit linedef, if reversed.
|
||||||
|
angle_t xangle =
|
||||||
|
R_PointToAngle2(0, 0, dst->dx, dst->dy) -
|
||||||
|
R_PointToAngle2(0, 0, src->dx, src->dy);
|
||||||
|
|
||||||
|
xangle += ANGLE_180;
|
||||||
|
angle += xangle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z)
|
||||||
|
{
|
||||||
|
// args[2] = 0 - no teleport
|
||||||
|
// args[2] = 1 - adjust by floor difference
|
||||||
|
// args[2] = 2 - adjust by ceiling difference
|
||||||
|
|
||||||
|
if (src->args[2] == 1)
|
||||||
|
{
|
||||||
|
z = z - src->frontsector->floorplane.ZatPoint(src->v1->x, src->v1->y) + dst->frontsector->floorplane.ZatPoint(dst->v2->x, dst->v2->y);
|
||||||
|
}
|
||||||
|
else if (src->args[2] == 2)
|
||||||
|
{
|
||||||
|
z = z - src->frontsector->ceilingplane.ZatPoint(src->v1->x, src->v1->y) + dst->frontsector->ceilingplane.ZatPoint(dst->v2->x, dst->v2->y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate shortest distance from a point (x,y) to a linedef
|
||||||
|
fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y)
|
||||||
|
{
|
||||||
|
angle_t angle = R_PointToAngle2(0, 0, line->dx, line->dy);
|
||||||
|
angle += ANGLE_180;
|
||||||
|
|
||||||
|
fixed_t dx = line->v1->x - x;
|
||||||
|
fixed_t dy = line->v1->y - y;
|
||||||
|
|
||||||
|
fixed_t s = finesine[angle>>ANGLETOFINESHIFT];
|
||||||
|
fixed_t c = finecosine[angle>>ANGLETOFINESHIFT];
|
||||||
|
|
||||||
|
fixed_t d2x = FixedMul(dx, c) - FixedMul(dy, s);
|
||||||
|
|
||||||
|
return abs(d2x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy)
|
||||||
|
{
|
||||||
|
float _vx = FIXED2FLOAT(vx);
|
||||||
|
float _vy = FIXED2FLOAT(vy);
|
||||||
|
float len = sqrt(_vx*_vx+_vy*_vy);
|
||||||
|
vx = FLOAT2FIXED(_vx/len);
|
||||||
|
vy = FLOAT2FIXED(_vy/len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// portal tracer code
|
||||||
|
PortalTracer::PortalTracer(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy)
|
||||||
|
{
|
||||||
|
this->startx = startx;
|
||||||
|
this->starty = starty;
|
||||||
|
this->endx = endx;
|
||||||
|
this->endy = endy;
|
||||||
|
intx = endx;
|
||||||
|
inty = endy;
|
||||||
|
intxIn = intx;
|
||||||
|
intyIn = inty;
|
||||||
|
z = 0;
|
||||||
|
angle = 0;
|
||||||
|
depth = 0;
|
||||||
|
frac = 0;
|
||||||
|
in = NULL;
|
||||||
|
out = NULL;
|
||||||
|
vx = 0;
|
||||||
|
vy = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PortalTracer::TraceStep()
|
||||||
|
{
|
||||||
|
if (depth > sv_portal_recursions)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this->in = NULL;
|
||||||
|
this->out = NULL;
|
||||||
|
this->vx = 0;
|
||||||
|
this->vy = 0;
|
||||||
|
|
||||||
|
int oDepth = depth;
|
||||||
|
|
||||||
|
fixed_t dirx = endx-startx;
|
||||||
|
fixed_t diry = endy-starty;
|
||||||
|
P_NormalizeVXVY(dirx, diry);
|
||||||
|
|
||||||
|
dirx = 0;
|
||||||
|
diry = 0;
|
||||||
|
|
||||||
|
FPathTraverse it(startx-dirx, starty-diry, endx+dirx, endy+diry, PT_ADDLINES | PT_COMPATIBLE);
|
||||||
|
|
||||||
|
intercept_t *in;
|
||||||
|
while ((in = it.Next()))
|
||||||
|
{
|
||||||
|
line_t* li;
|
||||||
|
|
||||||
|
if (in->isaline)
|
||||||
|
{
|
||||||
|
li = in->d.line;
|
||||||
|
|
||||||
|
if (li->portal && !li->portal_passive)
|
||||||
|
{
|
||||||
|
if (P_PointOnLineSide(startx-dirx, starty-diry, li))
|
||||||
|
continue; // we're at the back side of this line
|
||||||
|
|
||||||
|
line_t* out = li->portal_dst;
|
||||||
|
|
||||||
|
this->in = li;
|
||||||
|
this->out = out;
|
||||||
|
|
||||||
|
// we only know that we crossed it, but we also need to know WHERE we crossed it
|
||||||
|
fixed_t vx = it.Trace().dx;
|
||||||
|
fixed_t vy = it.Trace().dy;
|
||||||
|
|
||||||
|
fixed_t x = it.Trace().x + FixedMul(vx, in->frac);
|
||||||
|
fixed_t y = it.Trace().y + FixedMul(vy, in->frac);
|
||||||
|
|
||||||
|
P_NormalizeVXVY(vx, vy);
|
||||||
|
|
||||||
|
this->vx = vx;
|
||||||
|
this->vy = vy;
|
||||||
|
|
||||||
|
// teleport our trace
|
||||||
|
|
||||||
|
if (!out->backsector)
|
||||||
|
{
|
||||||
|
intx = x + vx;
|
||||||
|
inty = y + vy;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
intx = x - vx;
|
||||||
|
inty = y - vy;
|
||||||
|
}
|
||||||
|
|
||||||
|
//P_TranslateCoordinatesAndAngle(li, out, startx, starty, noangle);
|
||||||
|
//P_TranslateCoordinatesAndAngle(li, out, endx, endy, angle);
|
||||||
|
//if (hdeltaZ)
|
||||||
|
// P_TranslateZ(li, out, deltaZ);
|
||||||
|
//P_TranslateCoordinatesAndAngle(li, out, vx, vy, noangle);
|
||||||
|
|
||||||
|
P_TranslatePortalXY(li, out, startx, starty);
|
||||||
|
P_TranslatePortalVXVY(li, out, this->vx, this->vy);
|
||||||
|
intxIn = intx;
|
||||||
|
intyIn = inty;
|
||||||
|
P_TranslatePortalXY(li, out, intx, inty);
|
||||||
|
P_TranslatePortalXY(li, out, endx, endy);
|
||||||
|
P_TranslatePortalAngle(li, out, angle);
|
||||||
|
P_TranslatePortalZ(li, out, z);
|
||||||
|
frac += in->frac;
|
||||||
|
depth++;
|
||||||
|
break; // breaks to outer loop
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(li->flags & ML_TWOSIDED) || (li->flags & ML_BLOCKEVERYTHING))
|
||||||
|
return false; // stop tracing, 2D blocking line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Printf("returning %d; vx = %.2f; vy = %.2f\n", (oDepth != depth), FIXED2FLOAT(this->vx), FIXED2FLOAT(this->vy));
|
||||||
|
|
||||||
|
return (oDepth != depth); // if a portal has been found, return false
|
||||||
|
}
|
||||||
|
|
74
src/portal.h
Normal file
74
src/portal.h
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
#ifndef _PORTALS_H_
|
||||||
|
#define _PORTALS_H_
|
||||||
|
|
||||||
|
#include "basictypes.h"
|
||||||
|
#include "v_video.h"
|
||||||
|
#include "r_defs.h"
|
||||||
|
#include "actor.h"
|
||||||
|
#include "p_local.h"
|
||||||
|
#include "m_bbox.h"
|
||||||
|
|
||||||
|
/* portal structure, this is used in r_ code in order to store drawsegs with portals (and mirrors) */
|
||||||
|
struct PortalDrawseg
|
||||||
|
{
|
||||||
|
line_t* src; // source line (the one drawn) this doesn't change over render loops
|
||||||
|
line_t* dst; // destination line (the one that the portal is linked with, equals 'src' for mirrors)
|
||||||
|
|
||||||
|
int x1; // drawseg x1
|
||||||
|
int x2; // drawseg x2
|
||||||
|
|
||||||
|
int len;
|
||||||
|
TArray<short> ceilingclip;
|
||||||
|
TArray<short> floorclip;
|
||||||
|
|
||||||
|
bool mirror; // true if this is a mirror (src should equal dst)
|
||||||
|
};
|
||||||
|
|
||||||
|
extern PortalDrawseg* CurrentPortal;
|
||||||
|
extern int CurrentPortalUniq;
|
||||||
|
extern bool CurrentPortalInSkybox;
|
||||||
|
|
||||||
|
/* code ported from prototype */
|
||||||
|
bool P_ClipLineToPortal(line_t* line, line_t* portal, fixed_t viewx, fixed_t viewy, bool partial = true, bool samebehind = true);
|
||||||
|
bool P_CheckPortal(line_t* line);
|
||||||
|
void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y);
|
||||||
|
void P_TranslatePortalVXVY(line_t* src, line_t* dst, fixed_t& vx, fixed_t& vy);
|
||||||
|
void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle);
|
||||||
|
void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z);
|
||||||
|
void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy);
|
||||||
|
|
||||||
|
// basically, this is a teleporting tracer function,
|
||||||
|
// which can be used by itself (to calculate portal-aware offsets, say, for projectiles)
|
||||||
|
// or to teleport normal tracers (like hitscan, railgun, autoaim tracers)
|
||||||
|
class PortalTracer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PortalTracer(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy);
|
||||||
|
|
||||||
|
// trace to next portal
|
||||||
|
bool TraceStep();
|
||||||
|
// trace to last available portal on the path
|
||||||
|
void TraceAll() { while (TraceStep()) continue; }
|
||||||
|
|
||||||
|
int depth;
|
||||||
|
fixed_t startx;
|
||||||
|
fixed_t starty;
|
||||||
|
fixed_t intx;
|
||||||
|
fixed_t inty;
|
||||||
|
fixed_t intxIn;
|
||||||
|
fixed_t intyIn;
|
||||||
|
fixed_t endx;
|
||||||
|
fixed_t endy;
|
||||||
|
angle_t angle;
|
||||||
|
fixed_t z;
|
||||||
|
fixed_t frac;
|
||||||
|
line_t* in;
|
||||||
|
line_t* out;
|
||||||
|
fixed_t vx;
|
||||||
|
fixed_t vy;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* new code */
|
||||||
|
fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y);
|
||||||
|
|
||||||
|
#endif
|
|
@ -56,6 +56,7 @@
|
||||||
#include "r_sky.h"
|
#include "r_sky.h"
|
||||||
#include "po_man.h"
|
#include "po_man.h"
|
||||||
#include "r_data/colormaps.h"
|
#include "r_data/colormaps.h"
|
||||||
|
#include "portal.h"
|
||||||
|
|
||||||
seg_t* curline;
|
seg_t* curline;
|
||||||
side_t* sidedef;
|
side_t* sidedef;
|
||||||
|
@ -98,8 +99,8 @@ static BYTE FakeSide;
|
||||||
|
|
||||||
int WindowLeft, WindowRight;
|
int WindowLeft, WindowRight;
|
||||||
WORD MirrorFlags;
|
WORD MirrorFlags;
|
||||||
seg_t *ActiveWallMirror;
|
TArray<PortalDrawseg> WallPortals;
|
||||||
TArray<size_t> WallMirrors;
|
|
||||||
|
|
||||||
static subsector_t *InSubsector;
|
static subsector_t *InSubsector;
|
||||||
|
|
||||||
|
@ -553,6 +554,11 @@ void R_AddLine (seg_t *line)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reject lines that aren't seen from the portal (if any)
|
||||||
|
// [ZZ] 10.01.2016: lines inside a skybox shouldn't be clipped, although this imposes some limitations on portals in skyboxes.
|
||||||
|
if (!CurrentPortalInSkybox && CurrentPortal && P_ClipLineToPortal(line->linedef, CurrentPortal->dst, viewx, viewy))
|
||||||
|
return;
|
||||||
|
|
||||||
vertex_t *v1, *v2;
|
vertex_t *v1, *v2;
|
||||||
|
|
||||||
v1 = line->linedef->v1;
|
v1 = line->linedef->v1;
|
||||||
|
@ -584,7 +590,7 @@ void R_AddLine (seg_t *line)
|
||||||
rw_havehigh = rw_havelow = false;
|
rw_havehigh = rw_havelow = false;
|
||||||
|
|
||||||
// Single sided line?
|
// Single sided line?
|
||||||
if (backsector == NULL)
|
if (backsector == NULL || (line->linedef->portal && line->sidedef == line->linedef->sidedef[0]))
|
||||||
{
|
{
|
||||||
solid = true;
|
solid = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include "tarray.h"
|
#include "tarray.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include "portal.h"
|
||||||
|
|
||||||
// The 3072 below is just an arbitrary value picked to avoid
|
// The 3072 below is just an arbitrary value picked to avoid
|
||||||
// drawing lines the player is too close to that would overflow
|
// drawing lines the player is too close to that would overflow
|
||||||
|
@ -86,6 +87,7 @@ struct drawseg_t
|
||||||
// backups
|
// backups
|
||||||
ptrdiff_t bkup; // sprtopclip backup, for mid and fake textures
|
ptrdiff_t bkup; // sprtopclip backup, for mid and fake textures
|
||||||
FWallTmapVals tmapvals;
|
FWallTmapVals tmapvals;
|
||||||
|
int CurrentPortalUniq; // [ZZ] to identify the portal that this drawseg is in. used for sprite clipping.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,9 +106,8 @@ extern size_t FirstInterestingDrawseg;
|
||||||
|
|
||||||
extern int WindowLeft, WindowRight;
|
extern int WindowLeft, WindowRight;
|
||||||
extern WORD MirrorFlags;
|
extern WORD MirrorFlags;
|
||||||
extern seg_t* ActiveWallMirror;
|
|
||||||
|
|
||||||
extern TArray<size_t> WallMirrors;
|
extern TArray<PortalDrawseg> WallPortals;
|
||||||
|
|
||||||
typedef void (*drawfunc_t) (int start, int stop);
|
typedef void (*drawfunc_t) (int start, int stop);
|
||||||
|
|
||||||
|
|
|
@ -988,10 +988,14 @@ struct line_t
|
||||||
sector_t *frontsector, *backsector;
|
sector_t *frontsector, *backsector;
|
||||||
int validcount; // if == validcount, already checked
|
int validcount; // if == validcount, already checked
|
||||||
int locknumber; // [Dusk] lock number for special
|
int locknumber; // [Dusk] lock number for special
|
||||||
|
line_t *portal_dst;
|
||||||
|
bool portal;
|
||||||
|
bool portal_mirror;
|
||||||
|
bool portal_passive;
|
||||||
|
|
||||||
bool isLinePortal() const
|
bool isLinePortal() const
|
||||||
{
|
{
|
||||||
return false;
|
return portal;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
222
src/r_main.cpp
222
src/r_main.cpp
|
@ -57,6 +57,7 @@
|
||||||
#include "v_font.h"
|
#include "v_font.h"
|
||||||
#include "r_data/colormaps.h"
|
#include "r_data/colormaps.h"
|
||||||
#include "farchive.h"
|
#include "farchive.h"
|
||||||
|
#include "portal.h"
|
||||||
|
|
||||||
// MACROS ------------------------------------------------------------------
|
// MACROS ------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -608,52 +609,133 @@ void R_SetupFreelook()
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// R_EnterMirror
|
// R_EnterPortal
|
||||||
//
|
//
|
||||||
// [RH] Draw the reflection inside a mirror
|
// [RH] Draw the reflection inside a mirror
|
||||||
|
// [ZZ] Merged with portal code, originally called R_EnterMirror
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
void R_EnterMirror (drawseg_t *ds, int depth)
|
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);
|
||||||
|
|
||||||
|
BYTE* pixels = RenderTarget->GetBuffer();
|
||||||
|
// top edge
|
||||||
|
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-1)
|
||||||
|
{
|
||||||
|
RenderTarget->DrawLine(x, Ytop, x, Ybottom+1, color, 0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int YtopPrev = pds->ceilingclip[p-1];
|
||||||
|
int YbottomPrev = pds->floorclip[p-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 >= 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];
|
||||||
|
|
||||||
|
BYTE *dest = RenderTarget->GetBuffer() + x + Ytop * spacing;
|
||||||
|
|
||||||
|
for (int y = Ytop; y <= Ybottom; y++)
|
||||||
|
{
|
||||||
|
*dest = color;
|
||||||
|
dest += spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r_highlight_portals)
|
||||||
|
R_HighlightPortal(pds);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
angle_t startang = viewangle;
|
angle_t startang = viewangle;
|
||||||
fixed_t startx = viewx;
|
fixed_t startx = viewx;
|
||||||
fixed_t starty = viewy;
|
fixed_t starty = viewy;
|
||||||
|
fixed_t startz = viewz;
|
||||||
|
|
||||||
CurrentMirror++;
|
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
|
else
|
||||||
{ // any mirror--use floats to avoid integer overflow
|
{
|
||||||
vertex_t *v2 = ds->curline->v2;
|
P_TranslatePortalXY(pds->src, pds->dst, viewx, viewy);
|
||||||
|
P_TranslatePortalZ(pds->src, pds->dst, viewz);
|
||||||
float dx = FIXED2FLOAT(v2->x - v1->x);
|
P_TranslatePortalAngle(pds->src, pds->dst, viewangle);
|
||||||
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 (ds->curline->v1->x, ds->curline->v1->y,
|
|
||||||
ds->curline->v2->x, ds->curline->v2->y) - startang;
|
|
||||||
|
|
||||||
viewsin = finesine[viewangle>>ANGLETOFINESHIFT];
|
viewsin = finesine[viewangle>>ANGLETOFINESHIFT];
|
||||||
viewcos = finecosine[viewangle>>ANGLETOFINESHIFT];
|
viewcos = finecosine[viewangle>>ANGLETOFINESHIFT];
|
||||||
|
@ -664,38 +746,73 @@ void R_EnterMirror (drawseg_t *ds, int depth)
|
||||||
R_CopyStackedViewParameters();
|
R_CopyStackedViewParameters();
|
||||||
|
|
||||||
validcount++;
|
validcount++;
|
||||||
ActiveWallMirror = ds->curline;
|
PortalDrawseg* prevpds = CurrentPortal;
|
||||||
|
CurrentPortal = pds;
|
||||||
|
|
||||||
R_ClearPlanes (false);
|
R_ClearPlanes (false);
|
||||||
R_ClearClipSegs (ds->x1, ds->x2);
|
R_ClearClipSegs (pds->x1, pds->x2);
|
||||||
|
|
||||||
memcpy (ceilingclip + ds->x1, openings + ds->sprtopclip, (ds->x2 - ds->x1)*sizeof(*ceilingclip));
|
WindowLeft = pds->x1;
|
||||||
memcpy (floorclip + ds->x1, openings + ds->sprbottomclip, (ds->x2 - ds->x1)*sizeof(*floorclip));
|
WindowRight = pds->x2;
|
||||||
|
|
||||||
WindowLeft = ds->x1;
|
// RF_XFLIP should be removed before calling the root function
|
||||||
WindowRight = ds->x2;
|
int prevmf = MirrorFlags;
|
||||||
MirrorFlags = (depth + 1) & 1;
|
if (pds->mirror)
|
||||||
|
{
|
||||||
|
if (MirrorFlags & RF_XFLIP)
|
||||||
|
MirrorFlags &= ~RF_XFLIP;
|
||||||
|
else MirrorFlags |= RF_XFLIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// some portals have height differences, account for this here
|
||||||
|
R_3D_EnterSkybox(); // push 3D floor height map
|
||||||
|
CurrentPortalInSkybox = false; // first portal in a skybox should set this variable to false for proper clipping in skyboxes.
|
||||||
|
|
||||||
|
// 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_RenderBSPNode (nodes + numnodes - 1);
|
||||||
R_3D_ResetClip(); // reset clips (floor/ceiling)
|
R_3D_ResetClip(); // reset clips (floor/ceiling)
|
||||||
|
|
||||||
|
PlaneCycles.Clock();
|
||||||
R_DrawPlanes ();
|
R_DrawPlanes ();
|
||||||
R_DrawSkyBoxes ();
|
R_DrawSkyBoxes ();
|
||||||
|
PlaneCycles.Unclock();
|
||||||
|
|
||||||
// Allow up to 4 recursions through a mirror
|
fixed_t vzp = viewz;
|
||||||
if (depth < 4)
|
|
||||||
|
int prevuniq = CurrentPortalUniq;
|
||||||
|
// depth check is in another place right now
|
||||||
|
unsigned int portalsAtEnd = WallPortals.Size ();
|
||||||
|
for (; portalsAtStart < portalsAtEnd; portalsAtStart++)
|
||||||
{
|
{
|
||||||
unsigned int mirrorsAtEnd = WallMirrors.Size ();
|
R_EnterPortal (&WallPortals[portalsAtStart], depth + 1);
|
||||||
|
|
||||||
for (; mirrorsAtStart < mirrorsAtEnd; mirrorsAtStart++)
|
|
||||||
{
|
|
||||||
R_EnterMirror (drawsegs + WallMirrors[mirrorsAtStart], depth + 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
int prevuniq2 = CurrentPortalUniq;
|
||||||
|
CurrentPortalUniq = prevuniq;
|
||||||
|
|
||||||
|
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
|
||||||
|
CurrentPortalUniq = prevuniq2;
|
||||||
|
|
||||||
|
// draw a red line around a portal if it's being highlighted
|
||||||
|
if (r_highlight_portals)
|
||||||
|
R_HighlightPortal(pds);
|
||||||
|
|
||||||
|
CurrentPortal = prevpds;
|
||||||
|
MirrorFlags = prevmf;
|
||||||
viewangle = startang;
|
viewangle = startang;
|
||||||
viewx = startx;
|
viewx = startx;
|
||||||
viewy = starty;
|
viewy = starty;
|
||||||
|
viewz = startz;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -779,7 +896,8 @@ void R_RenderActorView (AActor *actor, bool dontmaplines)
|
||||||
WindowLeft = 0;
|
WindowLeft = 0;
|
||||||
WindowRight = viewwidth;
|
WindowRight = viewwidth;
|
||||||
MirrorFlags = 0;
|
MirrorFlags = 0;
|
||||||
ActiveWallMirror = NULL;
|
CurrentPortal = NULL;
|
||||||
|
CurrentPortalUniq = 0;
|
||||||
|
|
||||||
r_dontmaplines = dontmaplines;
|
r_dontmaplines = dontmaplines;
|
||||||
|
|
||||||
|
@ -813,12 +931,16 @@ void R_RenderActorView (AActor *actor, bool dontmaplines)
|
||||||
PlaneCycles.Unclock();
|
PlaneCycles.Unclock();
|
||||||
|
|
||||||
// [RH] Walk through mirrors
|
// [RH] Walk through mirrors
|
||||||
size_t lastmirror = WallMirrors.Size ();
|
// [ZZ] Merged with portals
|
||||||
for (unsigned int i = 0; i < lastmirror; i++)
|
size_t lastportal = WallPortals.Size();
|
||||||
|
for (unsigned int i = 0; i < lastportal; i++)
|
||||||
{
|
{
|
||||||
R_EnterMirror (drawsegs + WallMirrors[i], 0);
|
R_EnterPortal(&WallPortals[i], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CurrentPortal = NULL;
|
||||||
|
CurrentPortalUniq = 0;
|
||||||
|
|
||||||
NetUpdate ();
|
NetUpdate ();
|
||||||
|
|
||||||
MaskedCycles.Clock();
|
MaskedCycles.Clock();
|
||||||
|
@ -827,7 +949,7 @@ void R_RenderActorView (AActor *actor, bool dontmaplines)
|
||||||
|
|
||||||
NetUpdate ();
|
NetUpdate ();
|
||||||
}
|
}
|
||||||
WallMirrors.Clear ();
|
WallPortals.Clear ();
|
||||||
interpolator.RestoreInterpolations ();
|
interpolator.RestoreInterpolations ();
|
||||||
R_SetupBuffer ();
|
R_SetupBuffer ();
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@
|
||||||
#include "r_3dfloors.h"
|
#include "r_3dfloors.h"
|
||||||
#include "v_palette.h"
|
#include "v_palette.h"
|
||||||
#include "r_data/colormaps.h"
|
#include "r_data/colormaps.h"
|
||||||
|
#include "portal.h"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(disable:4244)
|
#pragma warning(disable:4244)
|
||||||
|
@ -686,9 +687,12 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl
|
||||||
yscale == check->yscale &&
|
yscale == check->yscale &&
|
||||||
angle == check->angle &&
|
angle == check->angle &&
|
||||||
sky == check->sky &&
|
sky == check->sky &&
|
||||||
CurrentMirror == check->CurrentMirror &&
|
CurrentPortalUniq == check->CurrentPortalUniq &&
|
||||||
MirrorFlags == check->MirrorFlags &&
|
MirrorFlags == check->MirrorFlags &&
|
||||||
CurrentSkybox == check->CurrentSkybox
|
CurrentSkybox == check->CurrentSkybox &&
|
||||||
|
viewx == check->viewx &&
|
||||||
|
viewy == check->viewy &&
|
||||||
|
viewz == check->viewz
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return check;
|
return check;
|
||||||
|
@ -718,7 +722,7 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl
|
||||||
check->viewangle = stacked_angle;
|
check->viewangle = stacked_angle;
|
||||||
check->Alpha = alpha;
|
check->Alpha = alpha;
|
||||||
check->Additive = additive;
|
check->Additive = additive;
|
||||||
check->CurrentMirror = CurrentMirror;
|
check->CurrentPortalUniq = CurrentPortalUniq;
|
||||||
check->MirrorFlags = MirrorFlags;
|
check->MirrorFlags = MirrorFlags;
|
||||||
check->CurrentSkybox = CurrentSkybox;
|
check->CurrentSkybox = CurrentSkybox;
|
||||||
|
|
||||||
|
@ -807,7 +811,7 @@ visplane_t *R_CheckPlane (visplane_t *pl, int start, int stop)
|
||||||
new_pl->sky = pl->sky;
|
new_pl->sky = pl->sky;
|
||||||
new_pl->Alpha = pl->Alpha;
|
new_pl->Alpha = pl->Alpha;
|
||||||
new_pl->Additive = pl->Additive;
|
new_pl->Additive = pl->Additive;
|
||||||
new_pl->CurrentMirror = pl->CurrentMirror;
|
new_pl->CurrentPortalUniq = pl->CurrentPortalUniq;
|
||||||
new_pl->MirrorFlags = pl->MirrorFlags;
|
new_pl->MirrorFlags = pl->MirrorFlags;
|
||||||
new_pl->CurrentSkybox = pl->CurrentSkybox;
|
new_pl->CurrentSkybox = pl->CurrentSkybox;
|
||||||
pl = new_pl;
|
pl = new_pl;
|
||||||
|
@ -1043,7 +1047,7 @@ int R_DrawPlanes ()
|
||||||
for (pl = visplanes[i]; pl; pl = pl->next)
|
for (pl = visplanes[i]; pl; pl = pl->next)
|
||||||
{
|
{
|
||||||
// kg3D - draw only correct planes
|
// kg3D - draw only correct planes
|
||||||
if(pl->CurrentMirror != CurrentMirror || pl->CurrentSkybox != CurrentSkybox)
|
if(pl->CurrentPortalUniq != CurrentPortalUniq || pl->CurrentSkybox != CurrentSkybox)
|
||||||
continue;
|
continue;
|
||||||
// kg3D - draw only real planes now
|
// kg3D - draw only real planes now
|
||||||
if(pl->sky >= 0) {
|
if(pl->sky >= 0) {
|
||||||
|
@ -1063,22 +1067,31 @@ void R_DrawHeightPlanes(fixed_t height)
|
||||||
|
|
||||||
ds_color = 3;
|
ds_color = 3;
|
||||||
|
|
||||||
|
fixed_t oViewX = viewx, oViewY = viewy, oViewZ = viewz;
|
||||||
|
angle_t oViewAngle = viewangle;
|
||||||
|
|
||||||
for (i = 0; i < MAXVISPLANES; i++)
|
for (i = 0; i < MAXVISPLANES; i++)
|
||||||
{
|
{
|
||||||
for (pl = visplanes[i]; pl; pl = pl->next)
|
for (pl = visplanes[i]; pl; pl = pl->next)
|
||||||
{
|
{
|
||||||
// kg3D - draw only correct planes
|
// kg3D - draw only correct planes
|
||||||
if(pl->CurrentSkybox != CurrentSkybox)
|
if(pl->CurrentSkybox != CurrentSkybox || pl->CurrentPortalUniq != CurrentPortalUniq)
|
||||||
continue;
|
continue;
|
||||||
if(pl->sky < 0 && pl->height.Zat0() == height) {
|
if(pl->sky < 0 && pl->height.Zat0() == height) {
|
||||||
viewx = pl->viewx;
|
viewx = pl->viewx;
|
||||||
viewy = pl->viewy;
|
viewy = pl->viewy;
|
||||||
|
viewz = pl->viewz;
|
||||||
viewangle = pl->viewangle;
|
viewangle = pl->viewangle;
|
||||||
MirrorFlags = pl->MirrorFlags;
|
MirrorFlags = pl->MirrorFlags;
|
||||||
R_DrawSinglePlane (pl, pl->sky & 0x7FFFFFFF, pl->Additive, true);
|
R_DrawSinglePlane (pl, pl->sky & 0x7FFFFFFF, pl->Additive, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewx = oViewX;
|
||||||
|
viewy = oViewY;
|
||||||
|
viewz = oViewZ;
|
||||||
|
viewangle = oViewAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1180,6 +1193,7 @@ void R_DrawSkyBoxes ()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
R_3D_EnterSkybox();
|
R_3D_EnterSkybox();
|
||||||
|
CurrentPortalInSkybox = true;
|
||||||
|
|
||||||
int savedextralight = extralight;
|
int savedextralight = extralight;
|
||||||
fixed_t savedx = viewx;
|
fixed_t savedx = viewx;
|
||||||
|
@ -1270,6 +1284,7 @@ void R_DrawSkyBoxes ()
|
||||||
|
|
||||||
// Create a drawseg to clip sprites to the sky plane
|
// Create a drawseg to clip sprites to the sky plane
|
||||||
R_CheckDrawSegs ();
|
R_CheckDrawSegs ();
|
||||||
|
ds_p->CurrentPortalUniq = CurrentPortalUniq;
|
||||||
ds_p->siz1 = INT_MAX;
|
ds_p->siz1 = INT_MAX;
|
||||||
ds_p->siz2 = INT_MAX;
|
ds_p->siz2 = INT_MAX;
|
||||||
ds_p->sz1 = 0;
|
ds_p->sz1 = 0;
|
||||||
|
@ -1281,6 +1296,7 @@ void R_DrawSkyBoxes ()
|
||||||
ds_p->sprtopclip = R_NewOpening (pl->right - pl->left);
|
ds_p->sprtopclip = R_NewOpening (pl->right - pl->left);
|
||||||
ds_p->maskedtexturecol = ds_p->swall = -1;
|
ds_p->maskedtexturecol = ds_p->swall = -1;
|
||||||
ds_p->bFogBoundary = false;
|
ds_p->bFogBoundary = false;
|
||||||
|
ds_p->curline = NULL;
|
||||||
ds_p->fake = 0;
|
ds_p->fake = 0;
|
||||||
memcpy (openings + ds_p->sprbottomclip, floorclip + pl->left, (pl->right - pl->left)*sizeof(short));
|
memcpy (openings + ds_p->sprbottomclip, floorclip + pl->left, (pl->right - pl->left)*sizeof(short));
|
||||||
memcpy (openings + ds_p->sprtopclip, ceilingclip + pl->left, (pl->right - pl->left)*sizeof(short));
|
memcpy (openings + ds_p->sprtopclip, ceilingclip + pl->left, (pl->right - pl->left)*sizeof(short));
|
||||||
|
@ -1354,6 +1370,7 @@ void R_DrawSkyBoxes ()
|
||||||
viewangle = savedangle;
|
viewangle = savedangle;
|
||||||
R_SetViewAngle ();
|
R_SetViewAngle ();
|
||||||
|
|
||||||
|
CurrentPortalInSkybox = false;
|
||||||
R_3D_LeaveSkybox();
|
R_3D_LeaveSkybox();
|
||||||
|
|
||||||
if(fakeActive) return;
|
if(fakeActive) return;
|
||||||
|
|
|
@ -58,7 +58,7 @@ struct visplane_s
|
||||||
|
|
||||||
// kg3D - keep track of mirror and skybox owner
|
// kg3D - keep track of mirror and skybox owner
|
||||||
int CurrentSkybox;
|
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
|
int MirrorFlags; // this is not related to CurrentMirror
|
||||||
|
|
||||||
unsigned short *bottom; // [RH] bottom and top arrays are dynamically
|
unsigned short *bottom; // [RH] bottom and top arrays are dynamically
|
||||||
|
|
144
src/r_segs.cpp
144
src/r_segs.cpp
|
@ -52,6 +52,7 @@
|
||||||
#include "r_3dfloors.h"
|
#include "r_3dfloors.h"
|
||||||
#include "v_palette.h"
|
#include "v_palette.h"
|
||||||
#include "r_data/colormaps.h"
|
#include "r_data/colormaps.h"
|
||||||
|
#include "portal.h"
|
||||||
|
|
||||||
#define WALLYREPEAT 8
|
#define WALLYREPEAT 8
|
||||||
|
|
||||||
|
@ -103,7 +104,7 @@ extern fixed_t rw_frontfz1, rw_frontfz2;
|
||||||
int rw_ceilstat, rw_floorstat;
|
int rw_ceilstat, rw_floorstat;
|
||||||
bool rw_mustmarkfloor, rw_mustmarkceiling;
|
bool rw_mustmarkfloor, rw_mustmarkceiling;
|
||||||
bool rw_prepped;
|
bool rw_prepped;
|
||||||
bool rw_markmirror;
|
bool rw_markportal;
|
||||||
bool rw_havehigh;
|
bool rw_havehigh;
|
||||||
bool rw_havelow;
|
bool rw_havelow;
|
||||||
|
|
||||||
|
@ -1989,7 +1990,7 @@ void R_NewWall (bool needlights)
|
||||||
{
|
{
|
||||||
fixed_t rowoffset, yrepeat;
|
fixed_t rowoffset, yrepeat;
|
||||||
|
|
||||||
rw_markmirror = false;
|
rw_markportal = false;
|
||||||
|
|
||||||
sidedef = curline->sidedef;
|
sidedef = curline->sidedef;
|
||||||
linedef = curline->linedef;
|
linedef = curline->linedef;
|
||||||
|
@ -1999,65 +2000,64 @@ void R_NewWall (bool needlights)
|
||||||
|
|
||||||
midtexture = toptexture = bottomtexture = 0;
|
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
|
// single sided line
|
||||||
// a single sided line is terminal, so it must mark ends
|
// a single sided line is terminal, so it must mark ends
|
||||||
markfloor = markceiling = true;
|
markfloor = markceiling = true;
|
||||||
// [RH] Render mirrors later, but mark them now.
|
// [RH] Horizon lines do not need to be textured
|
||||||
if (linedef->special != Line_Mirror || !r_drawmirrors)
|
if (linedef->special != Line_Horizon)
|
||||||
{
|
{
|
||||||
// [RH] Horizon lines do not need to be textured
|
midtexture = TexMan(sidedef->GetTexture(side_t::mid), true);
|
||||||
if (linedef->special != Line_Horizon)
|
rw_offset_mid = sidedef->GetTextureXOffset(side_t::mid);
|
||||||
{
|
rowoffset = sidedef->GetTextureYOffset(side_t::mid);
|
||||||
midtexture = TexMan(sidedef->GetTexture(side_t::mid), true);
|
rw_midtexturescalex = sidedef->GetTextureXScale(side_t::mid);
|
||||||
rw_offset_mid = sidedef->GetTextureXOffset(side_t::mid);
|
rw_midtexturescaley = sidedef->GetTextureYScale(side_t::mid);
|
||||||
rowoffset = sidedef->GetTextureYOffset(side_t::mid);
|
yrepeat = FixedMul(midtexture->yScale, rw_midtexturescaley);
|
||||||
rw_midtexturescalex = sidedef->GetTextureXScale(side_t::mid);
|
if (yrepeat >= 0)
|
||||||
rw_midtexturescaley = sidedef->GetTextureYScale(side_t::mid);
|
{ // normal orientation
|
||||||
yrepeat = FixedMul(midtexture->yScale, rw_midtexturescaley);
|
if (linedef->flags & ML_DONTPEGBOTTOM)
|
||||||
if (yrepeat >= 0)
|
{ // bottom of texture at bottom
|
||||||
{ // normal orientation
|
rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::floor) - viewz, yrepeat) + (midtexture->GetHeight() << FRACBITS);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // upside down
|
{ // top of texture at top
|
||||||
rowoffset = -rowoffset;
|
rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat);
|
||||||
if (linedef->flags & ML_DONTPEGBOTTOM)
|
if (rowoffset < 0 && midtexture != NULL)
|
||||||
{ // top of texture at bottom
|
{
|
||||||
rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::floor) - viewz, yrepeat);
|
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
|
||||||
else
|
{ // upside down
|
||||||
{
|
rowoffset = -rowoffset;
|
||||||
rw_markmirror = true;
|
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
|
else
|
||||||
|
@ -2380,6 +2380,7 @@ void R_StoreWallRange (int start, int stop)
|
||||||
rw_offset = sidedef->GetTextureXOffset(side_t::mid);
|
rw_offset = sidedef->GetTextureXOffset(side_t::mid);
|
||||||
rw_light = rw_lightleft + rw_lightstep * (start - WallC.sx1);
|
rw_light = rw_lightleft + rw_lightstep * (start - WallC.sx1);
|
||||||
|
|
||||||
|
ds_p->CurrentPortalUniq = CurrentPortalUniq;
|
||||||
ds_p->sx1 = WallC.sx1;
|
ds_p->sx1 = WallC.sx1;
|
||||||
ds_p->sx2 = WallC.sx2;
|
ds_p->sx2 = WallC.sx2;
|
||||||
ds_p->sz1 = WallC.sz1;
|
ds_p->sz1 = WallC.sz1;
|
||||||
|
@ -2403,10 +2404,8 @@ void R_StoreWallRange (int start, int stop)
|
||||||
// killough 1/6/98, 2/1/98: remove limit on openings
|
// 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;
|
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;
|
ds_p->silhouette = SIL_BOTH;
|
||||||
}
|
}
|
||||||
else if (backsector == NULL)
|
else if (backsector == NULL)
|
||||||
|
@ -2617,9 +2616,42 @@ void R_StoreWallRange (int start, int stop)
|
||||||
}
|
}
|
||||||
|
|
||||||
// [RH] Draw any decals bound to the seg
|
// [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.len = pds.x2 - pds.x1;
|
||||||
|
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; 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
ds_p++;
|
ds_p++;
|
||||||
|
|
120
src/r_things.cpp
120
src/r_things.cpp
|
@ -319,6 +319,49 @@ nextpost:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [ZZ]
|
||||||
|
// R_ClipSpriteColumnWithPortals
|
||||||
|
//
|
||||||
|
static inline bool R_ClipSpriteColumnWithPortals (fixed_t x, fixed_t y, vissprite_t* spr)
|
||||||
|
{
|
||||||
|
// [ZZ] 10.01.2016: don't clip sprites from the root of a skybox.
|
||||||
|
if (CurrentPortalInSkybox)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (drawseg_t* seg = ds_p; seg-- > firstdrawseg; ) // copied code from killough below
|
||||||
|
{
|
||||||
|
// ignore segs from other portals
|
||||||
|
if (seg->CurrentPortalUniq != CurrentPortalUniq)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// I don't know what makes this happen (some old top-down portal code or possibly skybox code? something adds null lines...)
|
||||||
|
// crashes at the first frame of the first map of Action2.wad
|
||||||
|
if (!seg->curline) 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
|
// R_DrawVisSprite
|
||||||
// mfloorclip and mceilingclip should also be set.
|
// mfloorclip and mceilingclip should also be set.
|
||||||
|
@ -332,6 +375,7 @@ void R_DrawVisSprite (vissprite_t *vis)
|
||||||
int x2, stop4;
|
int x2, stop4;
|
||||||
fixed_t xiscale;
|
fixed_t xiscale;
|
||||||
ESPSResult mode;
|
ESPSResult mode;
|
||||||
|
bool ispsprite = (!vis->sector && !vis->gx && !vis->gy && !vis->gz);
|
||||||
|
|
||||||
if (vis->xscale == 0 || vis->yscale == 0)
|
if (vis->xscale == 0 || vis->yscale == 0)
|
||||||
{ // scaled to 0; can't see
|
{ // scaled to 0; can't see
|
||||||
|
@ -393,7 +437,8 @@ void R_DrawVisSprite (vissprite_t *vis)
|
||||||
while ((dc_x < stop4) && (dc_x & 3))
|
while ((dc_x < stop4) && (dc_x & 3))
|
||||||
{
|
{
|
||||||
pixels = tex->GetColumn (frac >> FRACBITS, &spans);
|
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++;
|
dc_x++;
|
||||||
frac += xiscale;
|
frac += xiscale;
|
||||||
}
|
}
|
||||||
|
@ -404,7 +449,8 @@ void R_DrawVisSprite (vissprite_t *vis)
|
||||||
for (int zz = 4; zz; --zz)
|
for (int zz = 4; zz; --zz)
|
||||||
{
|
{
|
||||||
pixels = tex->GetColumn (frac >> FRACBITS, &spans);
|
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++;
|
dc_x++;
|
||||||
frac += xiscale;
|
frac += xiscale;
|
||||||
}
|
}
|
||||||
|
@ -414,7 +460,8 @@ void R_DrawVisSprite (vissprite_t *vis)
|
||||||
while (dc_x < x2)
|
while (dc_x < x2)
|
||||||
{
|
{
|
||||||
pixels = tex->GetColumn (frac >> FRACBITS, &spans);
|
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++;
|
dc_x++;
|
||||||
frac += xiscale;
|
frac += xiscale;
|
||||||
}
|
}
|
||||||
|
@ -524,7 +571,8 @@ void R_DrawWallSprite(vissprite_t *spr)
|
||||||
{ // calculate lighting
|
{ // calculate lighting
|
||||||
dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, shade) << COLORMAPSHIFT);
|
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++;
|
dc_x++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -537,7 +585,8 @@ void R_DrawWallSprite(vissprite_t *spr)
|
||||||
rt_initcols();
|
rt_initcols();
|
||||||
for (int zz = 4; zz; --zz)
|
for (int zz = 4; zz; --zz)
|
||||||
{
|
{
|
||||||
R_WallSpriteColumn(R_DrawMaskedColumnHoriz);
|
if (!R_ClipSpriteColumnWithPortals(spr->gx, spr->gy, spr))
|
||||||
|
R_WallSpriteColumn(R_DrawMaskedColumnHoriz);
|
||||||
dc_x++;
|
dc_x++;
|
||||||
}
|
}
|
||||||
rt_draw4cols(dc_x - 4);
|
rt_draw4cols(dc_x - 4);
|
||||||
|
@ -549,7 +598,8 @@ void R_DrawWallSprite(vissprite_t *spr)
|
||||||
{ // calculate lighting
|
{ // calculate lighting
|
||||||
dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, shade) << COLORMAPSHIFT);
|
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++;
|
dc_x++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -687,6 +737,11 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [ZZ] Or less definitely not visible (hue)
|
||||||
|
// [ZZ] 10.01.2016: don't try to clip stuff inside a skybox against the current portal.
|
||||||
|
if (!CurrentPortalInSkybox && CurrentPortal && !!P_PointOnLineSide(thing->X(), thing->Y(), CurrentPortal->dst))
|
||||||
|
return;
|
||||||
|
|
||||||
// [RH] Interpolate the sprite's position to make it look smooth
|
// [RH] Interpolate the sprite's position to make it look smooth
|
||||||
fixedvec3 pos = thing->InterpolatedPosition(r_TicFrac);
|
fixedvec3 pos = thing->InterpolatedPosition(r_TicFrac);
|
||||||
fx = pos.x;
|
fx = pos.x;
|
||||||
|
@ -912,6 +967,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
|
||||||
// store information in a vissprite
|
// store information in a vissprite
|
||||||
vis = R_NewVisSprite();
|
vis = R_NewVisSprite();
|
||||||
|
|
||||||
|
vis->CurrentPortalUniq = CurrentPortalUniq;
|
||||||
vis->xscale = xscale;
|
vis->xscale = xscale;
|
||||||
vis->yscale = Scale(InvZtoScale, yscale, tz << 4);
|
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
|
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
|
||||||
|
@ -939,6 +995,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
|
||||||
{
|
{
|
||||||
vis = R_NewVisSprite();
|
vis = R_NewVisSprite();
|
||||||
|
|
||||||
|
vis->CurrentPortalUniq = CurrentPortalUniq;
|
||||||
vis->xscale = xscale;
|
vis->xscale = xscale;
|
||||||
vis->yscale = yscale;
|
vis->yscale = yscale;
|
||||||
vis->x1 = WindowLeft;
|
vis->x1 = WindowLeft;
|
||||||
|
@ -1101,6 +1158,7 @@ static void R_ProjectWallSprite(AActor *thing, fixed_t fx, fixed_t fy, fixed_t f
|
||||||
gzb = fz + yscale * scaled_bo;
|
gzb = fz + yscale * scaled_bo;
|
||||||
|
|
||||||
vis = R_NewVisSprite();
|
vis = R_NewVisSprite();
|
||||||
|
vis->CurrentPortalUniq = CurrentPortalUniq;
|
||||||
vis->x1 = wallc.sx1 < WindowLeft ? WindowLeft : wallc.sx1;
|
vis->x1 = wallc.sx1 < WindowLeft ? WindowLeft : wallc.sx1;
|
||||||
vis->x2 = wallc.sx2 >= WindowRight ? WindowRight : wallc.sx2;
|
vis->x2 = wallc.sx2 >= WindowRight ? WindowRight : wallc.sx2;
|
||||||
vis->yscale = yscale;
|
vis->yscale = yscale;
|
||||||
|
@ -1801,7 +1859,6 @@ void R_SortVisSprites (bool (*compare)(vissprite_t *, vissprite_t *), size_t fir
|
||||||
std::stable_sort(&spritesorter[0], &spritesorter[vsprcount], compare);
|
std::stable_sort(&spritesorter[0], &spritesorter[vsprcount], compare);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// R_DrawSprite
|
// R_DrawSprite
|
||||||
//
|
//
|
||||||
|
@ -2096,8 +2153,13 @@ void R_DrawSprite (vissprite_t *spr)
|
||||||
|
|
||||||
for (ds = ds_p; ds-- > firstdrawseg; ) // new -- killough
|
for (ds = ds_p; ds-- > firstdrawseg; ) // new -- killough
|
||||||
{
|
{
|
||||||
|
// [ZZ] portal handling here
|
||||||
|
//if (ds->CurrentPortalUniq != spr->CurrentPortalUniq)
|
||||||
|
// continue;
|
||||||
|
// [ZZ] WARNING: uncommenting the two above lines, totally breaks sprite clipping
|
||||||
|
|
||||||
// kg3D - no clipping on fake segs
|
// kg3D - no clipping on fake segs
|
||||||
if(ds->fake) continue;
|
if (ds->fake) continue;
|
||||||
// determine if the drawseg obscures the sprite
|
// determine if the drawseg obscures the sprite
|
||||||
if (ds->x1 >= x2 || ds->x2 <= x1 ||
|
if (ds->x1 >= x2 || ds->x2 <= x1 ||
|
||||||
(!(ds->silhouette & SIL_BOTH) && ds->maskedtexturecol == -1 &&
|
(!(ds->silhouette & SIL_BOTH) && ds->maskedtexturecol == -1 &&
|
||||||
|
@ -2128,7 +2190,8 @@ void R_DrawSprite (vissprite_t *spr)
|
||||||
ds->curline->v1->x - spr->gx, ds->curline->v2->y - ds->curline->v1->y) <= 0))
|
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
|
// 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);
|
R_RenderMaskedSegRange (ds, r1, r2);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2232,6 +2295,8 @@ void R_DrawMaskedSingle (bool renew)
|
||||||
|
|
||||||
for (i = vsprcount; i > 0; i--)
|
for (i = vsprcount; i > 0; i--)
|
||||||
{
|
{
|
||||||
|
if (spritesorter[i-1]->CurrentPortalUniq != CurrentPortalUniq)
|
||||||
|
continue; // probably another time
|
||||||
R_DrawSprite (spritesorter[i-1]);
|
R_DrawSprite (spritesorter[i-1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2249,6 +2314,9 @@ void R_DrawMaskedSingle (bool renew)
|
||||||
}
|
}
|
||||||
for (ds = ds_p; ds-- > firstdrawseg; ) // new -- killough
|
for (ds = ds_p; ds-- > firstdrawseg; ) // new -- killough
|
||||||
{
|
{
|
||||||
|
// [ZZ] the same as above
|
||||||
|
if (ds->CurrentPortalUniq != CurrentPortalUniq)
|
||||||
|
continue;
|
||||||
// kg3D - no fake segs
|
// kg3D - no fake segs
|
||||||
if (ds->fake) continue;
|
if (ds->fake) continue;
|
||||||
if (ds->maskedtexturecol != -1 || ds->bFogBoundary)
|
if (ds->maskedtexturecol != -1 || ds->bFogBoundary)
|
||||||
|
@ -2328,6 +2396,10 @@ void R_ProjectParticle (particle_t *particle, const sector_t *sector, int shade,
|
||||||
sector_t* heightsec = NULL;
|
sector_t* heightsec = NULL;
|
||||||
BYTE* map;
|
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
|
// transform the origin point
|
||||||
tr_x = particle->x - viewx;
|
tr_x = particle->x - viewx;
|
||||||
tr_y = particle->y - viewy;
|
tr_y = particle->y - viewy;
|
||||||
|
@ -2431,6 +2503,7 @@ void R_ProjectParticle (particle_t *particle, const sector_t *sector, int shade,
|
||||||
|
|
||||||
// store information in a vissprite
|
// store information in a vissprite
|
||||||
vis = R_NewVisSprite ();
|
vis = R_NewVisSprite ();
|
||||||
|
vis->CurrentPortalUniq = CurrentPortalUniq;
|
||||||
vis->heightsec = heightsec;
|
vis->heightsec = heightsec;
|
||||||
vis->xscale = xscale;
|
vis->xscale = xscale;
|
||||||
// vis->yscale = FixedMul (xscale, InvZtoScale);
|
// vis->yscale = FixedMul (xscale, InvZtoScale);
|
||||||
|
@ -2491,7 +2564,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)
|
if (Scale (ds->siz2 - ds->siz1, (x2 + x1)/2 - ds->sx1, ds->sx2 - ds->sx1) + ds->siz1 < vis->idepth)
|
||||||
{
|
{
|
||||||
R_RenderMaskedSegRange (ds, MAX<int>(ds->x1, x1), MIN<int>(ds->x2, x2));
|
// [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<int>(ds->x1, x1), MIN<int>(ds->x2, x2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2522,6 +2597,8 @@ void R_DrawParticle (vissprite_t *vis)
|
||||||
fg = fg2rgb[color];
|
fg = fg2rgb[color];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
spacing = RenderTarget->GetPitch() - countbase;
|
spacing = RenderTarget->GetPitch() - countbase;
|
||||||
dest = ylookup[yl] + x1 + dc_destorg;
|
dest = ylookup[yl] + x1 + dc_destorg;
|
||||||
|
|
||||||
|
@ -2535,7 +2612,28 @@ void R_DrawParticle (vissprite_t *vis)
|
||||||
*dest++ = RGB32k.All[bg & (bg>>15)];
|
*dest++ = RGB32k.All[bg & (bg>>15)];
|
||||||
} while (--count);
|
} while (--count);
|
||||||
dest += spacing;
|
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.All[bg & (bg>>15)];
|
||||||
|
dest += spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fixed_t baseyaspectmul;
|
extern fixed_t baseyaspectmul;
|
||||||
|
|
|
@ -80,6 +80,7 @@ struct vissprite_t
|
||||||
short renderflags;
|
short renderflags;
|
||||||
DWORD Translation; // [RH] for color translation
|
DWORD Translation; // [RH] for color translation
|
||||||
visstyle_t Style;
|
visstyle_t Style;
|
||||||
|
int CurrentPortalUniq; // [ZZ] to identify the portal that this thing is in. used for clipping.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct particle_t;
|
struct particle_t;
|
||||||
|
|
12
zdoom.vcproj
12
zdoom.vcproj
|
@ -6944,6 +6944,18 @@
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="Portals"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath=".\src\portal.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\src\portal.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
</Files>
|
</Files>
|
||||||
<Globals>
|
<Globals>
|
||||||
</Globals>
|
</Globals>
|
||||||
|
|
Loading…
Reference in a new issue