Merge remote-tracking branch 'gzdoom/modern' into hw_postprocess

This commit is contained in:
Magnus Norddahl 2018-06-24 17:57:02 +02:00
commit 32d837cdf1
164 changed files with 23408 additions and 12966 deletions

View file

@ -89,7 +89,7 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip)
if (portalclip)
{
int clipres = mClipPortal->ClipSeg(seg);
int clipres = mClipPortal->ClipSeg(seg, Viewpoint.Pos);
if (clipres == PClip_InFront) return;
}
@ -353,6 +353,7 @@ void HWDrawInfo::RenderThings(subsector_t * sub, sector_t * sector)
SetupSprite.Clock();
sector_t * sec=sub->sector;
// Handle all things in sector.
const auto &vp = Viewpoint;
for (auto p = sec->touching_renderthings; p != nullptr; p = p->m_snext)
{
auto thing = p->m_thing;
@ -362,7 +363,7 @@ void HWDrawInfo::RenderThings(subsector_t * sub, sector_t * sector)
FIntCVar *cvar = thing->GetInfo()->distancecheck;
if (cvar != nullptr && *cvar >= 0)
{
double dist = (thing->Pos() - r_viewpoint.Pos).LengthSquared();
double dist = (thing->Pos() - vp.Pos).LengthSquared();
double check = (double)**cvar;
if (dist >= check * check)
{
@ -383,7 +384,7 @@ void HWDrawInfo::RenderThings(subsector_t * sub, sector_t * sector)
FIntCVar *cvar = thing->GetInfo()->distancecheck;
if (cvar != nullptr && *cvar >= 0)
{
double dist = (thing->Pos() - r_viewpoint.Pos).LengthSquared();
double dist = (thing->Pos() - vp.Pos).LengthSquared();
double check = (double)**cvar;
if (dist >= check * check)
{
@ -537,13 +538,13 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
portal = fakesector->GetPortalGroup(sector_t::ceiling);
if (portal != nullptr)
{
portal->AddSubsector(sub);
AddSubsectorToPortal(portal, sub);
}
portal = fakesector->GetPortalGroup(sector_t::floor);
if (portal != nullptr)
{
portal->AddSubsector(sub);
AddSubsectorToPortal(portal, sub);
}
}
}

View file

@ -373,10 +373,10 @@ angle_t Clipper::AngleToPseudo(angle_t ang)
//
//-----------------------------------------------------------------------------
angle_t R_PointToPseudoAngle(double x, double y)
angle_t Clipper::PointToPseudoAngle(double x, double y)
{
double vecx = x - r_viewpoint.Pos.X;
double vecy = y - r_viewpoint.Pos.Y;
double vecx = x - viewpoint->Pos.X;
double vecy = y - viewpoint->Pos.Y;
if (vecx == 0 && vecy == 0)
{
@ -427,14 +427,15 @@ bool Clipper::CheckBox(const float *bspcoord)
// Find the corners of the box
// that define the edges from current viewpoint.
boxpos = (r_viewpoint.Pos.X <= bspcoord[BOXLEFT] ? 0 : r_viewpoint.Pos.X < bspcoord[BOXRIGHT ] ? 1 : 2) +
(r_viewpoint.Pos.Y >= bspcoord[BOXTOP ] ? 0 : r_viewpoint.Pos.Y > bspcoord[BOXBOTTOM] ? 4 : 8);
auto &vp = viewpoint;
boxpos = (vp->Pos.X <= bspcoord[BOXLEFT] ? 0 : vp->Pos.X < bspcoord[BOXRIGHT ] ? 1 : 2) +
(vp->Pos.Y >= bspcoord[BOXTOP ] ? 0 : vp->Pos.Y > bspcoord[BOXBOTTOM] ? 4 : 8);
if (boxpos == 5) return true;
check = checkcoord[boxpos];
angle1 = R_PointToPseudoAngle (bspcoord[check[0]], bspcoord[check[1]]);
angle2 = R_PointToPseudoAngle (bspcoord[check[2]], bspcoord[check[3]]);
angle1 = PointToPseudoAngle (bspcoord[check[0]], bspcoord[check[1]]);
angle2 = PointToPseudoAngle (bspcoord[check[2]], bspcoord[check[3]]);
return SafeCheckRange(angle2, angle1);
}

View file

@ -6,14 +6,6 @@
#include "r_utility.h"
#include "memarena.h"
angle_t R_PointToPseudoAngle(double x, double y);
// Used to speed up angle calculations during clipping
inline angle_t vertex_t::GetClipAngle()
{
return R_PointToPseudoAngle(p.X, p.Y);
}
class ClipNode
{
friend class Clipper;
@ -37,6 +29,7 @@ class Clipper
ClipNode * clipnodes = nullptr;
ClipNode * cliphead = nullptr;
ClipNode * silhouette = nullptr; // will be preserved even when RemoveClipRange is called
const FRenderViewpoint *viewpoint = nullptr;
bool blocked = false;
static angle_t AngleToPseudo(angle_t ang);
@ -78,6 +71,11 @@ public:
c->next = c->prev = NULL;
return c;
}
void SetViewpoint(const FRenderViewpoint &vp)
{
viewpoint = &vp;
}
void SetSilhouette();
@ -105,6 +103,13 @@ public:
AddClipRange(startangle, endangle);
}
}
void SafeAddClipRange(const vertex_t *v1, const vertex_t *v2)
{
angle_t a2 = PointToPseudoAngle(v1->p.X, v1->p.Y);
angle_t a1 = PointToPseudoAngle(v2->p.X, v2->p.Y);
SafeAddClipRange(a1,a2);
}
void SafeAddClipRangeRealAngles(angle_t startangle, angle_t endangle)
{
@ -141,13 +146,15 @@ public:
{
return blocked;
}
angle_t PointToPseudoAngle(double x, double y);
bool CheckBox(const float *bspcoord);
// Used to speed up angle calculations during clipping
inline angle_t GetClipAngle(vertex_t *v)
{
return unsigned(v->angletime) == starttime ? v->viewangle : (v->angletime = starttime, v->viewangle = R_PointToPseudoAngle(v->p.X, v->p.Y));
return unsigned(v->angletime) == starttime ? v->viewangle : (v->angletime = starttime, v->viewangle = PointToPseudoAngle(v->p.X, v->p.Y));
}
};

View file

@ -0,0 +1,284 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2000-2018 Christoph Oelckers
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** gl_drawinfo.cpp
** Basic scene draw info management class
**
*/
#include "a_sharedglobal.h"
#include "r_utility.h"
#include "r_sky.h"
#include "d_player.h"
#include "g_levellocals.h"
#include "hw_fakeflat.h"
#include "hw_drawinfo.h"
#include "hw_portal.h"
#include "hwrenderer/utility/hw_clock.h"
#include "hwrenderer/utility/hw_cvars.h"
EXTERN_CVAR(Float, r_visibility)
CVAR(Bool, gl_bandedswlight, false, CVAR_ARCHIVE)
sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool back);
//==========================================================================
//
//
//
//==========================================================================
void HWDrawInfo::ClearBuffers()
{
for(unsigned int i=0;i< otherfloorplanes.Size();i++)
{
gl_subsectorrendernode * node = otherfloorplanes[i];
while (node)
{
gl_subsectorrendernode * n = node;
node = node->next;
delete n;
}
}
otherfloorplanes.Clear();
for(unsigned int i=0;i< otherceilingplanes.Size();i++)
{
gl_subsectorrendernode * node = otherceilingplanes[i];
while (node)
{
gl_subsectorrendernode * n = node;
node = node->next;
delete n;
}
}
otherceilingplanes.Clear();
// clear all the lists that might not have been cleared already
MissingUpperTextures.Clear();
MissingLowerTextures.Clear();
MissingUpperSegs.Clear();
MissingLowerSegs.Clear();
SubsectorHacks.Clear();
CeilingStacks.Clear();
FloorStacks.Clear();
HandledSubsectors.Clear();
spriteindex = 0;
CurrentMapSections.Resize(level.NumMapSections);
CurrentMapSections.Zero();
sectorrenderflags.Resize(level.sectors.Size());
ss_renderflags.Resize(level.subsectors.Size());
no_renderflags.Resize(level.subsectors.Size());
memset(&sectorrenderflags[0], 0, level.sectors.Size() * sizeof(sectorrenderflags[0]));
memset(&ss_renderflags[0], 0, level.subsectors.Size() * sizeof(ss_renderflags[0]));
memset(&no_renderflags[0], 0, level.nodes.Size() * sizeof(no_renderflags[0]));
mClipPortal = nullptr;
mCurrentPortal = nullptr;
}
//==========================================================================
//
//
//
//==========================================================================
void HWDrawInfo::UpdateCurrentMapSection()
{
const int mapsection = R_PointInSubsector(Viewpoint.Pos)->mapsection;
CurrentMapSections.Set(mapsection);
}
//-----------------------------------------------------------------------------
//
// Sets the area the camera is in
//
//-----------------------------------------------------------------------------
void HWDrawInfo::SetViewArea()
{
auto &vp = Viewpoint;
// The render_sector is better suited to represent the current position in GL
vp.sector = R_PointInSubsector(vp.Pos)->render_sector;
// Get the heightsec state from the render sector, not the current one!
if (vp.sector->GetHeightSec())
{
in_area = vp.Pos.Z <= vp.sector->heightsec->floorplane.ZatPoint(vp.Pos) ? area_below :
(vp.Pos.Z > vp.sector->heightsec->ceilingplane.ZatPoint(vp.Pos) &&
!(vp.sector->heightsec->MoreFlags&SECMF_FAKEFLOORONLY)) ? area_above : area_normal;
}
else
{
in_area = level.HasHeightSecs ? area_default : area_normal; // depends on exposed lower sectors, if map contains heightsecs.
}
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
int HWDrawInfo::SetFullbrightFlags(player_t *player)
{
FullbrightFlags = 0;
// check for special colormaps
player_t * cplayer = player? player->camera->player : nullptr;
if (cplayer)
{
int cm = CM_DEFAULT;
if (cplayer->extralight == INT_MIN)
{
cm = CM_FIRSTSPECIALCOLORMAP + INVERSECOLORMAP;
Viewpoint.extralight = 0;
FullbrightFlags = Fullbright;
// This does never set stealth vision.
}
else if (cplayer->fixedcolormap != NOFIXEDCOLORMAP)
{
cm = CM_FIRSTSPECIALCOLORMAP + cplayer->fixedcolormap;
FullbrightFlags = Fullbright;
if (gl_enhanced_nv_stealth > 2) FullbrightFlags |= StealthVision;
}
else if (cplayer->fixedlightlevel != -1)
{
auto torchtype = PClass::FindActor(NAME_PowerTorch);
auto litetype = PClass::FindActor(NAME_PowerLightAmp);
for (AInventory * in = cplayer->mo->Inventory; in; in = in->Inventory)
{
//PalEntry color = in->CallGetBlend();
// Need special handling for light amplifiers
if (in->IsKindOf(torchtype))
{
FullbrightFlags = Fullbright;
if (gl_enhanced_nv_stealth > 1) FullbrightFlags |= StealthVision;
}
else if (in->IsKindOf(litetype))
{
FullbrightFlags = Fullbright;
if (gl_enhanced_nightvision) FullbrightFlags |= Nightvision;
if (gl_enhanced_nv_stealth > 0) FullbrightFlags |= StealthVision;
}
}
}
return cm;
}
else
{
return CM_DEFAULT;
}
}
//-----------------------------------------------------------------------------
//
// R_FrustumAngle
//
//-----------------------------------------------------------------------------
angle_t HWDrawInfo::FrustumAngle()
{
float tilt = fabs(Viewpoint.HWAngles.Pitch.Degrees);
// If the pitch is larger than this you can look all around at a FOV of 90°
if (tilt > 46.0f) return 0xffffffff;
// ok, this is a gross hack that barely works...
// but at least it doesn't overestimate too much...
double floatangle = 2.0 + (45.0 + ((tilt / 1.9)))*Viewpoint.FieldOfView.Degrees*48.0 / AspectMultiplier(r_viewwindow.WidescreenRatio) / 90.0;
angle_t a1 = DAngle(floatangle).BAMs();
if (a1 >= ANGLE_180) return 0xffffffff;
return a1;
}
//-----------------------------------------------------------------------------
//
// Setup the modelview matrix
//
//-----------------------------------------------------------------------------
void HWDrawInfo::SetViewMatrix(const FRotator &angles, float vx, float vy, float vz, bool mirror, bool planemirror)
{
float mult = mirror ? -1.f : 1.f;
float planemult = planemirror ? -level.info->pixelstretch : level.info->pixelstretch;
VPUniforms.mViewMatrix.loadIdentity();
VPUniforms.mViewMatrix.rotate(angles.Roll.Degrees, 0.0f, 0.0f, 1.0f);
VPUniforms.mViewMatrix.rotate(angles.Pitch.Degrees, 1.0f, 0.0f, 0.0f);
VPUniforms.mViewMatrix.rotate(angles.Yaw.Degrees, 0.0f, mult, 0.0f);
VPUniforms.mViewMatrix.translate(vx * mult, -vz * planemult, -vy);
VPUniforms.mViewMatrix.scale(-mult, planemult, 1);
}
//-----------------------------------------------------------------------------
//
// SetupView
// Setup the view rotation matrix for the given viewpoint
//
//-----------------------------------------------------------------------------
void HWDrawInfo::SetupView(float vx, float vy, float vz, bool mirror, bool planemirror)
{
auto &vp = Viewpoint;
vp.SetViewAngle(r_viewwindow);
SetViewMatrix(vp.HWAngles, vx, vy, vz, mirror, planemirror);
SetCameraPos(vp.Pos);
ApplyVPUniforms();
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
IPortal * HWDrawInfo::FindPortal(const void * src)
{
int i = Portals.Size() - 1;
while (i >= 0 && Portals[i] && Portals[i]->GetSource() != src) i--;
return i >= 0 ? Portals[i] : nullptr;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void HWViewpointUniforms::SetDefaults()
{
mProjectionMatrix.loadIdentity();
mViewMatrix.loadIdentity();
mNormalViewMatrix.loadIdentity();
mViewHeight = viewheight;
mGlobVis = (float)R_GetGlobVis(r_viewwindow, r_visibility) / 32.f;
mPalLightLevels = static_cast<int>(gl_bandedswlight) | (static_cast<int>(gl_fogmode) << 8);
mClipLine.X = -10000000.0f;
}

View file

@ -1,7 +1,11 @@
#pragma once
#include <atomic>
#include "vectors.h"
#include "r_defs.h"
#include "r_utility.h"
#include "hw_viewpointuniforms.h"
#include "v_video.h"
struct FSectorPortalGroup;
@ -18,6 +22,8 @@ struct HUDSprite;
class Clipper;
class IPortal;
class FFlatVertexGenerator;
class IRenderQueue;
class HWScenePortalBase;
//==========================================================================
//
@ -53,7 +59,10 @@ enum EPortalClip
struct HWDrawInfo
{
virtual ~HWDrawInfo() {}
virtual ~HWDrawInfo()
{
ClearBuffers();
}
struct wallseg
{
@ -91,14 +100,17 @@ struct HWDrawInfo
bool isNightvision() const { return !!(FullbrightFlags & Nightvision); }
bool isStealthVision() const { return !!(FullbrightFlags & StealthVision); }
HWDrawInfo * outer = nullptr;
int FullbrightFlags;
std::atomic<int> spriteindex;
IPortal *mClipPortal;
FRotator mAngles;
FVector2 mViewVector;
AActor *mViewActor;
HWScenePortalBase *mClipPortal;
IPortal *mCurrentPortal;
//FRotator mAngles;
IShadowMap *mShadowMap;
Clipper *mClipper;
FRenderViewpoint Viewpoint;
HWViewpointUniforms VPUniforms; // per-viewpoint uniform state
TArray<IPortal *> Portals;
TArray<MissingTextureInfo> MissingUpperTextures;
TArray<MissingTextureInfo> MissingLowerTextures;
@ -138,6 +150,7 @@ private:
sector_t fakesec; // this is a struct member because it gets used in recursively called functions so it cannot be put on the stack.
void UnclipSubsector(subsector_t *sub);
void AddLine(seg_t *seg, bool portalclip);
void PolySubsector(subsector_t * sub);
@ -148,6 +161,31 @@ private:
void RenderThings(subsector_t * sub, sector_t * sector);
void DoSubsector(subsector_t * sub);
public:
void SetCameraPos(const DVector3 &pos)
{
VPUniforms.mCameraPos = { (float)pos.X, (float)pos.Z, (float)pos.Y, 0.f };
}
void SetClipHeight(float h, float d)
{
VPUniforms.mClipHeight = h;
VPUniforms.mClipHeightDirection = d;
VPUniforms.mClipLine.X = -1000001.f;
}
void SetClipLine(line_t *line)
{
VPUniforms.mClipLine = { (float)line->v1->fX(), (float)line->v1->fY(), (float)line->Delta().X, (float)line->Delta().Y };
VPUniforms.mClipHeight = 0;
}
bool ClipLineShouldBeActive()
{
return (screen->hwcaps & RFL_NO_CLIP_PLANES) && VPUniforms.mClipLine.X > -1000000.f;
}
IPortal * FindPortal(const void * src);
void RenderBSPNode(void *node);
void ClearBuffers();
@ -188,6 +226,9 @@ public:
void PrepareTargeterSprites();
void UpdateCurrentMapSection();
void SetViewMatrix(const FRotator &angles, float vx, float vy, float vz, bool mirror, bool planemirror);
void SetupView(float vx, float vy, float vz, bool mirror, bool planemirror);
angle_t FrustumAngle();
virtual void DrawWall(GLWall *wall, int pass) = 0;
virtual void DrawFlat(GLFlat *flat, int pass, bool trans) = 0;
@ -195,7 +236,7 @@ public:
virtual void FloodUpperGap(seg_t * seg) = 0;
virtual void FloodLowerGap(seg_t * seg) = 0;
virtual void ProcessLowerMinisegs(TArray<seg_t *> &lowersegs) = 0;
void ProcessLowerMinisegs(TArray<seg_t *> &lowersegs);
virtual void AddSubsectorToPortal(FSectorPortalGroup *portal, subsector_t *sub) = 0;
virtual void AddWall(GLWall *w) = 0;
@ -206,6 +247,8 @@ public:
virtual void AddHUDSprite(HUDSprite *huds) = 0;
virtual int UploadLights(FDynLightData &data) = 0;
virtual void ApplyVPUniforms() = 0;
virtual bool SetDepthClamp(bool on) = 0;
virtual GLDecal *AddDecal(bool onmirror) = 0;
virtual std::pair<FFlatVertex *, unsigned int> AllocVertices(unsigned int count) = 0;

View file

@ -121,7 +121,7 @@ inline void SortNode::AddToEqual(SortNode *child)
{
child->UnlinkFromChain();
child->equal=equal;
equal=child;
equal=child;
}
//==========================================================================
@ -269,7 +269,7 @@ void HWDrawList::SortWallIntoPlane(SortNode * head, SortNode * sort)
GLFlat * fh = flats[drawitems[head->itemindex].index];
GLWall * ws = walls[drawitems[sort->itemindex].index];
bool ceiling = fh->z > r_viewpoint.Pos.Z;
bool ceiling = fh->z > SortZ;
if ((ws->ztop[0] > fh->z || ws->ztop[1] > fh->z) && (ws->zbottom[0] < fh->z || ws->zbottom[1] < fh->z))
{
@ -327,7 +327,7 @@ void HWDrawList::SortSpriteIntoPlane(SortNode * head, SortNode * sort)
GLFlat * fh = flats[drawitems[head->itemindex].index];
GLSprite * ss = sprites[drawitems[sort->itemindex].index];
bool ceiling = fh->z > r_viewpoint.Pos.Z;
bool ceiling = fh->z > SortZ;
auto hiz = ss->z1 > ss->z2 ? ss->z1 : ss->z2;
auto loz = ss->z1 < ss->z2 ? ss->z1 : ss->z2;
@ -688,6 +688,7 @@ SortNode * HWDrawList::DoSort(HWDrawInfo *di, SortNode * head)
//==========================================================================
void HWDrawList::Sort(HWDrawInfo *di)
{
SortZ = di->Viewpoint.Pos.Z;
MakeSortList();
sorted = DoSort(di, SortNodes[SortNodeStart]);
}

View file

@ -61,6 +61,7 @@ struct HWDrawList
TArray<GLSprite*> sprites;
TArray<GLDrawItem> drawitems;
int SortNodeStart;
float SortZ;
SortNode * sorted;
public:

View file

@ -384,7 +384,7 @@ public:
void SplitSprite(HWDrawInfo *di, sector_t * frontsector, bool translucent);
void PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, float spriteheight);
bool CalculateVertices(HWDrawInfo *di, FVector3 *v);
bool CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp);
public:

View file

@ -386,79 +386,3 @@ sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac
}
return dest;
}
//-----------------------------------------------------------------------------
//
// Sets the area the camera is in
//
//-----------------------------------------------------------------------------
void HWDrawInfo::SetViewArea()
{
// The render_sector is better suited to represent the current position in GL
r_viewpoint.sector = R_PointInSubsector(r_viewpoint.Pos)->render_sector;
// Get the heightsec state from the render sector, not the current one!
if (r_viewpoint.sector->GetHeightSec())
{
in_area = r_viewpoint.Pos.Z <= r_viewpoint.sector->heightsec->floorplane.ZatPoint(r_viewpoint.Pos) ? area_below :
(r_viewpoint.Pos.Z > r_viewpoint.sector->heightsec->ceilingplane.ZatPoint(r_viewpoint.Pos) &&
!(r_viewpoint.sector->heightsec->MoreFlags&SECMF_FAKEFLOORONLY)) ? area_above : area_normal;
}
else
{
in_area = level.HasHeightSecs ? area_default : area_normal; // depends on exposed lower sectors, if map contains heightsecs.
}
}
int HWDrawInfo::SetFullbrightFlags(player_t *player)
{
FullbrightFlags = 0;
// check for special colormaps
player_t * cplayer = player? player->camera->player : nullptr;
if (cplayer)
{
int cm = CM_DEFAULT;
if (cplayer->extralight == INT_MIN)
{
cm = CM_FIRSTSPECIALCOLORMAP + INVERSECOLORMAP;
r_viewpoint.extralight = 0;
FullbrightFlags = Fullbright;
// This does never set stealth vision.
}
else if (cplayer->fixedcolormap != NOFIXEDCOLORMAP)
{
cm = CM_FIRSTSPECIALCOLORMAP + cplayer->fixedcolormap;
FullbrightFlags = Fullbright;
if (gl_enhanced_nv_stealth > 2) FullbrightFlags |= StealthVision;
}
else if (cplayer->fixedlightlevel != -1)
{
auto torchtype = PClass::FindActor(NAME_PowerTorch);
auto litetype = PClass::FindActor(NAME_PowerLightAmp);
for (AInventory * in = cplayer->mo->Inventory; in; in = in->Inventory)
{
//PalEntry color = in->CallGetBlend();
// Need special handling for light amplifiers
if (in->IsKindOf(torchtype))
{
FullbrightFlags = Fullbright;
if (gl_enhanced_nv_stealth > 1) FullbrightFlags |= StealthVision;
}
else if (in->IsKindOf(litetype))
{
FullbrightFlags = Fullbright;
if (gl_enhanced_nightvision) FullbrightFlags |= Nightvision;
if (gl_enhanced_nv_stealth > 0) FullbrightFlags |= StealthVision;
}
}
}
return cm;
}
else
{
return CM_DEFAULT;
}
}

View file

@ -9,7 +9,7 @@ enum area_t : int
};
// Global functions. Make them members of GLRenderer later?
// Global functions.
bool hw_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsector);
sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool back);
area_t hw_CheckViewArea(vertex_t *v1, vertex_t *v2, sector_t *frontsector, sector_t *backsector);

