mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-12-03 08:52:59 +00:00
Line portal rendering
This commit is contained in:
parent
eaa15f2b74
commit
cc3ac9ea05
4 changed files with 228 additions and 10 deletions
|
@ -23,6 +23,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "templates.h"
|
#include "templates.h"
|
||||||
#include "doomdef.h"
|
#include "doomdef.h"
|
||||||
|
#include "p_maputl.h"
|
||||||
#include "sbar.h"
|
#include "sbar.h"
|
||||||
#include "r_data/r_translate.h"
|
#include "r_data/r_translate.h"
|
||||||
#include "r_poly_portal.h"
|
#include "r_poly_portal.h"
|
||||||
|
@ -32,6 +33,8 @@
|
||||||
CVAR(Bool, r_debug_cull, 0, 0)
|
CVAR(Bool, r_debug_cull, 0, 0)
|
||||||
EXTERN_CVAR(Int, r_portal_recursions)
|
EXTERN_CVAR(Int, r_portal_recursions)
|
||||||
|
|
||||||
|
extern bool r_showviewer;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
RenderPolyPortal::RenderPolyPortal()
|
RenderPolyPortal::RenderPolyPortal()
|
||||||
|
@ -185,7 +188,7 @@ void RenderPolyPortal::RenderLine(subsector_t *sub, seg_t *line, sector_t *front
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render wall, and update culling info if its an occlusion blocker
|
// Render wall, and update culling info if its an occlusion blocker
|
||||||
if (RenderPolyWall::RenderLine(WorldToClip, line, frontsector, subsectorDepth, StencilValue, SubsectorTranslucentWalls))
|
if (RenderPolyWall::RenderLine(WorldToClip, line, frontsector, subsectorDepth, StencilValue, SubsectorTranslucentWalls, LinePortals))
|
||||||
{
|
{
|
||||||
if (hasSegmentRange)
|
if (hasSegmentRange)
|
||||||
Cull.MarkSegmentCulled(sx1, sx2);
|
Cull.MarkSegmentCulled(sx1, sx2);
|
||||||
|
@ -362,19 +365,144 @@ void PolyDrawSectorPortal::RestoreGlobals()
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
PolyDrawLinePortal::PolyDrawLinePortal(line_t *src, line_t *dest, bool mirror) : Src(src), Dest(dest)
|
PolyDrawLinePortal::PolyDrawLinePortal(FLinePortal *portal) : Portal(portal)
|
||||||
|
{
|
||||||
|
StencilValue = RenderPolyScene::Instance()->GetNextStencilValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
PolyDrawLinePortal::PolyDrawLinePortal(line_t *mirror) : Mirror(mirror)
|
||||||
{
|
{
|
||||||
// To do: do what R_EnterPortal and PortalDrawseg does
|
|
||||||
|
|
||||||
StencilValue = RenderPolyScene::Instance()->GetNextStencilValue();
|
StencilValue = RenderPolyScene::Instance()->GetNextStencilValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolyDrawLinePortal::Render(int portalDepth)
|
void PolyDrawLinePortal::Render(int portalDepth)
|
||||||
{
|
{
|
||||||
|
SaveGlobals();
|
||||||
|
|
||||||
|
// To do: get this information from RenderPolyScene instead of duplicating the code..
|
||||||
|
double radPitch = ViewPitch.Normalized180().Radians();
|
||||||
|
double angx = cos(radPitch);
|
||||||
|
double angy = sin(radPitch) * glset.pixelstretch;
|
||||||
|
double alen = sqrt(angx*angx + angy*angy);
|
||||||
|
float adjustedPitch = (float)asin(angy / alen);
|
||||||
|
float adjustedViewAngle = (float)(ViewAngle - 90).Radians();
|
||||||
|
float ratio = WidescreenRatio;
|
||||||
|
float fovratio = (WidescreenRatio >= 1.3f) ? 1.333333f : ratio;
|
||||||
|
float fovy = (float)(2 * DAngle::ToDegrees(atan(tan(FieldOfView.Radians() / 2) / fovratio)).Degrees);
|
||||||
|
TriMatrix worldToView =
|
||||||
|
TriMatrix::rotate(adjustedPitch, 1.0f, 0.0f, 0.0f) *
|
||||||
|
TriMatrix::rotate(adjustedViewAngle, 0.0f, -1.0f, 0.0f) *
|
||||||
|
TriMatrix::scale(1.0f, glset.pixelstretch, 1.0f) *
|
||||||
|
TriMatrix::swapYZ() *
|
||||||
|
TriMatrix::translate((float)-ViewPos.X, (float)-ViewPos.Y, (float)-ViewPos.Z);
|
||||||
|
TriMatrix worldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView;
|
||||||
|
|
||||||
|
RenderPortal.SetViewpoint(worldToClip, StencilValue);
|
||||||
RenderPortal.Render(portalDepth);
|
RenderPortal.Render(portalDepth);
|
||||||
|
|
||||||
|
RestoreGlobals();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolyDrawLinePortal::RenderTranslucent(int portalDepth)
|
void PolyDrawLinePortal::RenderTranslucent(int portalDepth)
|
||||||
{
|
{
|
||||||
|
SaveGlobals();
|
||||||
RenderPortal.RenderTranslucent(portalDepth);
|
RenderPortal.RenderTranslucent(portalDepth);
|
||||||
|
RestoreGlobals();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PolyDrawLinePortal::SaveGlobals()
|
||||||
|
{
|
||||||
|
savedextralight = extralight;
|
||||||
|
savedpos = ViewPos;
|
||||||
|
savedangle = ViewAngle;
|
||||||
|
savedcamera = camera;
|
||||||
|
savedsector = viewsector;
|
||||||
|
savedvisibility = camera ? camera->renderflags & RF_INVISIBLE : ActorRenderFlags::FromInt(0);
|
||||||
|
savedViewPath[0] = ViewPath[0];
|
||||||
|
savedViewPath[1] = ViewPath[1];
|
||||||
|
|
||||||
|
if (Mirror)
|
||||||
|
{
|
||||||
|
DAngle startang = ViewAngle;
|
||||||
|
DVector3 startpos = ViewPos;
|
||||||
|
|
||||||
|
vertex_t *v1 = Mirror->v1;
|
||||||
|
|
||||||
|
// Reflect the current view behind the mirror.
|
||||||
|
if (Mirror->Delta().X == 0)
|
||||||
|
{ // vertical mirror
|
||||||
|
ViewPos.X = v1->fX() - startpos.X + v1->fX();
|
||||||
|
}
|
||||||
|
else if (Mirror->Delta().Y == 0)
|
||||||
|
{ // horizontal mirror
|
||||||
|
ViewPos.Y = v1->fY() - startpos.Y + v1->fY();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // any mirror
|
||||||
|
vertex_t *v2 = Mirror->v2;
|
||||||
|
|
||||||
|
double dx = v2->fX() - v1->fX();
|
||||||
|
double dy = v2->fY() - v1->fY();
|
||||||
|
double x1 = v1->fX();
|
||||||
|
double y1 = v1->fY();
|
||||||
|
double x = startpos.X;
|
||||||
|
double y = startpos.Y;
|
||||||
|
|
||||||
|
// the above two cases catch len == 0
|
||||||
|
double r = ((x - x1)*dx + (y - y1)*dy) / (dx*dx + dy*dy);
|
||||||
|
|
||||||
|
ViewPos.X = (x1 + r * dx) * 2 - x;
|
||||||
|
ViewPos.Y = (y1 + r * dy) * 2 - y;
|
||||||
|
}
|
||||||
|
ViewAngle = Mirror->Delta().Angle() * 2 - startang;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto src = Portal->mOrigin;
|
||||||
|
auto dst = Portal->mDestination;
|
||||||
|
|
||||||
|
P_TranslatePortalXY(src, ViewPos.X, ViewPos.Y);
|
||||||
|
P_TranslatePortalZ(src, ViewPos.Z);
|
||||||
|
P_TranslatePortalAngle(src, ViewAngle);
|
||||||
|
P_TranslatePortalXY(src, ViewPath[0].X, ViewPath[0].Y);
|
||||||
|
P_TranslatePortalXY(src, ViewPath[1].X, ViewPath[1].Y);
|
||||||
|
|
||||||
|
if (!r_showviewer && camera && P_PointOnLineSidePrecise(ViewPath[0], dst) != P_PointOnLineSidePrecise(ViewPath[1], dst))
|
||||||
|
{
|
||||||
|
double distp = (ViewPath[0] - ViewPath[1]).Length();
|
||||||
|
if (distp > EQUAL_EPSILON)
|
||||||
|
{
|
||||||
|
double dist1 = (ViewPos - ViewPath[0]).Length();
|
||||||
|
double dist2 = (ViewPos - ViewPath[1]).Length();
|
||||||
|
|
||||||
|
if (dist1 + dist2 < distp + 1)
|
||||||
|
{
|
||||||
|
camera->renderflags |= RF_INVISIBLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if (Portal->mirror)
|
||||||
|
{
|
||||||
|
if (MirrorFlags & RF_XFLIP) MirrorFlags &= ~RF_XFLIP;
|
||||||
|
else MirrorFlags |= RF_XFLIP;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
camera = nullptr;
|
||||||
|
//viewsector = Portal->mDestination;
|
||||||
|
R_SetViewAngle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PolyDrawLinePortal::RestoreGlobals()
|
||||||
|
{
|
||||||
|
if (!savedvisibility && camera) camera->renderflags &= ~RF_INVISIBLE;
|
||||||
|
camera = savedcamera;
|
||||||
|
viewsector = savedsector;
|
||||||
|
ViewPos = savedpos;
|
||||||
|
extralight = savedextralight;
|
||||||
|
ViewAngle = savedangle;
|
||||||
|
ViewPath[0] = savedViewPath[0];
|
||||||
|
ViewPath[1] = savedViewPath[1];
|
||||||
|
R_SetViewAngle();
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,7 +127,7 @@ public:
|
||||||
void Render(int portalDepth);
|
void Render(int portalDepth);
|
||||||
void RenderTranslucent(int portalDepth);
|
void RenderTranslucent(int portalDepth);
|
||||||
|
|
||||||
FSectorPortal *Portal;
|
FSectorPortal *Portal = nullptr;
|
||||||
uint32_t StencilValue = 0;
|
uint32_t StencilValue = 0;
|
||||||
std::vector<PolyPortalVertexRange> Shape;
|
std::vector<PolyPortalVertexRange> Shape;
|
||||||
|
|
||||||
|
@ -149,16 +149,28 @@ private:
|
||||||
class PolyDrawLinePortal
|
class PolyDrawLinePortal
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PolyDrawLinePortal(line_t *src, line_t *dest, bool mirror);
|
PolyDrawLinePortal(FLinePortal *portal);
|
||||||
|
PolyDrawLinePortal(line_t *mirror);
|
||||||
|
|
||||||
void Render(int portalDepth);
|
void Render(int portalDepth);
|
||||||
void RenderTranslucent(int portalDepth);
|
void RenderTranslucent(int portalDepth);
|
||||||
|
|
||||||
|
FLinePortal *Portal = nullptr;
|
||||||
|
line_t *Mirror = nullptr;
|
||||||
uint32_t StencilValue = 0;
|
uint32_t StencilValue = 0;
|
||||||
std::vector<PolyPortalVertexRange> Shape;
|
std::vector<PolyPortalVertexRange> Shape;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
line_t *Src;
|
void SaveGlobals();
|
||||||
line_t *Dest;
|
void RestoreGlobals();
|
||||||
|
|
||||||
RenderPolyPortal RenderPortal;
|
RenderPolyPortal RenderPortal;
|
||||||
|
|
||||||
|
int savedextralight;
|
||||||
|
DVector3 savedpos;
|
||||||
|
DAngle savedangle;
|
||||||
|
AActor *savedcamera;
|
||||||
|
sector_t *savedsector;
|
||||||
|
ActorRenderFlags savedvisibility;
|
||||||
|
DVector3 savedViewPath[2];
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,6 +23,9 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "templates.h"
|
#include "templates.h"
|
||||||
#include "doomdef.h"
|
#include "doomdef.h"
|
||||||
|
#include "doomstat.h"
|
||||||
|
#include "doomdata.h"
|
||||||
|
#include "p_lnspec.h"
|
||||||
#include "sbar.h"
|
#include "sbar.h"
|
||||||
#include "r_data/r_translate.h"
|
#include "r_data/r_translate.h"
|
||||||
#include "r_poly_wall.h"
|
#include "r_poly_wall.h"
|
||||||
|
@ -30,8 +33,82 @@
|
||||||
#include "r_poly.h"
|
#include "r_poly.h"
|
||||||
#include "r_sky.h" // for skyflatnum
|
#include "r_sky.h" // for skyflatnum
|
||||||
|
|
||||||
bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject> &translucentWallsOutput)
|
EXTERN_CVAR(Bool, r_drawmirrors)
|
||||||
|
|
||||||
|
bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals)
|
||||||
{
|
{
|
||||||
|
PolyDrawLinePortal *polyportal = nullptr;
|
||||||
|
if (line->backsector == nullptr && line->sidedef == line->linedef->sidedef[0] && (line->linedef->special == Line_Mirror && r_drawmirrors))
|
||||||
|
{
|
||||||
|
linePortals.push_back(std::make_unique<PolyDrawLinePortal>(line->linedef));
|
||||||
|
polyportal = linePortals.back().get();
|
||||||
|
}
|
||||||
|
else if (line->linedef && line->linedef->isVisualPortal())
|
||||||
|
{
|
||||||
|
FLinePortal *portal = line->linedef->getPortal();
|
||||||
|
for (auto &p : linePortals)
|
||||||
|
{
|
||||||
|
if (p->Portal == portal) // To do: what other criterias do we need to check for?
|
||||||
|
{
|
||||||
|
polyportal = p.get();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!polyportal)
|
||||||
|
{
|
||||||
|
linePortals.push_back(std::make_unique<PolyDrawLinePortal>(portal));
|
||||||
|
polyportal = linePortals.back().get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (polyportal)
|
||||||
|
{
|
||||||
|
double ceil1 = frontsector->ceilingplane.ZatPoint(line->v1);
|
||||||
|
double floor1 = frontsector->floorplane.ZatPoint(line->v1);
|
||||||
|
double ceil2 = frontsector->ceilingplane.ZatPoint(line->v2);
|
||||||
|
double floor2 = frontsector->floorplane.ZatPoint(line->v2);
|
||||||
|
DVector2 v1 = line->v1->fPos();
|
||||||
|
DVector2 v2 = line->v2->fPos();
|
||||||
|
|
||||||
|
TriVertex *vertices = PolyVertexBuffer::GetVertices(4);
|
||||||
|
if (!vertices)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
vertices[0].x = (float)v1.X;
|
||||||
|
vertices[0].y = (float)v1.Y;
|
||||||
|
vertices[0].z = (float)ceil1;
|
||||||
|
vertices[0].w = 1.0f;
|
||||||
|
|
||||||
|
vertices[1].x = (float)v2.X;
|
||||||
|
vertices[1].y = (float)v2.Y;
|
||||||
|
vertices[1].z = (float)ceil2;
|
||||||
|
vertices[1].w = 1.0f;
|
||||||
|
|
||||||
|
vertices[2].x = (float)v2.X;
|
||||||
|
vertices[2].y = (float)v2.Y;
|
||||||
|
vertices[2].z = (float)floor2;
|
||||||
|
vertices[2].w = 1.0f;
|
||||||
|
|
||||||
|
vertices[3].x = (float)v1.X;
|
||||||
|
vertices[3].y = (float)v1.Y;
|
||||||
|
vertices[3].z = (float)floor1;
|
||||||
|
vertices[3].w = 1.0f;
|
||||||
|
|
||||||
|
PolyDrawArgs args;
|
||||||
|
args.uniforms.flags = 0;
|
||||||
|
args.objectToClip = &worldToClip;
|
||||||
|
args.vinput = vertices;
|
||||||
|
args.vcount = 4;
|
||||||
|
args.mode = TriangleDrawMode::Fan;
|
||||||
|
args.ccw = true;
|
||||||
|
args.stenciltestvalue = stencilValue;
|
||||||
|
args.stencilwritevalue = polyportal->StencilValue;
|
||||||
|
PolyTriangleDrawer::draw(args, TriDrawVariant::Stencil, TriBlendMode::Copy);
|
||||||
|
|
||||||
|
polyportal->Shape.push_back({ vertices, 4, true, subsectorDepth });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
RenderPolyWall wall;
|
RenderPolyWall wall;
|
||||||
wall.LineSeg = line;
|
wall.LineSeg = line;
|
||||||
wall.Line = line->linedef;
|
wall.Line = line->linedef;
|
||||||
|
|
|
@ -25,11 +25,12 @@
|
||||||
#include "r_poly_triangle.h"
|
#include "r_poly_triangle.h"
|
||||||
|
|
||||||
class PolyTranslucentObject;
|
class PolyTranslucentObject;
|
||||||
|
class PolyDrawLinePortal;
|
||||||
|
|
||||||
class RenderPolyWall
|
class RenderPolyWall
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool RenderLine(const TriMatrix &worldToClip, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject> &translucentWallsOutput);
|
static bool RenderLine(const TriMatrix &worldToClip, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals);
|
||||||
static void Render3DFloorLine(const TriMatrix &worldToClip, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject> &translucentWallsOutput);
|
static void Render3DFloorLine(const TriMatrix &worldToClip, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject> &translucentWallsOutput);
|
||||||
|
|
||||||
void SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2);
|
void SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2);
|
||||||
|
|
Loading…
Reference in a new issue