View file

@ -306,6 +306,7 @@ void GLFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector)
dynlightindex = -1;
uint8_t &srf = di->sectorrenderflags[sector->sectornum];
const auto &vp = di->Viewpoint;
//
//
@ -314,7 +315,7 @@ void GLFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector)
//
//
//
if (frontsector->floorplane.ZatPoint(r_viewpoint.Pos) <= r_viewpoint.Pos.Z)
if (frontsector->floorplane.ZatPoint(vp.Pos) <= vp.Pos.Z)
{
// process the original floor first.
@ -374,7 +375,7 @@ void GLFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector)
//
//
//
if (frontsector->ceilingplane.ZatPoint(r_viewpoint.Pos) >= r_viewpoint.Pos.Z)
if (frontsector->ceilingplane.ZatPoint(vp.Pos) >= vp.Pos.Z)
{
// process the original ceiling first.
@ -465,7 +466,7 @@ void GLFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector)
double ff_top = rover->top.plane->ZatPoint(sector->centerspot);
if (ff_top < lastceilingheight)
{
if (r_viewpoint.Pos.Z <= rover->top.plane->ZatPoint(r_viewpoint.Pos))
if (vp.Pos.Z <= rover->top.plane->ZatPoint(vp.Pos))
{
SetFrom3DFloor(rover, true, !!(rover->flags&FF_FOG));
Colormap.FadeColor = frontsector->Colormap.FadeColor;
@ -479,7 +480,7 @@ void GLFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector)
double ff_bottom = rover->bottom.plane->ZatPoint(sector->centerspot);
if (ff_bottom < lastceilingheight)
{
if (r_viewpoint.Pos.Z <= rover->bottom.plane->ZatPoint(r_viewpoint.Pos))
if (vp.Pos.Z <= rover->bottom.plane->ZatPoint(vp.Pos))
{
SetFrom3DFloor(rover, false, !(rover->flags&FF_FOG));
Colormap.FadeColor = frontsector->Colormap.FadeColor;
@ -505,7 +506,7 @@ void GLFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector)
double ff_bottom = rover->bottom.plane->ZatPoint(sector->centerspot);
if (ff_bottom > lastfloorheight || (rover->flags&FF_FIX))
{
if (r_viewpoint.Pos.Z >= rover->bottom.plane->ZatPoint(r_viewpoint.Pos))
if (vp.Pos.Z >= rover->bottom.plane->ZatPoint(vp.Pos))
{
SetFrom3DFloor(rover, false, !(rover->flags&FF_FOG));
Colormap.FadeColor = frontsector->Colormap.FadeColor;
@ -526,7 +527,7 @@ void GLFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector)
double ff_top = rover->top.plane->ZatPoint(sector->centerspot);
if (ff_top > lastfloorheight)
{
if (r_viewpoint.Pos.Z >= rover->top.plane->ZatPoint(r_viewpoint.Pos))
if (vp.Pos.Z >= rover->top.plane->ZatPoint(vp.Pos))
{
SetFrom3DFloor(rover, true, !!(rover->flags&FF_FOG));
Colormap.FadeColor = frontsector->Colormap.FadeColor;

View file

@ -0,0 +1,628 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2004-2018 Christoph Oelckers
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** hw_portal.cpp
** portal maintenance classes for skyboxes, horizons etc. (API independent parts)
**
*/
#include "c_dispatch.h"
#include "portal.h"
#include "p_maputl.h"
#include "hw_portal.h"
#include "hw_clipper.h"
#include "actor.h"
#include "g_levellocals.h"
EXTERN_CVAR(Int, r_mirror_recursions)
//-----------------------------------------------------------------------------
//
// StartFrame
//
//-----------------------------------------------------------------------------
void FPortalSceneState::StartFrame()
{
if (renderdepth == 0)
{
inskybox = false;
screen->instack[sector_t::floor] = screen->instack[sector_t::ceiling] = 0;
}
renderdepth++;
}
//-----------------------------------------------------------------------------
//
// printing portal info
//
//-----------------------------------------------------------------------------
static bool gl_portalinfo;
CCMD(gl_portalinfo)
{
gl_portalinfo = true;
}
static FString indent;
//-----------------------------------------------------------------------------
//
// EndFrame
//
//-----------------------------------------------------------------------------
void FPortalSceneState::EndFrame(HWDrawInfo *di)
{
IPortal * p;
if (gl_portalinfo)
{
Printf("%s%d portals, depth = %d\n%s{\n", indent.GetChars(), di->Portals.Size(), renderdepth, indent.GetChars());
indent += " ";
}
// Only use occlusion query if there are more than 2 portals.
// Otherwise there's too much overhead.
// (And don't forget to consider the separating null pointers!)
bool usequery = di->Portals.Size() > 2 + (unsigned)renderdepth;
while (di->Portals.Pop(p) && p)
{
if (gl_portalinfo)
{
Printf("%sProcessing %s, depth = %d, query = %d\n", indent.GetChars(), p->GetName(), renderdepth, usequery);
}
if (p->lines.Size() > 0)
{
p->RenderPortal(true, usequery, di);
}
delete p;
}
renderdepth--;
if (gl_portalinfo)
{
indent.Truncate(long(indent.Len()-2));
Printf("%s}\n", indent.GetChars());
if (indent.Len() == 0) gl_portalinfo = false;
}
}
//-----------------------------------------------------------------------------
//
// Renders one sky portal without a stencil.
// In more complex scenes using a stencil for skies can severely stall
// the GPU and there's rarely more than one sky visible at a time.
//
//-----------------------------------------------------------------------------
bool FPortalSceneState::RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di)
{
IPortal * p;
IPortal * best = nullptr;
unsigned bestindex = 0;
// Find the one with the highest amount of lines.
// Normally this is also the one that saves the largest amount
// of time by drawing it before the scene itself.
auto &portals = outer_di->Portals;
for (int i = portals.Size() - 1; i >= 0; --i)
{
p = portals[i];
if (p->lines.Size() > 0 && p->IsSky())
{
// Cannot clear the depth buffer inside a portal recursion
if (recursion && p->NeedDepthBuffer()) continue;
if (!best || p->lines.Size() > best->lines.Size())
{
best = p;
bestindex = i;
}
}
}
if (best)
{
portals.Delete(bestindex);
best->RenderPortal(false, false, outer_di);
delete best;
return true;
}
return false;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void HWScenePortalBase::ClearClipper(HWDrawInfo *di, Clipper *clipper)
{
auto outer_di = di->outer;
DAngle angleOffset = deltaangle(outer_di->Viewpoint.Angles.Yaw, di->Viewpoint.Angles.Yaw);
clipper->Clear();
auto &lines = mOwner->lines;
// Set the clipper to the minimal visible area
clipper->SafeAddClipRange(0, 0xffffffff);
for (unsigned int i = 0; i < lines.Size(); i++)
{
DAngle startAngle = (DVector2(lines[i].glseg.x2, lines[i].glseg.y2) - outer_di->Viewpoint.Pos).Angle() + angleOffset;
DAngle endAngle = (DVector2(lines[i].glseg.x1, lines[i].glseg.y1) - outer_di->Viewpoint.Pos).Angle() + angleOffset;
if (deltaangle(endAngle, startAngle) < 0)
{
clipper->SafeRemoveClipRangeRealAngles(startAngle.BAMs(), endAngle.BAMs());
}
}
// and finally clip it to the visible area
angle_t a1 = di->FrustumAngle();
if (a1 < ANGLE_180) clipper->SafeAddClipRangeRealAngles(di->Viewpoint.Angles.Yaw.BAMs() + a1, di->Viewpoint.Angles.Yaw.BAMs() - a1);
// lock the parts that have just been clipped out.
clipper->SetSilhouette();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
//
// Common code for line to line and mirror portals
//
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int HWLinePortal::ClipSeg(seg_t *seg, const DVector3 &viewpos)
{
line_t *linedef = seg->linedef;
if (!linedef)
{
return PClip_Inside; // should be handled properly.
}
return P_ClipLineToPortal(linedef, line(), viewpos) ? PClip_InFront : PClip_Inside;
}
int HWLinePortal::ClipSubsector(subsector_t *sub)
{
// this seg is completely behind the mirror
for (unsigned int i = 0; i<sub->numlines; i++)
{
if (P_PointOnLineSidePrecise(sub->firstline[i].v1->fPos(), line()) == 0) return PClip_Inside;
}
return PClip_InFront;
}
int HWLinePortal::ClipPoint(const DVector2 &pos)
{
if (P_PointOnLineSidePrecise(pos, line()))
{
return PClip_InFront;
}
return PClip_Inside;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
//
// Mirror Portal
//
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
bool HWMirrorPortal::Setup(HWDrawInfo *di, Clipper *clipper)
{
auto state = mOwner->mState;
if (state->renderdepth > r_mirror_recursions)
{
return false;
}
auto &vp = di->Viewpoint;
di->UpdateCurrentMapSection();
di->mClipPortal = this;
DAngle StartAngle = vp.Angles.Yaw;
DVector3 StartPos = vp.Pos;
vertex_t *v1 = linedef->v1;
vertex_t *v2 = linedef->v2;
// the player is always visible in a mirror.
vp.showviewer = true;
// Reflect the current view behind the mirror.
if (linedef->Delta().X == 0)
{
// vertical mirror
vp.Pos.X = 2 * v1->fX() - StartPos.X;
// Compensation for reendering inaccuracies
if (StartPos.X < v1->fX()) vp.Pos.X -= 0.1;
else vp.Pos.X += 0.1;
}
else if (linedef->Delta().Y == 0)
{
// horizontal mirror
vp.Pos.Y = 2 * v1->fY() - StartPos.Y;
// Compensation for reendering inaccuracies
if (StartPos.Y < v1->fY()) vp.Pos.Y -= 0.1;
else vp.Pos.Y += 0.1;
}
else
{
// any mirror--use floats to avoid integer overflow.
// Use doubles to avoid losing precision which is very important here.
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);
vp.Pos.X = (x1 + r * dx) * 2 - x;
vp.Pos.Y = (y1 + r * dy) * 2 - y;
// Compensation for reendering inaccuracies
FVector2 v(-dx, dy);
v.MakeUnit();
vp.Pos.X += v[1] * state->renderdepth / 2;
vp.Pos.Y += v[0] * state->renderdepth / 2;
}
vp.Angles.Yaw = linedef->Delta().Angle() * 2. - StartAngle;
vp.ViewActor = nullptr;
state->MirrorFlag++;
di->SetClipLine(linedef);
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
clipper->Clear();
angle_t af = di->FrustumAngle();
if (af < ANGLE_180) clipper->SafeAddClipRangeRealAngles(vp.Angles.Yaw.BAMs() + af, vp.Angles.Yaw.BAMs() - af);
clipper->SafeAddClipRange(linedef->v1, linedef->v2);
return true;
}
void HWMirrorPortal::Shutdown(HWDrawInfo *di)
{
mOwner->mState->MirrorFlag--;
}
const char *HWMirrorPortal::GetName() { return "Mirror"; }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
//
// Line to line Portal
//
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
bool HWLineToLinePortal::Setup(HWDrawInfo *di, Clipper *clipper)
{
// TODO: Handle recursion more intelligently
auto &state = mOwner->mState;
if (state->renderdepth>r_mirror_recursions)
{
return false;
}
auto &vp = di->Viewpoint;
di->mClipPortal = this;
line_t *origin = glport->lines[0]->mOrigin;
P_TranslatePortalXY(origin, vp.Pos.X, vp.Pos.Y);
P_TranslatePortalXY(origin, vp.ActorPos.X, vp.ActorPos.Y);
P_TranslatePortalAngle(origin, vp.Angles.Yaw);
P_TranslatePortalZ(origin, vp.Pos.Z);
P_TranslatePortalXY(origin, vp.Path[0].X, vp.Path[0].Y);
P_TranslatePortalXY(origin, vp.Path[1].X, vp.Path[1].Y);
if (!vp.showviewer && vp.camera != nullptr && P_PointOnLineSidePrecise(vp.Path[0], glport->lines[0]->mDestination) != P_PointOnLineSidePrecise(vp.Path[1], glport->lines[0]->mDestination))
{
double distp = (vp.Path[0] - vp.Path[1]).Length();
if (distp > EQUAL_EPSILON)
{
double dist1 = (vp.Pos - vp.Path[0]).Length();
double dist2 = (vp.Pos - vp.Path[1]).Length();
if (dist1 + dist2 < distp + 1)
{
vp.camera->renderflags |= RF_MAYBEINVISIBLE;
}
}
}
auto &lines = mOwner->lines;
for (unsigned i = 0; i < lines.Size(); i++)
{
line_t *line = lines[i].seg->linedef->getPortalDestination();
subsector_t *sub;
if (line->sidedef[0]->Flags & WALLF_POLYOBJ)
sub = R_PointInSubsector(line->v1->fixX(), line->v1->fixY());
else sub = line->frontsector->subsectors[0];
di->CurrentMapSections.Set(sub->mapsection);
}
vp.ViewActor = nullptr;
di->SetClipLine(glport->lines[0]->mDestination);
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
ClearClipper(di, clipper);
return true;
}
void HWLineToLinePortal::RenderAttached(HWDrawInfo *di)
{
di->ProcessActorsInPortal(glport, di->in_area);
}
const char *HWLineToLinePortal::GetName() { return "LineToLine"; }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
//
// Skybox Portal
//
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
// GLSkyboxPortal::DrawContents
//
//-----------------------------------------------------------------------------
bool HWSkyboxPortal::Setup(HWDrawInfo *di, Clipper *clipper)
{
auto state = mOwner->mState;
old_pm = state->PlaneMirrorMode;
if (mOwner->mState->skyboxrecursion >= 3)
{
return false;
}
auto &vp = di->Viewpoint;
state->skyboxrecursion++;
state->PlaneMirrorMode = 0;
state->inskybox = true;
AActor *origin = portal->mSkybox;
portal->mFlags |= PORTSF_INSKYBOX;
vp.extralight = 0;
oldclamp = di->SetDepthClamp(false);
vp.Pos = origin->InterpolatedPosition(vp.TicFrac);
vp.ActorPos = origin->Pos();
vp.Angles.Yaw += (origin->PrevAngles.Yaw + deltaangle(origin->PrevAngles.Yaw, origin->Angles.Yaw) * vp.TicFrac);
// Don't let the viewpoint be too close to a floor or ceiling
double floorh = origin->Sector->floorplane.ZatPoint(origin->Pos());
double ceilh = origin->Sector->ceilingplane.ZatPoint(origin->Pos());
if (vp.Pos.Z < floorh + 4) vp.Pos.Z = floorh + 4;
if (vp.Pos.Z > ceilh - 4) vp.Pos.Z = ceilh - 4;
vp.ViewActor = origin;
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
di->SetViewArea();
ClearClipper(di, clipper);
di->UpdateCurrentMapSection();
return true;
}
void HWSkyboxPortal::Shutdown(HWDrawInfo *di)
{
auto state = mOwner->mState;
portal->mFlags &= ~PORTSF_INSKYBOX;
di->SetDepthClamp(oldclamp);
state->inskybox = false;
state->skyboxrecursion--;
state->PlaneMirrorMode = old_pm;
}
const char *HWSkyboxPortal::GetName() { return "Skybox"; }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
//
// Sector stack Portal
//
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
// GLSectorStackPortal::SetupCoverage
//
//-----------------------------------------------------------------------------
static uint8_t SetCoverage(HWDrawInfo *di, void *node)
{
if (level.nodes.Size() == 0)
{
return 0;
}
if (!((size_t)node & 1)) // Keep going until found a subsector
{
node_t *bsp = (node_t *)node;
uint8_t coverage = SetCoverage(di, bsp->children[0]) | SetCoverage(di, bsp->children[1]);
di->no_renderflags[bsp->Index()] = coverage;
return coverage;
}
else
{
subsector_t *sub = (subsector_t *)((uint8_t *)node - 1);
return di->ss_renderflags[sub->Index()] & SSRF_SEEN;
}
}
void HWSectorStackPortal::SetupCoverage(HWDrawInfo *di)
{
for (unsigned i = 0; i<subsectors.Size(); i++)
{
subsector_t *sub = subsectors[i];
int plane = origin->plane;
for (int j = 0; j<sub->portalcoverage[plane].sscount; j++)
{
subsector_t *dsub = &::level.subsectors[sub->portalcoverage[plane].subsectors[j]];
di->CurrentMapSections.Set(dsub->mapsection);
di->ss_renderflags[dsub->Index()] |= SSRF_SEEN;
}
}
SetCoverage(di, ::level.HeadNode());
}
//-----------------------------------------------------------------------------
//
// GLSectorStackPortal::DrawContents
//
//-----------------------------------------------------------------------------
bool HWSectorStackPortal::Setup(HWDrawInfo *di, Clipper *clipper)
{
auto state = mOwner->mState;
FSectorPortalGroup *portal = origin;
auto &vp = di->Viewpoint;
vp.Pos += origin->mDisplacement;
vp.ActorPos += origin->mDisplacement;
vp.ViewActor = nullptr;
// avoid recursions!
if (origin->plane != -1) screen->instack[origin->plane]++;
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
SetupCoverage(di);
ClearClipper(di, clipper);
// If the viewpoint is not within the portal, we need to invalidate the entire clip area.
// The portal will re-validate the necessary parts when its subsectors get traversed.
subsector_t *sub = R_PointInSubsector(vp.Pos);
if (!(di->ss_renderflags[sub->Index()] & SSRF_SEEN))
{
clipper->SafeAddClipRange(0, ANGLE_MAX);
clipper->SetBlocked(true);
}
return true;
}
void HWSectorStackPortal::Shutdown(HWDrawInfo *di)
{
if (origin->plane != -1) screen->instack[origin->plane]--;
}
const char *HWSectorStackPortal::GetName() { return "Sectorstack"; }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
//
// Plane Mirror Portal
//
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
// GLPlaneMirrorPortal::DrawContents
//
//-----------------------------------------------------------------------------
bool HWPlaneMirrorPortal::Setup(HWDrawInfo *di, Clipper *clipper)
{
auto state = mOwner->mState;
if (state->renderdepth > r_mirror_recursions)
{
return false;
}
// A plane mirror needs to flip the portal exclusion logic because inside the mirror, up is down and down is up.
std::swap(screen->instack[sector_t::floor], screen->instack[sector_t::ceiling]);
auto &vp = di->Viewpoint;
old_pm = state->PlaneMirrorMode;
// the player is always visible in a mirror.
vp.showviewer = true;
double planez = origin->ZatPoint(vp.Pos);
vp.Pos.Z = 2 * planez - vp.Pos.Z;
vp.ViewActor = nullptr;
state->PlaneMirrorMode = origin->fC() < 0 ? -1 : 1;
state->PlaneMirrorFlag++;
di->SetClipHeight(planez, state->PlaneMirrorMode < 0 ? -1.f : 1.f);
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
ClearClipper(di, clipper);
di->UpdateCurrentMapSection();
return true;
}
void HWPlaneMirrorPortal::Shutdown(HWDrawInfo *di)
{
auto state = mOwner->mState;
state->PlaneMirrorFlag--;
state->PlaneMirrorMode = old_pm;
std::swap(screen->instack[sector_t::floor], screen->instack[sector_t::ceiling]);
}
const char *HWPlaneMirrorPortal::GetName() { return origin->fC() < 0? "Planemirror ceiling" : "Planemirror floor"; }

View file

@ -1,6 +1,8 @@
#pragma once
#include "portal.h"
#include "hw_drawinfo.h"
#include "hw_drawstructs.h"
#include "hwrenderer/textures/hw_material.h"
struct GLSkyInfo
@ -33,12 +35,278 @@ struct GLHorizonInfo
PalEntry specialcolor;
};
struct FPortalSceneState;
class IPortal
{
friend struct FPortalSceneState;
public:
FPortalSceneState * mState;
TArray<GLWall> lines;
IPortal(FPortalSceneState *s, bool local);
virtual ~IPortal() {}
virtual int ClipSeg(seg_t *seg) { return PClip_Inside; }
virtual void * GetSource() const = 0; // GetSource MUST be implemented!
virtual const char *GetName() = 0;
virtual bool IsSky() { return false; }
virtual bool NeedCap() { return true; }
virtual bool NeedDepthBuffer() { return true; }
virtual void DrawContents(HWDrawInfo *di) = 0;
virtual void RenderAttached(HWDrawInfo *di) {}
virtual bool Start(bool usestencil, bool doquery, HWDrawInfo *outer_di, HWDrawInfo **pDi) = 0;
virtual void End(HWDrawInfo *di, bool usestencil) = 0;
void AddLine(GLWall * l)
{
lines.Push(*l);
}
void RenderPortal(bool usestencil, bool doquery, HWDrawInfo *outer_di)
{
// Start may perform an occlusion query. If that returns 0 there
// is no need to draw the stencil's contents and there's also no
// need to restore the affected area becasue there is none!
HWDrawInfo *di;
if (Start(usestencil, doquery, outer_di, &di))
{
DrawContents(di);
End(di, usestencil);
}
}
};
struct FPortalSceneState
{
int recursion = 0;
int MirrorFlag = 0;
int PlaneMirrorFlag = 0;
int renderdepth = 0;
int PlaneMirrorMode = 0;
bool inskybox = 0;
UniqueList<GLSkyInfo> UniqueSkies;
UniqueList<GLHorizonInfo> UniqueHorizons;
UniqueList<secplane_t> UniquePlaneMirrors;
int skyboxrecursion = 0;
void BeginScene()
{
UniqueSkies.Clear();
UniqueHorizons.Clear();
UniquePlaneMirrors.Clear();
}
int GetRecursion() const
{
return recursion;
}
bool isMirrored() const
{
return !!((MirrorFlag ^ PlaneMirrorFlag) & 1);
}
void StartFrame();
bool RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di);
void EndFrame(HWDrawInfo *outer_di);
};
inline IPortal::IPortal(FPortalSceneState *s, bool local) : mState(s)
{
//if (!local) s->portals.Push(this);
}
class HWScenePortalBase
{
protected:
IPortal *mOwner;
public:
HWScenePortalBase() {}
virtual ~HWScenePortalBase() {}
void SetOwner(IPortal *p) { mOwner = p; }
void ClearClipper(HWDrawInfo *di, Clipper *clipper);
virtual int ClipSeg(seg_t *seg, const DVector3 &viewpos) { return PClip_Inside; }
virtual int ClipSubsector(subsector_t *sub) { return PClip_Inside; }
virtual int ClipPoint(const DVector2 &pos) { return PClip_Inside; }
virtual line_t *ClipLine() { return nullptr; }
virtual bool IsSky() { return false; }
virtual bool NeedCap() { return false; }
virtual bool NeedDepthBuffer() { return true; }
virtual void * GetSource() const = 0; // GetSource MUST be implemented!
virtual const char *GetName() = 0;
virtual bool Setup(HWDrawInfo *di, Clipper *clipper) = 0;
virtual void Shutdown(HWDrawInfo *di) {}
virtual void RenderAttached(HWDrawInfo *di) {}
};
struct HWLinePortal : public HWScenePortalBase
{
// this must be the same as at the start of line_t, so that we can pass in this structure directly to P_ClipLineToPortal.
vertex_t *v1, *v2; // vertices, from v1 to v2
DVector2 delta; // precalculated v2 - v1 for side checking
angle_t angv1, angv2; // for quick comparisons with a line or subsector
HWLinePortal(line_t *line)
{
v1 = line->v1;
v2 = line->v2;
CalcDelta();
}
HWLinePortal(FLinePortalSpan *line)
{
if (line->lines[0]->mType != PORTT_LINKED || line->v1 == nullptr)
{
// For non-linked portals we must check the actual linedef.
line_t *lline = line->lines[0]->mDestination;
v1 = lline->v1;
v2 = lline->v2;
}
else
{
// For linked portals we can check the merged span.
v1 = line->v1;
v2 = line->v2;
}
CalcDelta();
}
void CalcDelta()
{
delta = v2->fPos() - v1->fPos();
}
line_t *line()
{
vertex_t **pv = &v1;
return reinterpret_cast<line_t*>(pv);
}
int ClipSeg(seg_t *seg, const DVector3 &viewpos) override;
int ClipSubsector(subsector_t *sub) override;
int ClipPoint(const DVector2 &pos);
bool NeedCap() override { return false; }
};
struct HWMirrorPortal : public HWLinePortal
{
// mirror portals always consist of single linedefs!
line_t * linedef;
protected:
bool Setup(HWDrawInfo *di, Clipper *clipper) override;
void Shutdown(HWDrawInfo *di) override;
void * GetSource() const override { return linedef; }
const char *GetName() override;
public:
HWMirrorPortal(line_t * line)
: HWLinePortal(line)
{
linedef = line;
}
};
struct HWLineToLinePortal : public HWLinePortal
{
FLinePortalSpan *glport;
protected:
bool Setup(HWDrawInfo *di, Clipper *clipper) override;
virtual void * GetSource() const override { return glport; }
virtual const char *GetName() override;
virtual line_t *ClipLine() override { return line(); }
virtual void RenderAttached(HWDrawInfo *di) override;
public:
HWLineToLinePortal(FLinePortalSpan *ll)
: HWLinePortal(ll)
{
glport = ll;
}
};
struct HWSkyboxPortal : public HWScenePortalBase
{
bool oldclamp;
int old_pm;
FSectorPortal * portal;
protected:
bool Setup(HWDrawInfo *di, Clipper *clipper) override;
void Shutdown(HWDrawInfo *di) override;
virtual void * GetSource() const { return portal; }
virtual bool IsSky() { return true; }
virtual const char *GetName();
public:
HWSkyboxPortal(FSectorPortal * pt)
{
portal = pt;
}
};
struct HWSectorStackPortal : public HWScenePortalBase
{
TArray<subsector_t *> subsectors;
protected:
bool Setup(HWDrawInfo *di, Clipper *clipper) override;
void Shutdown(HWDrawInfo *di) override;
virtual void * GetSource() const { return origin; }
virtual bool IsSky() { return true; } // although this isn't a real sky it can be handled as one.
virtual const char *GetName();
FSectorPortalGroup *origin;
public:
HWSectorStackPortal(FSectorPortalGroup *pt)
{
origin = pt;
}
void SetupCoverage(HWDrawInfo *di);
void AddSubsector(subsector_t *sub)
{
subsectors.Push(sub);
}
};
struct HWPlaneMirrorPortal : public HWScenePortalBase
{
int old_pm;
protected:
bool Setup(HWDrawInfo *di, Clipper *clipper) override;
void Shutdown(HWDrawInfo *di) override;
virtual void * GetSource() const { return origin; }
virtual const char *GetName();
secplane_t * origin;
public:
HWPlaneMirrorPortal(secplane_t * pt)
{
origin = pt;
}
};

View file

@ -30,68 +30,12 @@
#include "r_sky.h"
#include "g_levellocals.h"
#include "hwrenderer/scene/hw_drawinfo.h"
#include "hw_drawinfo.h"
#include "hw_drawstructs.h"
#include "hwrenderer/utility/hw_clock.h"
sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool back);
void HWDrawInfo::ClearBuffers()
{
for(unsigned int i=0;i< otherfloorplanes.Size();i++)
{
gl_subsectorrendernode * node = otherfloorplanes[i];
while (node)
{
gl_subsectorrendernode * n = node;
node = node->next;
delete n;
}
}
otherfloorplanes.Clear();
for(unsigned int i=0;i< otherceilingplanes.Size();i++)
{
gl_subsectorrendernode * node = otherceilingplanes[i];
while (node)
{
gl_subsectorrendernode * n = node;
node = node->next;
delete n;
}
}
otherceilingplanes.Clear();
// clear all the lists that might not have been cleared already
MissingUpperTextures.Clear();
MissingLowerTextures.Clear();
MissingUpperSegs.Clear();
MissingLowerSegs.Clear();
SubsectorHacks.Clear();
CeilingStacks.Clear();
FloorStacks.Clear();
HandledSubsectors.Clear();
spriteindex = 0;
CurrentMapSections.Resize(level.NumMapSections);
CurrentMapSections.Zero();
sectorrenderflags.Resize(level.sectors.Size());
ss_renderflags.Resize(level.subsectors.Size());
no_renderflags.Resize(level.subsectors.Size());
memset(&sectorrenderflags[0], 0, level.sectors.Size() * sizeof(sectorrenderflags[0]));
memset(&ss_renderflags[0], 0, level.subsectors.Size() * sizeof(ss_renderflags[0]));
memset(&no_renderflags[0], 0, level.nodes.Size() * sizeof(no_renderflags[0]));
mClipPortal = nullptr;
}
void HWDrawInfo::UpdateCurrentMapSection()
{
const int mapsection = R_PointInSubsector(r_viewpoint.Pos)->mapsection;
CurrentMapSections.Set(mapsection);
}
//==========================================================================
//
// Adds a subsector plane to a sector's render list
@ -484,7 +428,7 @@ void HWDrawInfo::HandleMissingTextures(area_t in_area)
HandledSubsectors.Clear();
validcount++;
if (MissingUpperTextures[i].Planez > r_viewpoint.Pos.Z)
if (MissingUpperTextures[i].Planez > Viewpoint.Pos.Z)
{
// close the hole only if all neighboring sectors are an exact height match
// Otherwise just fill in the missing textures.
@ -556,7 +500,7 @@ void HWDrawInfo::HandleMissingTextures(area_t in_area)
HandledSubsectors.Clear();
validcount++;
if (MissingLowerTextures[i].Planez < r_viewpoint.Pos.Z)
if (MissingLowerTextures[i].Planez < Viewpoint.Pos.Z)
{
// close the hole only if all neighboring sectors are an exact height match
// Otherwise just fill in the missing textures.
@ -642,7 +586,7 @@ void HWDrawInfo::DrawUnhandledMissingTextures()
// already done!
if (seg->linedef->validcount == validcount) continue; // already done
seg->linedef->validcount = validcount;
if (seg->frontsector->GetPlaneTexZ(sector_t::ceiling) < r_viewpoint.Pos.Z) continue; // out of sight
if (seg->frontsector->GetPlaneTexZ(sector_t::ceiling) < Viewpoint.Pos.Z) continue; // out of sight
// FIXME: The check for degenerate subsectors should be more precise
if (seg->PartnerSeg && (seg->PartnerSeg->Subsector->flags & SSECF_DEGENERATE)) continue;
@ -664,7 +608,7 @@ void HWDrawInfo::DrawUnhandledMissingTextures()
if (seg->linedef->validcount == validcount) continue; // already done
seg->linedef->validcount = validcount;
if (!(sectorrenderflags[seg->backsector->sectornum] & SSRF_RENDERFLOOR)) continue;
if (seg->frontsector->GetPlaneTexZ(sector_t::floor) > r_viewpoint.Pos.Z) continue; // out of sight
if (seg->frontsector->GetPlaneTexZ(sector_t::floor) > Viewpoint.Pos.Z) continue; // out of sight
if (seg->backsector->transdoor) continue;
if (seg->backsector->GetTexture(sector_t::floor) == skyflatnum) continue;
if (seg->backsector->ValidatePortal(sector_t::floor) != NULL) continue;
@ -757,7 +701,7 @@ bool HWDrawInfo::CollectSubsectorsFloor(subsector_t * sub, sector_t * anchor)
sub->render_sector->GetPlaneTexZ(sector_t::floor) != anchor->GetPlaneTexZ(sector_t::floor) ||
sub->render_sector->GetFloorLight() != anchor->GetFloorLight())
{
if (sub == viewsubsector && r_viewpoint.Pos.Z < anchor->GetPlaneTexZ(sector_t::floor)) inview = true;
if (sub == viewsubsector && Viewpoint.Pos.Z < anchor->GetPlaneTexZ(sector_t::floor)) inview = true;
HandledSubsectors.Push(sub);
}
}
@ -901,9 +845,21 @@ bool HWDrawInfo::CollectSubsectorsCeiling(subsector_t * sub, sector_t * anchor)
//
//==========================================================================
void HWDrawInfo::ProcessLowerMinisegs(TArray<seg_t *> &lowersegs)
{
for(unsigned int j=0;j<lowersegs.Size();j++)
{
seg_t * seg=lowersegs[j];
GLWall wall;
wall.ProcessLowerMiniseg(this, seg, seg->Subsector->render_sector, seg->PartnerSeg->Subsector->render_sector);
rendered_lines++;
}
}
void HWDrawInfo::HandleHackedSubsectors()
{
viewsubsector = R_PointInSubsector(r_viewpoint.Pos);
viewsubsector = R_PointInSubsector(Viewpoint.Pos);
// Each subsector may only be processed once in this loop!
validcount++;

View file

@ -154,8 +154,9 @@ void GLWall::SkyPlane(HWDrawInfo *di, sector_t *sector, int plane, bool allowref
}
else if (allowreflect && sector->GetReflect(plane) > 0)
{
if ((plane == sector_t::ceiling && r_viewpoint.Pos.Z > sector->ceilingplane.fD()) ||
(plane == sector_t::floor && r_viewpoint.Pos.Z < -sector->floorplane.fD())) return;
auto vpz = di->Viewpoint.Pos.Z;
if ((plane == sector_t::ceiling && vpz > sector->ceilingplane.fD()) ||
(plane == sector_t::floor && vpz < -sector->floorplane.fD())) return;
ptype = PORTALTYPE_PLANEMIRROR;
planemirror = plane == sector_t::ceiling ? &sector->ceilingplane : &sector->floorplane;
}
@ -340,7 +341,7 @@ void GLWall::SkyBottom(HWDrawInfo *di, seg_t * seg,sector_t * fs,sector_t * bs,v
else
{
// Special hack for Vrack2b
if (bs->floorplane.ZatPoint(r_viewpoint.Pos) > r_viewpoint.Pos.Z) return;
if (bs->floorplane.ZatPoint(di->Viewpoint.Pos) > di->Viewpoint.Pos.Z) return;
}
}
zbottom[0]=zbottom[1]=-32768.0f;

View file

@ -289,7 +289,7 @@ void FSkyDomeCreator::SetupMatrices(FMaterial *tex, float x_offset, float y_offs
// smaller sky textures must be tiled. We restrict it to 128 sky pixels, though
modelMatrix.translate(0.f, -1250.f, 0.f);
modelMatrix.scale(1.f, 128 / 230.f, 1.f);
yscale = 128 / texh; // intentionally left as integer.
yscale = float(128 / texh); // intentionally left as integer.
}
else if (texh < 200)
{

View file

@ -68,8 +68,9 @@ EXTERN_CVAR(Float, transsouls)
//
//==========================================================================
bool GLSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v)
bool GLSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp)
{
const auto &HWAngles = di->Viewpoint.HWAngles;
if (actor != nullptr && (actor->renderflags & RF_SPRITETYPEMASK) == RF_FLATSPRITE)
{
Matrix3x4 mat;
@ -146,10 +147,10 @@ bool GLSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v)
{
// [CMB] Rotate relative to camera XY position, not just camera direction,
// which is nicer in VR
float xrel = xcenter - r_viewpoint.Pos.X;
float yrel = ycenter - r_viewpoint.Pos.Y;
float xrel = xcenter - vp->X;
float yrel = ycenter - vp->Y;
float absAngleDeg = RAD2DEG(atan2(-yrel, xrel));
float counterRotationDeg = 270. - di->mAngles.Yaw.Degrees; // counteracts existing sprite rotation
float counterRotationDeg = 270. - HWAngles.Yaw.Degrees; // counteracts existing sprite rotation
float relAngleDeg = counterRotationDeg + absAngleDeg;
mat.Rotate(0, 1, 0, relAngleDeg);
@ -157,7 +158,7 @@ bool GLSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v)
// [fgsfds] calculate yaw vectors
float yawvecX = 0, yawvecY = 0, rollDegrees = 0;
float angleRad = (270. - di->mAngles.Yaw).Radians();
float angleRad = (270. - HWAngles.Yaw).Radians();
if (actor) rollDegrees = Angles.Roll.Degrees;
if (isFlatSprite)
{
@ -181,7 +182,7 @@ bool GLSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v)
if (useOffsets) mat.Translate(xx, zz, yy);
if (drawWithXYBillboard)
{
mat.Rotate(-sin(angleRad), 0, cos(angleRad), -di->mAngles.Pitch.Degrees);
mat.Rotate(-sin(angleRad), 0, cos(angleRad), -HWAngles.Pitch.Degrees);
}
mat.Rotate(cos(angleRad), 0, sin(angleRad), rollDegrees);
if (useOffsets) mat.Translate(-xx, -zz, -yy);
@ -191,7 +192,7 @@ bool GLSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v)
// Rotate the sprite about the vector starting at the center of the sprite
// triangle strip and with direction orthogonal to where the player is looking
// in the x/y plane.
mat.Rotate(-sin(angleRad), 0, cos(angleRad), -di->mAngles.Pitch.Degrees);
mat.Rotate(-sin(angleRad), 0, cos(angleRad), -HWAngles.Pitch.Degrees);
}
mat.Translate(-xcenter, -zcenter, -ycenter); // retreat from sprite center
@ -403,7 +404,8 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
return;
}
AActor *camera = r_viewpoint.camera;
const auto &vp = di->Viewpoint;
AActor *camera = vp.camera;
if (thing->renderflags & RF_INVISIBLE || !thing->RenderStyle.IsVisible(thing->Alpha))
{
@ -425,26 +427,26 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
}
// [RH] Interpolate the sprite's position to make it look smooth
DVector3 thingpos = thing->InterpolatedPosition(r_viewpoint.TicFrac);
DVector3 thingpos = thing->InterpolatedPosition(vp.TicFrac);
if (thruportal == 1) thingpos += level.Displacements.getOffset(thing->Sector->PortalGroup, sector->PortalGroup);
// Some added checks if the camera actor is not supposed to be seen. It can happen that some portal setup has this actor in view in which case it may not be skipped here
if (thing == camera && !r_viewpoint.showviewer)
if (thing == camera && !vp.showviewer)
{
DVector3 thingorigin = thing->Pos();
if (thruportal == 1) thingorigin += level.Displacements.getOffset(thing->Sector->PortalGroup, sector->PortalGroup);
if (fabs(thingorigin.X - r_viewpoint.ActorPos.X) < 2 && fabs(thingorigin.Y - r_viewpoint.ActorPos.Y) < 2) return;
if (fabs(thingorigin.X - vp.ActorPos.X) < 2 && fabs(thingorigin.Y - vp.ActorPos.Y) < 2) return;
}
// Thing is invisible if close to the camera.
if (thing->renderflags & RF_MAYBEINVISIBLE)
{
if (fabs(thingpos.X - r_viewpoint.Pos.X) < 32 && fabs(thingpos.Y - r_viewpoint.Pos.Y) < 32) return;
if (fabs(thingpos.X - vp.Pos.X) < 32 && fabs(thingpos.Y - vp.Pos.Y) < 32) return;
}
// Too close to the camera. This doesn't look good if it is a sprite.
if (fabs(thingpos.X - r_viewpoint.Pos.X) < 2 && fabs(thingpos.Y - r_viewpoint.Pos.Y) < 2)
if (fabs(thingpos.X - vp.Pos.X) < 2 && fabs(thingpos.Y - vp.Pos.Y) < 2)
{
if (r_viewpoint.Pos.Z >= thingpos.Z - 2 && r_viewpoint.Pos.Z <= thingpos.Z + thing->Height + 2)
if (vp.Pos.Z >= thingpos.Z - 2 && vp.Pos.Z <= thingpos.Z + thing->Height + 2)
{
// exclude vertically moving objects from this check.
if (!thing->Vel.isZero())
@ -460,13 +462,13 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
// don't draw first frame of a player missile
if (thing->flags&MF_MISSILE)
{
if (!(thing->flags7 & MF7_FLYCHEAT) && thing->target == di->mViewActor && di->mViewActor != nullptr)
if (!(thing->flags7 & MF7_FLYCHEAT) && thing->target == vp.ViewActor && vp.ViewActor != nullptr)
{
double speed = thing->Vel.Length();
if (speed >= thing->target->radius / 2)
{
double clipdist = clamp(thing->Speed, thing->target->radius, thing->target->radius * 2);
if ((thingpos - r_viewpoint.Pos).LengthSquared() < clipdist * clipdist) return;
if ((thingpos - vp.Pos).LengthSquared() < clipdist * clipdist) return;
}
}
thing->flags7 |= MF7_FLYCHEAT; // do this only once for the very first frame, but not if it gets into range again.
@ -479,7 +481,7 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
}
// disabled because almost none of the actual game code is even remotely prepared for this. If desired, use the INTERPOLATE flag.
if (thing->renderflags & RF_INTERPOLATEANGLES)
Angles = thing->InterpolatedAngles(r_viewpoint.TicFrac);
Angles = thing->InterpolatedAngles(vp.TicFrac);
else
Angles = thing->Angles;
@ -506,7 +508,7 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
// [RH] Make floatbobbing a renderer-only effect.
if (thing->flags2 & MF2_FLOATBOB)
{
float fz = thing->GetBobOffset(r_viewpoint.TicFrac);
float fz = thing->GetBobOffset(vp.TicFrac);
z += fz;
}
@ -514,7 +516,7 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
if (!modelframe)
{
bool mirror;
DAngle ang = (thingpos - r_viewpoint.Pos).Angle();
DAngle ang = (thingpos - vp.Pos).Angle();
FTextureID patch;
// [ZZ] add direct picnum override
if (isPicnumOverride)
@ -531,7 +533,7 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
int rot;
if (!(thing->renderflags & RF_FLATSPRITE) || thing->flags7 & MF7_SPRITEANGLE)
{
sprangle = thing->GetSpriteAngle(ang, r_viewpoint.TicFrac);
sprangle = thing->GetSpriteAngle(ang, vp.TicFrac);
rot = -1;
}
else
@ -596,8 +598,8 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
switch (spritetype)
{
case RF_FACESPRITE:
viewvecX = di->mViewVector.X;
viewvecY = di->mViewVector.Y;
viewvecX = vp.ViewVector.X;
viewvecY = vp.ViewVector.Y;
x1 = x - viewvecY*leftfac;
x2 = x - viewvecY*rightfac;
@ -632,7 +634,7 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
gltexture = nullptr;
}
depth = FloatToFixed((x - r_viewpoint.Pos.X) * r_viewpoint.TanCos + (y - r_viewpoint.Pos.Y) * r_viewpoint.TanSin);
depth = FloatToFixed((x - vp.Pos.X) * vp.TanCos + (y - vp.Pos.Y) * vp.TanSin);
// light calculation
@ -923,7 +925,8 @@ void GLSprite::ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t *
}
}
double timefrac = r_viewpoint.TicFrac;
const auto &vp = di->Viewpoint;
double timefrac = vp.TicFrac;
if (paused || bglobal.freeze || (level.flags2 & LEVEL2_FROZEN))
timefrac = 0.;
float xvf = (particle->Vel.X) * timefrac;
@ -940,8 +943,8 @@ void GLSprite::ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t *
else factor = 1 / 7.f;
float scalefac=particle->size * factor;
float viewvecX = di->mViewVector.X;
float viewvecY = di->mViewVector.Y;
float viewvecX = vp.ViewVector.X;
float viewvecY = vp.ViewVector.Y;
x1=x+viewvecY*scalefac;
x2=x-viewvecY*scalefac;
@ -950,7 +953,7 @@ void GLSprite::ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t *
z1=z-scalefac;
z2=z+scalefac;
depth = FloatToFixed((x - r_viewpoint.Pos.X) * r_viewpoint.TanCos + (y - r_viewpoint.Pos.Y) * r_viewpoint.TanSin);
depth = FloatToFixed((x - vp.Pos.X) * vp.TanCos + (y - vp.Pos.Y) * vp.TanSin);
actor=nullptr;
this->particle=particle;
@ -980,6 +983,7 @@ void HWDrawInfo::ProcessActorsInPortal(FLinePortalSpan *glport, area_t in_area)
TMap<AActor*, bool> processcheck;
if (glport->validcount == validcount) return; // only process once per frame
glport->validcount = validcount;
const auto &vp = Viewpoint;
for (auto port : glport->lines)
{
line_t *line = port->mOrigin;
@ -1003,9 +1007,9 @@ void HWDrawInfo::ProcessActorsInPortal(FLinePortalSpan *glport, area_t in_area)
DVector3 newpos = savedpos;
sector_t fakesector;
if (!r_viewpoint.showviewer && th == r_viewpoint.camera)
if (!vp.showviewer && th == vp.camera)
{
if (fabs(savedpos.X - r_viewpoint.ActorPos.X) < 2 && fabs(savedpos.Y - r_viewpoint.ActorPos.Y) < 2)
if (fabs(savedpos.X - vp.ActorPos.X) < 2 && fabs(savedpos.Y - vp.ActorPos.Y) < 2)
{
continue;
}

View file

@ -0,0 +1,30 @@
#pragma once
#include "r_data/matrix.h"
#include "r_utility.h"
struct HWViewpointUniforms
{
VSMatrix mProjectionMatrix;
VSMatrix mViewMatrix;
VSMatrix mNormalViewMatrix;
FVector4 mCameraPos;
FVector4 mClipLine;
float mGlobVis = 1.f;
int mPalLightLevels = 0;
int mViewHeight = 0;
float mClipHeight = 0.f;
float mClipHeightDirection = 0.f;
void CalcDependencies()
{
mNormalViewMatrix.computeNormalMatrix(mViewMatrix);
}
void SetDefaults();
};

View file

@ -169,7 +169,7 @@ void GLWall::PutWall(HWDrawInfo *di, bool translucent)
if (translucent)
{
flags |= GLWF_TRANSLUCENT;
ViewDistance = (r_viewpoint.Pos - (seg->linedef->v1->fPos() + seg->linedef->Delta() / 2)).XY().LengthSquared();
ViewDistance = (di->Viewpoint.Pos - (seg->linedef->v1->fPos() + seg->linedef->Delta() / 2)).XY().LengthSquared();
}
if (di->isFullbrightScene())
@ -443,10 +443,11 @@ bool GLWall::DoHorizon(HWDrawInfo *di, seg_t * seg,sector_t * fs, vertex_t * v1,
ztop[1] = ztop[0] = fs->GetPlaneTexZ(sector_t::ceiling);
zbottom[1] = zbottom[0] = fs->GetPlaneTexZ(sector_t::floor);
if (r_viewpoint.Pos.Z < fs->GetPlaneTexZ(sector_t::ceiling))
auto vpz = di->Viewpoint.Pos.Z;
if (vpz < fs->GetPlaneTexZ(sector_t::ceiling))
{
if (r_viewpoint.Pos.Z > fs->GetPlaneTexZ(sector_t::floor))
zbottom[1] = zbottom[0] = r_viewpoint.Pos.Z;
if (vpz > fs->GetPlaneTexZ(sector_t::floor))
zbottom[1] = zbottom[0] = vpz;
if (fs->GetTexture(sector_t::ceiling) == skyflatnum)
{
@ -474,7 +475,7 @@ bool GLWall::DoHorizon(HWDrawInfo *di, seg_t * seg,sector_t * fs, vertex_t * v1,
ztop[1] = ztop[0] = zbottom[0];
}
if (r_viewpoint.Pos.Z > fs->GetPlaneTexZ(sector_t::floor))
if (vpz > fs->GetPlaneTexZ(sector_t::floor))
{
zbottom[1] = zbottom[0] = fs->GetPlaneTexZ(sector_t::floor);
if (fs->GetTexture(sector_t::floor) == skyflatnum)
@ -1457,7 +1458,7 @@ void GLWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_
sector_t * segback;
#ifdef _DEBUG
if (seg->linedef->Index() == 10)
if (seg->linedef->Index() == 3407)
{
int a = 0;
}

View file

@ -76,10 +76,10 @@ static bool isBright(DPSprite *psp)
//
//==========================================================================
static WeaponPosition GetWeaponPosition(player_t *player)
static WeaponPosition GetWeaponPosition(player_t *player, double ticFrac)
{
WeaponPosition w;
P_BobWeapon(player, &w.bobx, &w.boby, r_viewpoint.TicFrac);
P_BobWeapon(player, &w.bobx, &w.boby, ticFrac);
// Interpolate the main weapon layer once so as to be able to add it to other layers.
if ((w.weapon = player->FindPSprite(PSP_WEAPON)) != nullptr)
@ -91,8 +91,8 @@ static WeaponPosition GetWeaponPosition(player_t *player)
}
else
{
w.wx = (float)(w.weapon->oldx + (w.weapon->x - w.weapon->oldx) * r_viewpoint.TicFrac);
w.wy = (float)(w.weapon->oldy + (w.weapon->y - w.weapon->oldy) * r_viewpoint.TicFrac);
w.wx = (float)(w.weapon->oldx + (w.weapon->x - w.weapon->oldx) * ticFrac);
w.wy = (float)(w.weapon->oldy + (w.weapon->y - w.weapon->oldy) * ticFrac);
}
}
else
@ -109,7 +109,7 @@ static WeaponPosition GetWeaponPosition(player_t *player)
//
//==========================================================================
static FVector2 BobWeapon(WeaponPosition &weap, DPSprite *psp)
static FVector2 BobWeapon(WeaponPosition &weap, DPSprite *psp, double ticFrac)
{
if (psp->firstTic)
{ // Can't interpolate the first tic.
@ -118,8 +118,8 @@ static FVector2 BobWeapon(WeaponPosition &weap, DPSprite *psp)
psp->oldy = psp->y;
}
float sx = float(psp->oldx + (psp->x - psp->oldx) * r_viewpoint.TicFrac);
float sy = float(psp->oldy + (psp->y - psp->oldy) * r_viewpoint.TicFrac);
float sx = float(psp->oldx + (psp->x - psp->oldx) * ticFrac);
float sy = float(psp->oldy + (psp->y - psp->oldy) * ticFrac);
if (psp->Flags & PSPF_ADDBOB)
{
@ -169,14 +169,14 @@ static WeaponLighting GetWeaponLighting(sector_t *viewsector, const DVector3 &po
if (i<lightlist.Size() - 1)
{
lightbottom = lightlist[i + 1].plane.ZatPoint(r_viewpoint.Pos);
lightbottom = lightlist[i + 1].plane.ZatPoint(pos);
}
else
{
lightbottom = viewsector->floorplane.ZatPoint(r_viewpoint.Pos);
lightbottom = viewsector->floorplane.ZatPoint(pos);
}
if (lightbottom<r_viewpoint.Pos.Z)
if (lightbottom < pos.Z)
{
l.cm = lightlist[i].extra_colormap;
l.lightlevel = hw_ClampLight(*lightlist[i].p_lightlevel);
@ -426,8 +426,10 @@ void HWDrawInfo::PreparePlayerSprites(sector_t * viewsector, area_t in_area)
AActor * playermo = players[consoleplayer].camera;
player_t * player = playermo->player;
const bool hudModelStep = IsHUDModelForPlayerAvailable(player);
const auto &vp = Viewpoint;
AActor *camera = r_viewpoint.camera;
AActor *camera = vp.camera;
// this is the same as the software renderer
if (!player ||
@ -437,8 +439,8 @@ void HWDrawInfo::PreparePlayerSprites(sector_t * viewsector, area_t in_area)
(r_deathcamera && camera->health <= 0))
return;
WeaponPosition weap = GetWeaponPosition(camera->player);
WeaponLighting light = GetWeaponLighting(viewsector, r_viewpoint.Pos, isFullbrightScene(), in_area, camera->Pos());
WeaponPosition weap = GetWeaponPosition(camera->player, vp.TicFrac);
WeaponLighting light = GetWeaponLighting(viewsector, vp.Pos, isFullbrightScene(), in_area, camera->Pos());
// hack alert! Rather than changing everything in the underlying lighting code let's just temporarily change
// light mode here to draw the weapon sprite.
@ -460,7 +462,7 @@ void HWDrawInfo::PreparePlayerSprites(sector_t * viewsector, area_t in_area)
if (!hudsprite.GetWeaponRenderStyle(psp, camera, viewsector, light)) continue;
FVector2 spos = BobWeapon(weap, psp);
FVector2 spos = BobWeapon(weap, psp, vp.TicFrac);
hudsprite.dynrgb[0] = hudsprite.dynrgb[1] = hudsprite.dynrgb[2] = 0;
hudsprite.lightindex = -1;
@ -505,7 +507,7 @@ void HWDrawInfo::PrepareTargeterSprites()
{
AActor * playermo = players[consoleplayer].camera;
player_t * player = playermo->player;
AActor *camera = r_viewpoint.camera;
AActor *camera = Viewpoint.camera;
// this is the same as above
if (!player ||

View file

@ -8,6 +8,7 @@ class AActor;
enum area_t : int;
struct FSpriteModelFrame;
struct HWDrawInfo;
class FMaterial;
struct WeaponPosition

View file

@ -160,8 +160,9 @@ void CheckBench()
FString compose;
auto &vp = r_viewpoint;
compose.Format("Map %s: \"%s\",\nx = %1.4f, y = %1.4f, z = %1.4f, angle = %1.4f, pitch = %1.4f\n",
level.MapName.GetChars(), level.LevelName.GetChars(), r_viewpoint.Pos.X, r_viewpoint.Pos.Y, r_viewpoint.Pos.Z, r_viewpoint.Angles.Yaw.Degrees, r_viewpoint.Angles.Pitch.Degrees);
level.MapName.GetChars(), level.LevelName.GetChars(), vp.Pos.X, vp.Pos.Y, vp.Pos.Z, vp.Angles.Yaw.Degrees, vp.Angles.Pitch.Degrees);
AppendRenderStats(compose);
AppendRenderTimes(compose);

View file

@ -25,6 +25,7 @@
#include "c_dispatch.h"
#include "v_video.h"
#include "hw_cvars.h"
#include "hwrenderer/textures/hw_material.h"
#include "menu/menu.h"
@ -91,7 +92,7 @@ CUSTOM_CVAR(Float,gl_texture_filter_anisotropic,8.0f,CVAR_ARCHIVE|CVAR_GLOBALCON
CCMD(gl_flush)
{
screen->FlushTextures();
FMaterial::FlushAll();
}
CUSTOM_CVAR(Int, gl_texture_filter, 4, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
@ -102,7 +103,7 @@ CUSTOM_CVAR(Int, gl_texture_filter, 4, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINI
CUSTOM_CVAR(Bool, gl_texture_usehires, true, CVAR_ARCHIVE|CVAR_NOINITCALL)
{
screen->FlushTextures();
FMaterial::FlushAll();
}
CVAR(Bool, gl_precache, false, CVAR_ARCHIVE)

View file

@ -0,0 +1,176 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2015 Christopher Bruns
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** gl_stereo_leftright.cpp
** Offsets for left and right eye views
**
*/
#include "vectors.h" // RAD2DEG
#include "doomtype.h" // M_PI
#include "hwrenderer/utility/hw_cvars.h"
#include "hw_vrmodes.h"
#include "v_video.h"
// Set up 3D-specific console variables:
CVAR(Int, vr_mode, 0, CVAR_GLOBALCONFIG)
// switch left and right eye views
CVAR(Bool, vr_swap_eyes, false, CVAR_GLOBALCONFIG)
// intraocular distance in meters
CVAR(Float, vr_ipd, 0.062f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // METERS
// distance between viewer and the display screen
CVAR(Float, vr_screendist, 0.80f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS
// default conversion between (vertical) DOOM units and meters
CVAR(Float, vr_hunits_per_meter, 41.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS
#define isqrt2 0.7071067812f
static VRMode vrmi_mono = { 1, 1.f, 1.f, 1.f,{ { 0.f, 1.f },{ 0.f, 0.f } } };
static VRMode vrmi_stereo = { 2, 1.f, 1.f, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } };
static VRMode vrmi_sbsfull = { 2, .5f, 1.f, 2.f,{ { -.5f, .5f },{ .5f, .5f } } };
static VRMode vrmi_sbssquished = { 2, .5f, 1.f, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } };
static VRMode vrmi_lefteye = { 1, 1.f, 1.f, 1.f, { { -.5f, 1.f },{ 0.f, 0.f } } };
static VRMode vrmi_righteye = { 1, 1.f, 1.f, 1.f,{ { .5f, 1.f },{ 0.f, 0.f } } };
static VRMode vrmi_topbottom = { 2, 1.f, .5f, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } };
static VRMode vrmi_checker = { 2, isqrt2, isqrt2, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } };
const VRMode *VRMode::GetVRMode(bool toscreen)
{
switch (toscreen && vid_rendermode == 4 ? vr_mode : 0)
{
default:
case VR_MONO:
return &vrmi_mono;
case VR_GREENMAGENTA:
case VR_REDCYAN:
case VR_QUADSTEREO:
case VR_AMBERBLUE:
return &vrmi_stereo;
case VR_SIDEBYSIDESQUISHED:
case VR_COLUMNINTERLEAVED:
return &vrmi_sbssquished;
case VR_SIDEBYSIDEFULL:
return &vrmi_sbsfull;
case VR_TOPBOTTOM:
case VR_ROWINTERLEAVED:
return &vrmi_topbottom;
case VR_LEFTEYEVIEW:
return &vrmi_lefteye;
case VR_RIGHTEYEVIEW:
return &vrmi_righteye;
case VR_CHECKERINTERLEAVED:
return &vrmi_checker;
}
}
void VRMode::AdjustViewport(DFrameBuffer *screen) const
{
screen->mSceneViewport.height = (int)(screen->mSceneViewport.height * mVerticalViewportScale);
screen->mSceneViewport.top = (int)(screen->mSceneViewport.top * mVerticalViewportScale);
screen->mSceneViewport.width = (int)(screen->mSceneViewport.width * mHorizontalViewportScale);
screen->mSceneViewport.left = (int)(screen->mSceneViewport.left * mHorizontalViewportScale);
screen->mScreenViewport.height = (int)(screen->mScreenViewport.height * mVerticalViewportScale);
screen->mScreenViewport.top = (int)(screen->mScreenViewport.top * mVerticalViewportScale);
screen->mScreenViewport.width = (int)(screen->mScreenViewport.width * mHorizontalViewportScale);
screen->mScreenViewport.left = (int)(screen->mScreenViewport.left * mHorizontalViewportScale);
}
VSMatrix VRMode::GetHUDSpriteProjection() const
{
VSMatrix mat;
int w = screen->GetWidth();
int h = screen->GetHeight();
float scaled_w = w / mWeaponProjectionScale;
float left_ofs = (w - scaled_w) / 2.f;
mat.ortho(left_ofs, left_ofs + scaled_w, (float)h, 0, -1.0f, 1.0f);
return mat;
}
float VREyeInfo::getShift() const
{
auto res = mShiftFactor * vr_ipd;
return vr_swap_eyes ? -res : res;
}
VSMatrix VREyeInfo::GetProjection(float fov, float aspectRatio, float fovRatio) const
{
VSMatrix result;
if (mShiftFactor == 0)
{
float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio)));
result.perspective(fovy, aspectRatio, screen->GetZNear(), screen->GetZFar());
return result;
}
else
{
double zNear = screen->GetZNear();
double zFar = screen->GetZFar();
// For stereo 3D, use asymmetric frustum shift in projection matrix
// Q: shouldn't shift vary with roll angle, at least for desktop display?
// A: No. (lab) roll is not measured on desktop display (yet)
double frustumShift = zNear * getShift() / vr_screendist; // meters cancel, leaving doom units
// double frustumShift = 0; // Turning off shift for debugging
double fH = zNear * tan(DEG2RAD(fov) / 2) / fovRatio;
double fW = fH * aspectRatio * mScaleFactor;
double left = -fW - frustumShift;
double right = fW - frustumShift;
double bottom = -fH;
double top = fH;
VSMatrix result(1);
result.frustum((float)left, (float)right, (float)bottom, (float)top, (float)zNear, (float)zFar);
return result;
}
}
/* virtual */
DVector3 VREyeInfo::GetViewShift(float yaw) const
{
if (mShiftFactor == 0)
{
// pass-through for Mono view
return { 0,0,0 };
}
else
{
double dx = -cos(DEG2RAD(yaw)) * vr_hunits_per_meter * getShift();
double dy = sin(DEG2RAD(yaw)) * vr_hunits_per_meter * getShift();
return { dx, dy, 0 };
}
}

View file

@ -0,0 +1,47 @@
#pragma once
#include "r_data/matrix.h"
class DFrameBuffer;
enum
{
VR_MONO = 0,
VR_GREENMAGENTA = 1,
VR_REDCYAN = 2,
VR_SIDEBYSIDEFULL = 3,
VR_SIDEBYSIDESQUISHED = 4,
VR_LEFTEYEVIEW = 5,
VR_RIGHTEYEVIEW = 6,
VR_QUADSTEREO = 7,
VR_AMBERBLUE = 9,
VR_TOPBOTTOM = 11,
VR_ROWINTERLEAVED = 12,
VR_COLUMNINTERLEAVED = 13,
VR_CHECKERINTERLEAVED = 14
};
struct VREyeInfo
{
float mShiftFactor;
float mScaleFactor;
VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const;
DVector3 GetViewShift(float yaw) const;
private:
float getShift() const;
};
struct VRMode
{
int mEyeCount;
float mHorizontalViewportScale;
float mVerticalViewportScale;
float mWeaponProjectionScale;
VREyeInfo mEyes[2];
static const VRMode *GetVRMode(bool toscreen = true);
void AdjustViewport(DFrameBuffer *fb) const;
VSMatrix GetHUDSpriteProjection() const;
};

View file

@ -1,62 +0,0 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2015 Christopher Bruns
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** scoped_view_shifter.h
** Stack-scoped class for temporarily changing camera viewpoint
** Used for stereoscopic 3D.
**
*/
#ifndef GL_STEREO3D_SCOPED_VIEW_SHIFTER_H_
#define GL_STEREO3D_SCOPED_VIEW_SHIFTER_H_
#include "basictypes.h"
#include "vectors.h"
/**
* Temporarily shift
*/
class ScopedViewShifter
{
public:
ScopedViewShifter(DVector3 &var, float dxyz[3]) // in meters
{
// save original values
mVar = &var;
cachedView = var;
// modify values
var += DVector3(dxyz[0], dxyz[1], dxyz[2]);
}
~ScopedViewShifter()
{
// restore original values
*mVar = cachedView;
}
private:
DVector3 *mVar;
DVector3 cachedView;
};
#endif // GL_STEREO3D_SCOPED_VIEW_SHIFTER_H_