2016-09-14 18:01:13 +00:00
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Copyright(C) 2004-2016 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/
|
|
|
|
|
//
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
//
|
2013-06-23 07:49:34 +00:00
|
|
|
|
/*
|
|
|
|
|
** gl_portal.cpp
|
|
|
|
|
** Generalized portal maintenance classes for skyboxes, horizons etc.
|
|
|
|
|
**
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "gl/system/gl_system.h"
|
|
|
|
|
#include "p_local.h"
|
|
|
|
|
#include "vectors.h"
|
|
|
|
|
#include "c_dispatch.h"
|
|
|
|
|
#include "doomstat.h"
|
|
|
|
|
#include "a_sharedglobal.h"
|
2016-01-11 14:07:58 +00:00
|
|
|
|
#include "r_sky.h"
|
2016-02-06 11:32:47 +00:00
|
|
|
|
#include "portal.h"
|
2016-02-16 21:01:04 +00:00
|
|
|
|
#include "p_maputl.h"
|
|
|
|
|
#include "d_player.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
2013-09-03 16:29:39 +00:00
|
|
|
|
#include "gl/system/gl_interface.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
|
#include "gl/system/gl_framebuffer.h"
|
|
|
|
|
#include "gl/system/gl_cvars.h"
|
|
|
|
|
#include "gl/renderer/gl_lightdata.h"
|
2014-05-11 19:47:54 +00:00
|
|
|
|
#include "gl/renderer/gl_renderer.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
|
#include "gl/renderer/gl_renderstate.h"
|
2016-09-03 23:46:29 +00:00
|
|
|
|
#include "gl/renderer/gl_quaddrawer.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
|
#include "gl/dynlights/gl_glow.h"
|
|
|
|
|
#include "gl/data/gl_data.h"
|
2014-05-31 07:32:17 +00:00
|
|
|
|
#include "gl/data/gl_vertexbuffer.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
|
#include "gl/scene/gl_clipper.h"
|
|
|
|
|
#include "gl/scene/gl_drawinfo.h"
|
|
|
|
|
#include "gl/scene/gl_portal.h"
|
|
|
|
|
#include "gl/shaders/gl_shader.h"
|
2015-10-31 00:51:35 +00:00
|
|
|
|
#include "gl/stereo3d/scoped_color_mask.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
|
#include "gl/textures/gl_material.h"
|
|
|
|
|
#include "gl/utility/gl_clock.h"
|
|
|
|
|
#include "gl/utility/gl_templates.h"
|
|
|
|
|
#include "gl/utility/gl_geometric.h"
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// General portal handling code
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
EXTERN_CVAR(Bool, gl_portals)
|
|
|
|
|
EXTERN_CVAR(Bool, gl_noquery)
|
|
|
|
|
EXTERN_CVAR(Int, r_mirror_recursions)
|
|
|
|
|
|
2016-02-26 11:09:59 +00:00
|
|
|
|
extern bool r_showviewer;
|
|
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
|
TArray<GLPortal *> GLPortal::portals;
|
2014-07-13 10:14:12 +00:00
|
|
|
|
TArray<float> GLPortal::planestack;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
int GLPortal::recursion;
|
|
|
|
|
int GLPortal::MirrorFlag;
|
|
|
|
|
int GLPortal::PlaneMirrorFlag;
|
|
|
|
|
int GLPortal::renderdepth;
|
|
|
|
|
int GLPortal::PlaneMirrorMode;
|
|
|
|
|
GLuint GLPortal::QueryObject;
|
|
|
|
|
|
|
|
|
|
int GLPortal::instack[2];
|
|
|
|
|
bool GLPortal::inskybox;
|
|
|
|
|
|
|
|
|
|
UniqueList<GLSkyInfo> UniqueSkies;
|
|
|
|
|
UniqueList<GLHorizonInfo> UniqueHorizons;
|
|
|
|
|
UniqueList<secplane_t> UniquePlaneMirrors;
|
2016-03-04 13:10:13 +00:00
|
|
|
|
UniqueList<FGLLinePortal> UniqueLineToLines;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
2016-04-30 14:57:53 +00:00
|
|
|
|
void gl_RenderActorsInPortal(FGLLinePortal *glport);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
|
|
void GLPortal::BeginScene()
|
|
|
|
|
{
|
|
|
|
|
UniqueSkies.Clear();
|
|
|
|
|
UniqueHorizons.Clear();
|
|
|
|
|
UniquePlaneMirrors.Clear();
|
2016-02-06 04:17:47 +00:00
|
|
|
|
UniqueLineToLines.Clear();
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
|
|
|
|
void GLPortal::ClearScreen()
|
|
|
|
|
{
|
2013-09-03 12:05:41 +00:00
|
|
|
|
bool multi = !!glIsEnabled(GL_MULTISAMPLE);
|
2014-07-13 20:37:34 +00:00
|
|
|
|
gl_MatrixStack.Push(gl_RenderState.mViewMatrix);
|
|
|
|
|
gl_MatrixStack.Push(gl_RenderState.mProjectionMatrix);
|
2016-09-03 23:46:29 +00:00
|
|
|
|
|
|
|
|
|
gl_RenderState.mViewMatrix.loadIdentity();
|
|
|
|
|
gl_RenderState.mProjectionMatrix.ortho(0, SCREENWIDTH, SCREENHEIGHT, 0, -1.0f, 1.0f);
|
|
|
|
|
gl_RenderState.ApplyMatrices();
|
|
|
|
|
|
|
|
|
|
glDisable(GL_MULTISAMPLE);
|
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
|
|
2016-09-06 09:58:22 +00:00
|
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, FFlatVertexBuffer::FULLSCREEN_INDEX, 4);
|
2016-09-03 23:46:29 +00:00
|
|
|
|
|
2013-09-03 12:05:41 +00:00
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
2014-07-13 20:37:34 +00:00
|
|
|
|
gl_MatrixStack.Pop(gl_RenderState.mProjectionMatrix);
|
|
|
|
|
gl_MatrixStack.Pop(gl_RenderState.mViewMatrix);
|
|
|
|
|
gl_RenderState.ApplyMatrices();
|
2013-09-03 12:05:41 +00:00
|
|
|
|
if (multi) glEnable(GL_MULTISAMPLE);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// DrawPortalStencil
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void GLPortal::DrawPortalStencil()
|
|
|
|
|
{
|
2014-06-15 08:15:44 +00:00
|
|
|
|
if (mPrimIndices.Size() == 0)
|
2013-06-23 07:49:34 +00:00
|
|
|
|
{
|
2016-08-25 22:01:51 +00:00
|
|
|
|
mPrimIndices.Resize(2 * lines.Size());
|
2014-06-15 08:15:44 +00:00
|
|
|
|
|
2016-08-25 22:01:51 +00:00
|
|
|
|
for (unsigned int i = 0; i < lines.Size(); i++)
|
2014-05-31 07:32:17 +00:00
|
|
|
|
{
|
2016-08-25 21:02:43 +00:00
|
|
|
|
if (gl.buffermethod != BM_DEFERRED) lines[i].MakeVertices(false);
|
|
|
|
|
mPrimIndices[i * 2] = lines[i].vertindex;
|
|
|
|
|
mPrimIndices[i * 2 + 1] = lines[i].vertcount;
|
2014-05-31 07:32:17 +00:00
|
|
|
|
}
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
2014-06-15 08:30:03 +00:00
|
|
|
|
gl_RenderState.Apply();
|
2014-06-15 08:15:44 +00:00
|
|
|
|
for (unsigned int i = 0; i < mPrimIndices.Size(); i += 2)
|
2013-06-23 07:49:34 +00:00
|
|
|
|
{
|
2014-06-15 08:15:44 +00:00
|
|
|
|
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_FAN, mPrimIndices[i], mPrimIndices[i + 1]);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
2016-08-25 22:01:51 +00:00
|
|
|
|
if (NeedCap() && lines.Size() > 1)
|
|
|
|
|
{
|
2016-08-29 08:43:03 +00:00
|
|
|
|
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_FAN, FFlatVertexBuffer::STENCILTOP_INDEX, 4);
|
|
|
|
|
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_FAN, FFlatVertexBuffer::STENCILBOTTOM_INDEX, 4);
|
2016-08-25 22:01:51 +00:00
|
|
|
|
}
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-05-31 07:32:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Start
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
bool GLPortal::Start(bool usestencil, bool doquery)
|
|
|
|
|
{
|
|
|
|
|
rendered_portals++;
|
2016-09-25 23:38:25 +00:00
|
|
|
|
// PortalAll.Clock();
|
2013-06-23 07:49:34 +00:00
|
|
|
|
if (usestencil)
|
|
|
|
|
{
|
|
|
|
|
if (!gl_portals)
|
|
|
|
|
{
|
2016-09-25 23:38:25 +00:00
|
|
|
|
// PortalAll.Unclock();
|
2013-06-23 07:49:34 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create stencil
|
2013-09-03 12:05:41 +00:00
|
|
|
|
glStencilFunc(GL_EQUAL,recursion,~0); // create stencil
|
2015-10-31 01:48:42 +00:00
|
|
|
|
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // increment stencil of valid pixels
|
2013-06-23 07:49:34 +00:00
|
|
|
|
{
|
2015-10-31 01:48:42 +00:00
|
|
|
|
ScopedColorMask colorMask(0, 0, 0, 0); // glColorMask(0,0,0,0); // don't write to the graphics buffer
|
|
|
|
|
gl_RenderState.SetEffect(EFF_STENCIL);
|
|
|
|
|
gl_RenderState.EnableTexture(false);
|
|
|
|
|
gl_RenderState.ResetColor();
|
|
|
|
|
glDepthFunc(GL_LESS);
|
|
|
|
|
gl_RenderState.Apply();
|
2015-10-31 01:29:36 +00:00
|
|
|
|
|
2015-10-31 01:48:42 +00:00
|
|
|
|
if (NeedDepthBuffer())
|
2013-06-23 07:49:34 +00:00
|
|
|
|
{
|
2015-10-31 01:48:42 +00:00
|
|
|
|
glDepthMask(false); // don't write to Z-buffer!
|
|
|
|
|
if (!NeedDepthBuffer()) doquery = false; // too much overhead and nothing to gain.
|
|
|
|
|
else if (gl_noquery) doquery = false;
|
|
|
|
|
|
|
|
|
|
// If occlusion query is supported let's use it to avoid rendering portals that aren't visible
|
2016-02-06 04:17:47 +00:00
|
|
|
|
if (!QueryObject && doquery) glGenQueries(1, &QueryObject);
|
2015-10-31 01:48:42 +00:00
|
|
|
|
if (QueryObject)
|
|
|
|
|
{
|
|
|
|
|
glBeginQuery(GL_SAMPLES_PASSED, QueryObject);
|
|
|
|
|
}
|
|
|
|
|
else doquery = false; // some kind of error happened
|
2015-10-31 00:51:35 +00:00
|
|
|
|
|
2015-10-31 01:48:42 +00:00
|
|
|
|
DrawPortalStencil();
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
2015-10-31 01:48:42 +00:00
|
|
|
|
glEndQuery(GL_SAMPLES_PASSED);
|
2014-04-06 12:35:44 +00:00
|
|
|
|
|
2015-10-31 01:48:42 +00:00
|
|
|
|
// Clear Z-buffer
|
|
|
|
|
glStencilFunc(GL_EQUAL, recursion + 1, ~0); // draw sky into stencil
|
|
|
|
|
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // this stage doesn't modify the stencil
|
|
|
|
|
glDepthMask(true); // enable z-buffer again
|
|
|
|
|
glDepthRange(1, 1);
|
|
|
|
|
glDepthFunc(GL_ALWAYS);
|
|
|
|
|
DrawPortalStencil();
|
2014-04-06 12:35:44 +00:00
|
|
|
|
|
2015-10-31 01:48:42 +00:00
|
|
|
|
// set normal drawing mode
|
|
|
|
|
gl_RenderState.EnableTexture(true);
|
|
|
|
|
glDepthFunc(GL_LESS);
|
|
|
|
|
// glColorMask(1, 1, 1, 1);
|
|
|
|
|
gl_RenderState.SetEffect(EFF_NONE);
|
|
|
|
|
glDepthRange(0, 1);
|
|
|
|
|
|
|
|
|
|
GLuint sampleCount;
|
|
|
|
|
|
2016-02-06 04:17:47 +00:00
|
|
|
|
if (QueryObject)
|
2015-10-31 01:48:42 +00:00
|
|
|
|
{
|
2016-02-06 04:17:47 +00:00
|
|
|
|
glGetQueryObjectuiv(QueryObject, GL_QUERY_RESULT, &sampleCount);
|
|
|
|
|
|
|
|
|
|
if (sampleCount == 0) // not visible
|
|
|
|
|
{
|
|
|
|
|
// restore default stencil op.
|
|
|
|
|
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
|
|
|
|
glStencilFunc(GL_EQUAL, recursion, ~0); // draw sky into stencil
|
|
|
|
|
PortalAll.Unclock();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-10-31 01:48:42 +00:00
|
|
|
|
}
|
|
|
|
|
FDrawInfo::StartDrawInfo();
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
2015-10-31 01:48:42 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// No z-buffer is needed therefore we can skip all the complicated stuff that is involved
|
|
|
|
|
// No occlusion queries will be done here. For these portals the overhead is far greater
|
|
|
|
|
// than the benefit.
|
|
|
|
|
// Note: We must draw the stencil with z-write enabled here because there is no second pass!
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
2015-10-31 01:48:42 +00:00
|
|
|
|
glDepthMask(true);
|
|
|
|
|
DrawPortalStencil();
|
|
|
|
|
glStencilFunc(GL_EQUAL, recursion + 1, ~0); // draw sky into stencil
|
|
|
|
|
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // this stage doesn't modify the stencil
|
|
|
|
|
gl_RenderState.EnableTexture(true);
|
|
|
|
|
// glColorMask(1,1,1,1);
|
|
|
|
|
gl_RenderState.SetEffect(EFF_NONE);
|
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
|
glDepthMask(false); // don't write to Z-buffer!
|
|
|
|
|
}
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
|
|
|
|
recursion++;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (NeedDepthBuffer())
|
|
|
|
|
{
|
|
|
|
|
FDrawInfo::StartDrawInfo();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-09-03 12:05:41 +00:00
|
|
|
|
glDepthMask(false);
|
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// save viewpoint
|
2016-04-02 21:17:16 +00:00
|
|
|
|
savedViewPos = ViewPos;
|
2016-12-29 21:19:09 +00:00
|
|
|
|
savedViewActorPos = ViewActorPos;
|
|
|
|
|
savedshowviewer = r_showviewer;
|
2016-04-02 21:17:16 +00:00
|
|
|
|
savedAngle = ViewAngle;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
savedviewactor=GLRenderer->mViewActor;
|
|
|
|
|
savedviewarea=in_area;
|
2017-01-07 00:07:35 +00:00
|
|
|
|
savedviewpath[0] = ViewPath[0];
|
|
|
|
|
savedviewpath[1] = ViewPath[1];
|
|
|
|
|
savedvisibility = camera ? camera->renderflags & RF_MAYBEINVISIBLE : ActorRenderFlags::FromInt(0);
|
2016-06-18 10:14:20 +00:00
|
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
2016-04-28 23:48:06 +00:00
|
|
|
|
PrevPortal = GLRenderer->mCurrentPortal;
|
|
|
|
|
PrevClipPortal = GLRenderer->mClipPortal;
|
|
|
|
|
GLRenderer->mClipPortal = NULL; // Portals which need this have to set it themselves
|
|
|
|
|
GLRenderer->mCurrentPortal = this;
|
|
|
|
|
|
|
|
|
|
if (PrevPortal != NULL) PrevPortal->PushState();
|
2016-09-25 23:38:25 +00:00
|
|
|
|
// PortalAll.Unclock();
|
2013-06-23 07:49:34 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inline void GLPortal::ClearClipper()
|
|
|
|
|
{
|
2016-04-02 21:17:16 +00:00
|
|
|
|
DAngle angleOffset = deltaangle(savedAngle, ViewAngle);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
clipper.Clear();
|
|
|
|
|
|
|
|
|
|
static int call=0;
|
|
|
|
|
|
|
|
|
|
// Set the clipper to the minimal visible area
|
|
|
|
|
clipper.SafeAddClipRange(0,0xffffffff);
|
2016-04-02 21:17:16 +00:00
|
|
|
|
for (unsigned int i = 0; i < lines.Size(); i++)
|
2013-06-23 07:49:34 +00:00
|
|
|
|
{
|
2016-04-02 21:17:16 +00:00
|
|
|
|
DAngle startAngle = (DVector2(lines[i].glseg.x2, lines[i].glseg.y2) - savedViewPos).Angle() + angleOffset;
|
|
|
|
|
DAngle endAngle = (DVector2(lines[i].glseg.x1, lines[i].glseg.y1) - savedViewPos).Angle() + angleOffset;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
2016-04-02 21:17:16 +00:00
|
|
|
|
if (deltaangle(endAngle, startAngle) < 0)
|
2013-06-23 07:49:34 +00:00
|
|
|
|
{
|
2016-04-02 21:17:16 +00:00
|
|
|
|
clipper.SafeRemoveClipRangeRealAngles(startAngle.BAMs(), endAngle.BAMs());
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// and finally clip it to the visible area
|
|
|
|
|
angle_t a1 = GLRenderer->FrustumAngle();
|
2016-04-02 21:17:16 +00:00
|
|
|
|
if (a1 < ANGLE_180) clipper.SafeAddClipRangeRealAngles(ViewAngle.BAMs() + a1, ViewAngle.BAMs() - a1);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
// lock the parts that have just been clipped out.
|
|
|
|
|
clipper.SetSilhouette();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// End
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void GLPortal::End(bool usestencil)
|
|
|
|
|
{
|
|
|
|
|
bool needdepth = NeedDepthBuffer();
|
|
|
|
|
|
|
|
|
|
PortalAll.Clock();
|
2016-04-28 23:48:06 +00:00
|
|
|
|
if (PrevPortal != NULL) PrevPortal->PopState();
|
|
|
|
|
GLRenderer->mCurrentPortal = PrevPortal;
|
|
|
|
|
GLRenderer->mClipPortal = PrevClipPortal;
|
2014-07-13 10:14:12 +00:00
|
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
|
if (usestencil)
|
|
|
|
|
{
|
|
|
|
|
if (needdepth) FDrawInfo::EndDrawInfo();
|
|
|
|
|
|
|
|
|
|
// Restore the old view
|
2017-01-07 00:07:35 +00:00
|
|
|
|
ViewPath[0] = savedviewpath[0];
|
|
|
|
|
ViewPath[1] = savedviewpath[1];
|
2016-04-02 21:17:16 +00:00
|
|
|
|
ViewPos = savedViewPos;
|
2016-12-29 21:19:09 +00:00
|
|
|
|
r_showviewer = savedshowviewer;
|
|
|
|
|
ViewActorPos = savedViewActorPos;
|
2016-04-02 21:17:16 +00:00
|
|
|
|
ViewAngle = savedAngle;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
GLRenderer->mViewActor=savedviewactor;
|
|
|
|
|
in_area=savedviewarea;
|
2017-01-07 00:07:35 +00:00
|
|
|
|
if (camera != nullptr) camera->renderflags = (camera->renderflags & ~RF_MAYBEINVISIBLE) | savedvisibility;
|
2016-04-02 21:17:16 +00:00
|
|
|
|
GLRenderer->SetupView(ViewPos.X, ViewPos.Y, ViewPos.Z, ViewAngle, !!(MirrorFlag & 1), !!(PlaneMirrorFlag & 1));
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
{
|
2015-10-31 01:48:42 +00:00
|
|
|
|
ScopedColorMask colorMask(0, 0, 0, 0); // glColorMask(0, 0, 0, 0); // no graphics
|
2015-10-31 00:51:35 +00:00
|
|
|
|
gl_RenderState.SetEffect(EFF_NONE);
|
|
|
|
|
gl_RenderState.ResetColor();
|
|
|
|
|
gl_RenderState.EnableTexture(false);
|
|
|
|
|
gl_RenderState.Apply();
|
|
|
|
|
|
|
|
|
|
if (needdepth)
|
|
|
|
|
{
|
|
|
|
|
// first step: reset the depth buffer to max. depth
|
|
|
|
|
glDepthRange(1, 1); // always
|
|
|
|
|
glDepthFunc(GL_ALWAYS); // write the farthest depth value
|
|
|
|
|
DrawPortalStencil();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// second step: restore the depth buffer to the previous values and reset the stencil
|
|
|
|
|
glDepthFunc(GL_LEQUAL);
|
|
|
|
|
glDepthRange(0, 1);
|
|
|
|
|
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
|
|
|
|
|
glStencilFunc(GL_EQUAL, recursion, ~0); // draw sky into stencil
|
2013-06-23 07:49:34 +00:00
|
|
|
|
DrawPortalStencil();
|
2015-10-31 00:51:35 +00:00
|
|
|
|
glDepthFunc(GL_LESS);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
|
2015-10-31 00:51:35 +00:00
|
|
|
|
gl_RenderState.EnableTexture(true);
|
|
|
|
|
gl_RenderState.SetEffect(EFF_NONE);
|
2015-10-31 01:48:42 +00:00
|
|
|
|
} // glColorMask(1, 1, 1, 1);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
recursion--;
|
|
|
|
|
|
|
|
|
|
// restore old stencil op.
|
2013-09-03 12:05:41 +00:00
|
|
|
|
glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP);
|
|
|
|
|
glStencilFunc(GL_EQUAL,recursion,~0); // draw sky into stencil
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (needdepth)
|
|
|
|
|
{
|
|
|
|
|
FDrawInfo::EndDrawInfo();
|
2013-09-03 12:05:41 +00:00
|
|
|
|
glClear(GL_DEPTH_BUFFER_BIT);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-09-03 12:05:41 +00:00
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
|
glDepthMask(true);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
|
|
|
|
// Restore the old view
|
2016-12-29 21:19:09 +00:00
|
|
|
|
r_showviewer = savedshowviewer;
|
|
|
|
|
ViewActorPos = savedViewActorPos;
|
2016-04-02 21:17:16 +00:00
|
|
|
|
ViewPos = savedViewPos;
|
|
|
|
|
ViewAngle = savedAngle;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
GLRenderer->mViewActor=savedviewactor;
|
|
|
|
|
in_area=savedviewarea;
|
2016-06-18 10:14:20 +00:00
|
|
|
|
if (camera != nullptr) camera->renderflags |= savedvisibility;
|
2016-04-02 21:17:16 +00:00
|
|
|
|
GLRenderer->SetupView(ViewPos.X, ViewPos.Y, ViewPos.Z, ViewAngle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1));
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
// This draws a valid z-buffer into the stencil's contents to ensure it
|
|
|
|
|
// doesn't get overwritten by the level's geometry.
|
|
|
|
|
|
2014-05-11 19:47:54 +00:00
|
|
|
|
gl_RenderState.ResetColor();
|
2013-09-03 12:05:41 +00:00
|
|
|
|
glDepthFunc(GL_LEQUAL);
|
2015-10-31 00:51:35 +00:00
|
|
|
|
glDepthRange(0, 1);
|
|
|
|
|
{
|
2016-09-04 06:15:29 +00:00
|
|
|
|
ScopedColorMask colorMask(0, 0, 0, 1); // mark portal in alpha channel but don't touch color
|
2015-10-31 00:51:35 +00:00
|
|
|
|
gl_RenderState.SetEffect(EFF_STENCIL);
|
|
|
|
|
gl_RenderState.EnableTexture(false);
|
2016-09-04 06:15:29 +00:00
|
|
|
|
gl_RenderState.BlendFunc(GL_ONE, GL_ZERO);
|
|
|
|
|
gl_RenderState.BlendEquation(GL_FUNC_ADD);
|
|
|
|
|
gl_RenderState.Apply();
|
2015-10-31 00:51:35 +00:00
|
|
|
|
DrawPortalStencil();
|
|
|
|
|
gl_RenderState.SetEffect(EFF_NONE);
|
|
|
|
|
gl_RenderState.EnableTexture(true);
|
2016-09-04 06:15:29 +00:00
|
|
|
|
}
|
2013-09-03 12:05:41 +00:00
|
|
|
|
glDepthFunc(GL_LESS);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
|
|
|
|
PortalAll.Unclock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// StartFrame
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void GLPortal::StartFrame()
|
|
|
|
|
{
|
|
|
|
|
GLPortal * p=NULL;
|
|
|
|
|
portals.Push(p);
|
|
|
|
|
if (renderdepth==0)
|
|
|
|
|
{
|
|
|
|
|
inskybox=false;
|
|
|
|
|
instack[sector_t::floor]=instack[sector_t::ceiling]=0;
|
|
|
|
|
}
|
|
|
|
|
renderdepth++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Portal info
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
static bool gl_portalinfo;
|
|
|
|
|
|
|
|
|
|
CCMD(gl_portalinfo)
|
|
|
|
|
{
|
|
|
|
|
gl_portalinfo = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FString indent;
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// EndFrame
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void GLPortal::EndFrame()
|
|
|
|
|
{
|
|
|
|
|
GLPortal * p;
|
|
|
|
|
|
|
|
|
|
if (gl_portalinfo)
|
|
|
|
|
{
|
|
|
|
|
Printf("%s%d portals, depth = %d\n%s{\n", indent.GetChars(), 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 = portals.Size() > 2 + (unsigned)renderdepth;
|
|
|
|
|
|
|
|
|
|
while (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);
|
|
|
|
|
}
|
|
|
|
|
delete p;
|
|
|
|
|
}
|
|
|
|
|
renderdepth--;
|
|
|
|
|
|
|
|
|
|
if (gl_portalinfo)
|
|
|
|
|
{
|
|
|
|
|
indent.Truncate(long(indent.Len()-2));
|
|
|
|
|
Printf("%s}\n", indent.GetChars());
|
|
|
|
|
if (portals.Size() == 0) gl_portalinfo = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Renders one sky portal without a stencil.
|
2016-01-11 14:07:58 +00:00
|
|
|
|
// In more complex scenes using a stencil for skies can severely stall
|
2013-06-23 07:49:34 +00:00
|
|
|
|
// the GPU and there's rarely more than one sky visible at a time.
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
bool GLPortal::RenderFirstSkyPortal(int recursion)
|
|
|
|
|
{
|
|
|
|
|
GLPortal * p;
|
|
|
|
|
GLPortal * best = NULL;
|
|
|
|
|
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.
|
|
|
|
|
for(int i = portals.Size()-1; i >= 0 && portals[i] != NULL; --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);
|
|
|
|
|
delete best;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// FindPortal
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
GLPortal * GLPortal::FindPortal(const void * src)
|
|
|
|
|
{
|
|
|
|
|
int i=portals.Size()-1;
|
|
|
|
|
|
|
|
|
|
while (i>=0 && portals[i] && portals[i]->GetSource()!=src) i--;
|
|
|
|
|
return i>=0? portals[i]:NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void GLPortal::SaveMapSection()
|
|
|
|
|
{
|
|
|
|
|
savedmapsection.Resize(currentmapsection.Size());
|
|
|
|
|
memcpy(&savedmapsection[0], ¤tmapsection[0], currentmapsection.Size());
|
|
|
|
|
memset(¤tmapsection[0], 0, currentmapsection.Size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GLPortal::RestoreMapSection()
|
|
|
|
|
{
|
|
|
|
|
memcpy(¤tmapsection[0], &savedmapsection[0], currentmapsection.Size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// Skybox Portal
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// GLSkyboxPortal::DrawContents
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
static int skyboxrecursion=0;
|
|
|
|
|
void GLSkyboxPortal::DrawContents()
|
|
|
|
|
{
|
2016-03-31 19:42:27 +00:00
|
|
|
|
int old_pm = PlaneMirrorMode;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
int saved_extralight = extralight;
|
|
|
|
|
|
2016-03-31 19:42:27 +00:00
|
|
|
|
if (skyboxrecursion >= 3)
|
2013-06-23 07:49:34 +00:00
|
|
|
|
{
|
|
|
|
|
ClearScreen();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
skyboxrecursion++;
|
2016-04-20 18:08:53 +00:00
|
|
|
|
AActor *origin = portal->mSkybox;
|
|
|
|
|
portal->mFlags |= PORTSF_INSKYBOX;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
extralight = 0;
|
|
|
|
|
|
2016-03-31 19:42:27 +00:00
|
|
|
|
PlaneMirrorMode = 0;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
2014-11-27 11:26:52 +00:00
|
|
|
|
bool oldclamp = gl_RenderState.SetDepthClamp(false);
|
2016-04-02 21:17:16 +00:00
|
|
|
|
ViewPos = origin->InterpolatedPosition(r_TicFracF);
|
2016-12-29 21:19:09 +00:00
|
|
|
|
ViewActorPos = origin->Pos();
|
2016-04-02 21:17:16 +00:00
|
|
|
|
ViewAngle += (origin->PrevAngles.Yaw + deltaangle(origin->PrevAngles.Yaw, origin->Angles.Yaw) * r_TicFracF);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
2016-01-21 11:36:37 +00:00
|
|
|
|
// Don't let the viewpoint be too close to a floor or ceiling
|
2016-03-31 19:42:27 +00:00
|
|
|
|
double floorh = origin->Sector->floorplane.ZatPoint(origin->Pos());
|
|
|
|
|
double ceilh = origin->Sector->ceilingplane.ZatPoint(origin->Pos());
|
2016-04-02 21:17:16 +00:00
|
|
|
|
if (ViewPos.Z < floorh + 4) ViewPos.Z = floorh + 4;
|
|
|
|
|
if (ViewPos.Z > ceilh - 4) ViewPos.Z = ceilh - 4;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
GLRenderer->mViewActor = origin;
|
|
|
|
|
|
2016-03-31 19:42:27 +00:00
|
|
|
|
inskybox = true;
|
2016-04-02 21:17:16 +00:00
|
|
|
|
GLRenderer->SetupView(ViewPos.X, ViewPos.Y, ViewPos.Z, ViewAngle, !!(MirrorFlag & 1), !!(PlaneMirrorFlag & 1));
|
2013-06-23 07:49:34 +00:00
|
|
|
|
GLRenderer->SetViewArea();
|
|
|
|
|
ClearClipper();
|
|
|
|
|
|
2016-04-02 21:17:16 +00:00
|
|
|
|
int mapsection = R_PointInSubsector(ViewPos)->mapsection;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
SaveMapSection();
|
2016-03-31 19:42:27 +00:00
|
|
|
|
currentmapsection[mapsection >> 3] |= 1 << (mapsection & 7);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
2016-06-18 10:14:20 +00:00
|
|
|
|
GLRenderer->DrawScene(DM_PORTAL);
|
2016-04-20 18:08:53 +00:00
|
|
|
|
portal->mFlags &= ~PORTSF_INSKYBOX;
|
2016-03-31 19:42:27 +00:00
|
|
|
|
inskybox = false;
|
2014-11-27 11:26:52 +00:00
|
|
|
|
gl_RenderState.SetDepthClamp(oldclamp);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
skyboxrecursion--;
|
|
|
|
|
|
2016-03-31 19:42:27 +00:00
|
|
|
|
PlaneMirrorMode = old_pm;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
extralight = saved_extralight;
|
|
|
|
|
|
|
|
|
|
RestoreMapSection();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// Sector stack Portal
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
GLSectorStackPortal::~GLSectorStackPortal()
|
|
|
|
|
{
|
|
|
|
|
if (origin != NULL && origin->glportal == this)
|
|
|
|
|
{
|
|
|
|
|
origin->glportal = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// GLSectorStackPortal::SetupCoverage
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2017-03-09 18:54:41 +00:00
|
|
|
|
static uint8_t SetCoverage(void *node)
|
2013-06-23 07:49:34 +00:00
|
|
|
|
{
|
|
|
|
|
if (numnodes == 0)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!((size_t)node & 1)) // Keep going until found a subsector
|
|
|
|
|
{
|
|
|
|
|
node_t *bsp = (node_t *)node;
|
2017-03-09 18:54:41 +00:00
|
|
|
|
uint8_t coverage = SetCoverage(bsp->children[0]) | SetCoverage(bsp->children[1]);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
gl_drawinfo->no_renderflags[bsp-nodes] = coverage;
|
|
|
|
|
return coverage;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-03-09 18:54:41 +00:00
|
|
|
|
subsector_t *sub = (subsector_t *)((uint8_t *)node - 1);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
return gl_drawinfo->ss_renderflags[sub-subsectors] & SSRF_SEEN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GLSectorStackPortal::SetupCoverage()
|
|
|
|
|
{
|
|
|
|
|
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 = &::subsectors[sub->portalcoverage[plane].subsectors[j]];
|
|
|
|
|
currentmapsection[dsub->mapsection>>3] |= 1 << (dsub->mapsection&7);
|
|
|
|
|
gl_drawinfo->ss_renderflags[dsub-::subsectors] |= SSRF_SEEN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
SetCoverage(&nodes[numnodes-1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// GLSectorStackPortal::DrawContents
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void GLSectorStackPortal::DrawContents()
|
|
|
|
|
{
|
|
|
|
|
FPortal *portal = origin;
|
|
|
|
|
|
2016-04-02 21:17:16 +00:00
|
|
|
|
ViewPos += origin->mDisplacement;
|
2016-12-29 21:19:09 +00:00
|
|
|
|
ViewActorPos += origin->mDisplacement;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
GLRenderer->mViewActor = NULL;
|
|
|
|
|
|
|
|
|
|
// avoid recursions!
|
|
|
|
|
if (origin->plane != -1) instack[origin->plane]++;
|
|
|
|
|
|
2016-04-02 21:17:16 +00:00
|
|
|
|
GLRenderer->SetupView(ViewPos.X, ViewPos.Y, ViewPos.Z, ViewAngle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1));
|
2013-06-23 07:49:34 +00:00
|
|
|
|
SaveMapSection();
|
|
|
|
|
SetupCoverage();
|
|
|
|
|
ClearClipper();
|
2016-07-23 07:47:14 +00:00
|
|
|
|
|
|
|
|
|
// 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(ViewPos);
|
|
|
|
|
if (!(gl_drawinfo->ss_renderflags[sub - ::subsectors] & SSRF_SEEN))
|
|
|
|
|
{
|
|
|
|
|
clipper.SafeAddClipRange(0, ANGLE_MAX);
|
2016-07-23 08:23:34 +00:00
|
|
|
|
clipper.SetBlocked(true);
|
2016-07-23 07:47:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-06-18 10:14:20 +00:00
|
|
|
|
GLRenderer->DrawScene(DM_PORTAL);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
RestoreMapSection();
|
|
|
|
|
|
|
|
|
|
if (origin->plane != -1) instack[origin->plane]--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// Plane Mirror Portal
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// GLPlaneMirrorPortal::DrawContents
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void GLPlaneMirrorPortal::DrawContents()
|
|
|
|
|
{
|
2016-12-29 21:19:09 +00:00
|
|
|
|
if (renderdepth > r_mirror_recursions)
|
2013-06-23 07:49:34 +00:00
|
|
|
|
{
|
|
|
|
|
ClearScreen();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-12-29 18:54:38 +00:00
|
|
|
|
// A plane mirror needs to flip the portal exclusion logic because inside the mirror, up is down and down is up.
|
|
|
|
|
std::swap(instack[sector_t::floor], instack[sector_t::ceiling]);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
2016-12-29 21:19:09 +00:00
|
|
|
|
int old_pm = PlaneMirrorMode;
|
|
|
|
|
|
|
|
|
|
// the player is always visible in a mirror.
|
|
|
|
|
r_showviewer = true;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
2016-04-02 21:17:16 +00:00
|
|
|
|
double planez = origin->ZatPoint(ViewPos);
|
|
|
|
|
ViewPos.Z = 2 * planez - ViewPos.Z;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
GLRenderer->mViewActor = NULL;
|
2016-03-29 11:45:50 +00:00
|
|
|
|
PlaneMirrorMode = origin->fC() < 0 ? -1 : 1;
|
2016-12-29 21:19:09 +00:00
|
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
|
PlaneMirrorFlag++;
|
2016-12-29 21:19:09 +00:00
|
|
|
|
GLRenderer->SetupView(ViewPos.X, ViewPos.Y, ViewPos.Z, ViewAngle, !!(MirrorFlag & 1), !!(PlaneMirrorFlag & 1));
|
2013-06-23 07:49:34 +00:00
|
|
|
|
ClearClipper();
|
|
|
|
|
|
2016-12-29 21:19:09 +00:00
|
|
|
|
gl_RenderState.SetClipHeight(planez, PlaneMirrorMode < 0 ? -1.f : 1.f);
|
2016-06-18 10:14:20 +00:00
|
|
|
|
GLRenderer->DrawScene(DM_PORTAL);
|
2016-04-26 22:41:00 +00:00
|
|
|
|
gl_RenderState.SetClipHeight(0.f, 0.f);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
PlaneMirrorFlag--;
|
2016-12-29 21:19:09 +00:00
|
|
|
|
PlaneMirrorMode = old_pm;
|
2016-12-29 18:54:38 +00:00
|
|
|
|
std::swap(instack[sector_t::floor], instack[sector_t::ceiling]);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-04-28 23:48:06 +00:00
|
|
|
|
void GLPlaneMirrorPortal::PushState()
|
|
|
|
|
{
|
|
|
|
|
planestack.Push(gl_RenderState.GetClipHeight());
|
|
|
|
|
planestack.Push(gl_RenderState.GetClipHeightDirection());
|
|
|
|
|
gl_RenderState.SetClipHeight(0.f, 0.f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GLPlaneMirrorPortal::PopState()
|
|
|
|
|
{
|
|
|
|
|
float d, f;
|
|
|
|
|
planestack.Pop(d);
|
|
|
|
|
planestack.Pop(f);
|
|
|
|
|
gl_RenderState.SetClipHeight(f, d);
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
2016-04-28 23:48:06 +00:00
|
|
|
|
// Common code for line to line and mirror portals
|
2013-06-23 07:49:34 +00:00
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2016-04-29 10:26:57 +00:00
|
|
|
|
void GLLinePortal::PushState()
|
|
|
|
|
{
|
|
|
|
|
FStateVec4 &v = gl_RenderState.GetClipLine();
|
|
|
|
|
planestack.Push(v.vec[0]);
|
|
|
|
|
planestack.Push(v.vec[1]);
|
|
|
|
|
planestack.Push(v.vec[2]);
|
|
|
|
|
planestack.Push(v.vec[3]);
|
|
|
|
|
planestack.Push(gl_RenderState.GetClipLineState());
|
|
|
|
|
gl_RenderState.EnableClipLine(false);
|
|
|
|
|
}
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
2016-04-29 10:26:57 +00:00
|
|
|
|
void GLLinePortal::PopState()
|
|
|
|
|
{
|
|
|
|
|
FStateVec4 &v = gl_RenderState.GetClipLine();
|
|
|
|
|
float e;
|
|
|
|
|
planestack.Pop(e);
|
|
|
|
|
planestack.Pop(v.vec[3]);
|
|
|
|
|
planestack.Pop(v.vec[2]);
|
|
|
|
|
planestack.Pop(v.vec[1]);
|
|
|
|
|
planestack.Pop(v.vec[0]);
|
|
|
|
|
gl_RenderState.EnableClipLine(e != 0);
|
|
|
|
|
}
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
2016-04-28 23:48:06 +00:00
|
|
|
|
int GLLinePortal::ClipSeg(seg_t *seg)
|
|
|
|
|
{
|
|
|
|
|
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 GLLinePortal::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 GLLinePortal::ClipPoint(const DVector2 &pos)
|
|
|
|
|
{
|
|
|
|
|
if (P_PointOnLineSidePrecise(pos, line()))
|
|
|
|
|
{
|
|
|
|
|
return PClip_InFront;
|
|
|
|
|
}
|
|
|
|
|
return PClip_Inside;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// Mirror Portal
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// R_EnterMirror
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void GLMirrorPortal::DrawContents()
|
|
|
|
|
{
|
|
|
|
|
if (renderdepth>r_mirror_recursions)
|
|
|
|
|
{
|
|
|
|
|
ClearScreen();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-28 23:48:06 +00:00
|
|
|
|
GLRenderer->mClipPortal = this;
|
2016-04-02 21:17:16 +00:00
|
|
|
|
DAngle StartAngle = ViewAngle;
|
|
|
|
|
DVector3 StartPos = ViewPos;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
vertex_t *v1 = linedef->v1;
|
|
|
|
|
vertex_t *v2 = linedef->v2;
|
|
|
|
|
|
2016-12-29 21:19:09 +00:00
|
|
|
|
// the player is always visible in a mirror.
|
|
|
|
|
r_showviewer = true;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
// Reflect the current view behind the mirror.
|
2016-03-29 14:31:58 +00:00
|
|
|
|
if (linedef->Delta().X == 0)
|
2016-04-02 21:17:16 +00:00
|
|
|
|
{
|
2013-06-23 07:49:34 +00:00
|
|
|
|
// vertical mirror
|
2016-04-02 21:17:16 +00:00
|
|
|
|
ViewPos.X = 2 * v1->fX() - StartPos.X;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
// Compensation for reendering inaccuracies
|
2016-04-02 21:17:16 +00:00
|
|
|
|
if (StartPos.X < v1->fX()) ViewPos.X -= 0.1;
|
|
|
|
|
else ViewPos.X += 0.1;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
2016-03-29 14:31:58 +00:00
|
|
|
|
else if (linedef->Delta().Y == 0)
|
2013-06-23 07:49:34 +00:00
|
|
|
|
{
|
|
|
|
|
// horizontal mirror
|
2016-04-02 21:17:16 +00:00
|
|
|
|
ViewPos.Y = 2*v1->fY() - StartPos.Y;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
// Compensation for reendering inaccuracies
|
2016-04-02 21:17:16 +00:00
|
|
|
|
if (StartPos.Y<v1->fY()) ViewPos.Y -= 0.1;
|
|
|
|
|
else ViewPos.Y += 0.1;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// any mirror--use floats to avoid integer overflow.
|
|
|
|
|
// Use doubles to avoid losing precision which is very important here.
|
|
|
|
|
|
2016-03-29 09:26:33 +00:00
|
|
|
|
double dx = v2->fX() - v1->fX();
|
|
|
|
|
double dy = v2->fY() - v1->fY();
|
|
|
|
|
double x1 = v1->fX();
|
|
|
|
|
double y1 = v1->fY();
|
2016-04-02 21:17:16 +00:00
|
|
|
|
double x = StartPos.X;
|
|
|
|
|
double y = StartPos.Y;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
// the above two cases catch len == 0
|
|
|
|
|
double r = ((x - x1)*dx + (y - y1)*dy) / (dx*dx + dy*dy);
|
|
|
|
|
|
2016-04-02 21:17:16 +00:00
|
|
|
|
ViewPos.X = (x1 + r * dx)*2 - x;
|
|
|
|
|
ViewPos.Y = (y1 + r * dy)*2 - y;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
// Compensation for reendering inaccuracies
|
|
|
|
|
FVector2 v(-dx, dy);
|
|
|
|
|
v.MakeUnit();
|
|
|
|
|
|
2016-04-02 21:17:16 +00:00
|
|
|
|
ViewPos.X+= v[1] * renderdepth / 2;
|
|
|
|
|
ViewPos.Y+= v[0] * renderdepth / 2;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
2016-04-02 21:17:16 +00:00
|
|
|
|
ViewAngle = linedef->Delta().Angle() * 2. - StartAngle;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
GLRenderer->mViewActor = NULL;
|
|
|
|
|
|
|
|
|
|
MirrorFlag++;
|
2016-04-02 21:17:16 +00:00
|
|
|
|
GLRenderer->SetupView(ViewPos.X, ViewPos.Y, ViewPos.Z, ViewAngle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1));
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
clipper.Clear();
|
|
|
|
|
|
|
|
|
|
angle_t af = GLRenderer->FrustumAngle();
|
2016-04-02 21:17:16 +00:00
|
|
|
|
if (af<ANGLE_180) clipper.SafeAddClipRangeRealAngles(ViewAngle.BAMs()+af, ViewAngle.BAMs()-af);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
angle_t a2 = linedef->v1->GetClipAngle();
|
|
|
|
|
angle_t a1 = linedef->v2->GetClipAngle();
|
|
|
|
|
clipper.SafeAddClipRange(a1,a2);
|
|
|
|
|
|
2016-04-29 10:26:57 +00:00
|
|
|
|
gl_RenderState.SetClipLine(linedef);
|
|
|
|
|
gl_RenderState.EnableClipLine(true);
|
2016-06-18 10:14:20 +00:00
|
|
|
|
GLRenderer->DrawScene(DM_PORTAL);
|
2016-04-29 10:26:57 +00:00
|
|
|
|
gl_RenderState.EnableClipLine(false);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
MirrorFlag--;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-06 04:17:47 +00:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// Line to line Portal
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void GLLineToLinePortal::DrawContents()
|
|
|
|
|
{
|
|
|
|
|
// TODO: Handle recursion more intelligently
|
|
|
|
|
if (renderdepth>r_mirror_recursions)
|
|
|
|
|
{
|
|
|
|
|
ClearScreen();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-28 23:48:06 +00:00
|
|
|
|
GLRenderer->mClipPortal = this;
|
2016-02-06 04:17:47 +00:00
|
|
|
|
|
2016-04-30 14:57:53 +00:00
|
|
|
|
line_t *origin = glport->lines[0]->mOrigin;
|
2016-04-02 21:17:16 +00:00
|
|
|
|
P_TranslatePortalXY(origin, ViewPos.X, ViewPos.Y);
|
2016-12-29 21:19:09 +00:00
|
|
|
|
P_TranslatePortalXY(origin, ViewActorPos.X, ViewActorPos.Y);
|
2016-04-02 21:17:16 +00:00
|
|
|
|
P_TranslatePortalAngle(origin, ViewAngle);
|
|
|
|
|
P_TranslatePortalZ(origin, ViewPos.Z);
|
2017-01-07 00:07:35 +00:00
|
|
|
|
P_TranslatePortalXY(origin, ViewPath[0].X, ViewPath[0].Y);
|
|
|
|
|
P_TranslatePortalXY(origin, ViewPath[1].X, ViewPath[1].Y);
|
|
|
|
|
if (!r_showviewer && camera != nullptr && P_PointOnLineSidePrecise(ViewPath[0], glport->lines[0]->mDestination) != P_PointOnLineSidePrecise(ViewPath[1], glport->lines[0]->mDestination))
|
|
|
|
|
{
|
|
|
|
|
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_MAYBEINVISIBLE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-04 13:10:13 +00:00
|
|
|
|
|
2016-02-06 04:17:47 +00:00
|
|
|
|
SaveMapSection();
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < lines.Size(); i++)
|
|
|
|
|
{
|
2016-02-06 18:19:18 +00:00
|
|
|
|
line_t *line = lines[i].seg->linedef->getPortalDestination();
|
|
|
|
|
subsector_t *sub;
|
|
|
|
|
if (line->sidedef[0]->Flags & WALLF_POLYOBJ)
|
2016-03-29 09:26:33 +00:00
|
|
|
|
sub = R_PointInSubsector(line->v1->fixX(), line->v1->fixY());
|
2016-02-06 18:19:18 +00:00
|
|
|
|
else sub = line->frontsector->subsectors[0];
|
|
|
|
|
int mapsection = sub->mapsection;
|
2016-02-06 04:17:47 +00:00
|
|
|
|
currentmapsection[mapsection >> 3] |= 1 << (mapsection & 7);
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-30 14:57:53 +00:00
|
|
|
|
GLRenderer->mViewActor = nullptr;
|
2016-04-02 21:17:16 +00:00
|
|
|
|
GLRenderer->SetupView(ViewPos.X, ViewPos.Y, ViewPos.Z, ViewAngle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1));
|
2016-02-06 04:17:47 +00:00
|
|
|
|
|
|
|
|
|
ClearClipper();
|
2016-04-30 14:57:53 +00:00
|
|
|
|
gl_RenderState.SetClipLine(glport->lines[0]->mDestination);
|
2016-04-29 10:26:57 +00:00
|
|
|
|
gl_RenderState.EnableClipLine(true);
|
2016-06-18 10:14:20 +00:00
|
|
|
|
GLRenderer->DrawScene(DM_PORTAL);
|
2016-04-29 10:26:57 +00:00
|
|
|
|
gl_RenderState.EnableClipLine(false);
|
2016-02-06 04:17:47 +00:00
|
|
|
|
RestoreMapSection();
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-30 14:57:53 +00:00
|
|
|
|
void GLLineToLinePortal::RenderAttached()
|
|
|
|
|
{
|
|
|
|
|
gl_RenderActorsInPortal(glport);
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// Horizon Portal
|
|
|
|
|
//
|
|
|
|
|
// This simply draws the area in medium sized squares. Drawing it as a whole
|
|
|
|
|
// polygon creates visible inaccuracies.
|
|
|
|
|
//
|
|
|
|
|
// Originally I tried to minimize the amount of data to be drawn but there
|
|
|
|
|
// are 2 problems with it:
|
|
|
|
|
//
|
|
|
|
|
// 1. Setting this up completely negates any performance gains.
|
|
|
|
|
// 2. It doesn't work with a 360<36> field of view (as when you are looking up.)
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// So the brute force mechanism is just as good.
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2016-08-26 16:18:50 +00:00
|
|
|
|
|
|
|
|
|
GLHorizonPortal::GLHorizonPortal(GLHorizonInfo * pt, bool local)
|
|
|
|
|
: GLPortal(local)
|
|
|
|
|
{
|
|
|
|
|
origin = pt;
|
|
|
|
|
|
|
|
|
|
// create the vertex data for this horizon portal.
|
|
|
|
|
GLSectorPlane * sp = &origin->plane;
|
|
|
|
|
const float vx = ViewPos.X;
|
|
|
|
|
const float vy = ViewPos.Y;
|
|
|
|
|
const float vz = ViewPos.Z;
|
|
|
|
|
const float z = sp->Texheight;
|
|
|
|
|
const float tz = (z - vz);
|
|
|
|
|
|
|
|
|
|
// Draw to some far away boundary
|
|
|
|
|
// This is not drawn as larger strips because it causes visual glitches.
|
|
|
|
|
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
|
|
|
|
|
for (float x = -32768 + vx; x<32768 + vx; x += 4096)
|
|
|
|
|
{
|
|
|
|
|
for (float y = -32768 + vy; y<32768 + vy; y += 4096)
|
|
|
|
|
{
|
|
|
|
|
ptr->Set(x, z, y, x / 64, -y / 64);
|
|
|
|
|
ptr++;
|
|
|
|
|
ptr->Set(x + 4096, z, y, x / 64 + 64, -y / 64);
|
|
|
|
|
ptr++;
|
|
|
|
|
ptr->Set(x, z, y + 4096, x / 64, -y / 64 - 64);
|
|
|
|
|
ptr++;
|
|
|
|
|
ptr->Set(x + 4096, z, y + 4096, x / 64 + 64, -y / 64 - 64);
|
|
|
|
|
ptr++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fill the gap between the polygon and the true horizon
|
|
|
|
|
// Since I can't draw into infinity there can always be a
|
|
|
|
|
// small gap
|
|
|
|
|
ptr->Set(-32768 + vx, z, -32768 + vy, 512.f, 0);
|
|
|
|
|
ptr++;
|
|
|
|
|
ptr->Set(-32768 + vx, vz, -32768 + vy, 512.f, tz);
|
|
|
|
|
ptr++;
|
|
|
|
|
ptr->Set(-32768 + vx, z, 32768 + vy, -512.f, 0);
|
|
|
|
|
ptr++;
|
|
|
|
|
ptr->Set(-32768 + vx, vz, 32768 + vy, -512.f, tz);
|
|
|
|
|
ptr++;
|
|
|
|
|
ptr->Set(32768 + vx, z, 32768 + vy, 512.f, 0);
|
|
|
|
|
ptr++;
|
|
|
|
|
ptr->Set(32768 + vx, vz, 32768 + vy, 512.f, tz);
|
|
|
|
|
ptr++;
|
|
|
|
|
ptr->Set(32768 + vx, z, -32768 + vy, -512.f, 0);
|
|
|
|
|
ptr++;
|
|
|
|
|
ptr->Set(32768 + vx, vz, -32768 + vy, -512.f, tz);
|
|
|
|
|
ptr++;
|
|
|
|
|
ptr->Set(-32768 + vx, z, -32768 + vy, 512.f, 0);
|
|
|
|
|
ptr++;
|
|
|
|
|
ptr->Set(-32768 + vx, vz, -32768 + vy, 512.f, tz);
|
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
|
|
vcount = GLRenderer->mVBO->GetCount(ptr, &voffset) - 10;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// GLHorizonPortal::DrawContents
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void GLHorizonPortal::DrawContents()
|
|
|
|
|
{
|
|
|
|
|
PortalAll.Clock();
|
|
|
|
|
|
|
|
|
|
FMaterial * gltexture;
|
|
|
|
|
PalEntry color;
|
|
|
|
|
player_t * player=&players[consoleplayer];
|
2016-08-26 16:18:50 +00:00
|
|
|
|
GLSectorPlane * sp = &origin->plane;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
2014-08-22 21:50:38 +00:00
|
|
|
|
gltexture=FMaterial::ValidateTexture(sp->texture, false, true);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
if (!gltexture)
|
|
|
|
|
{
|
|
|
|
|
ClearScreen();
|
|
|
|
|
PortalAll.Unclock();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-04-02 21:17:16 +00:00
|
|
|
|
gl_RenderState.SetCameraPos(ViewPos.X, ViewPos.Y, ViewPos.Z);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (gltexture && gltexture->tex->isFullbright())
|
|
|
|
|
{
|
|
|
|
|
// glowing textures are always drawn full bright without color
|
2014-05-11 22:13:19 +00:00
|
|
|
|
gl_SetColor(255, 0, origin->colormap, 1.f);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
gl_SetFog(255, 0, &origin->colormap, false);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int rel = getExtraLight();
|
2014-05-11 22:13:19 +00:00
|
|
|
|
gl_SetColor(origin->lightlevel, rel, origin->colormap, 1.0f);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
gl_SetFog(origin->lightlevel, rel, &origin->colormap, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-09-09 10:00:42 +00:00
|
|
|
|
gl_RenderState.SetMaterial(gltexture, CLAMP_NONE, 0, -1, false);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
2014-07-13 18:41:20 +00:00
|
|
|
|
gl_SetPlaneTextureRotation(sp, gltexture);
|
2014-07-14 19:14:43 +00:00
|
|
|
|
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
gl_RenderState.BlendFunc(GL_ONE,GL_ZERO);
|
|
|
|
|
gl_RenderState.Apply();
|
|
|
|
|
|
|
|
|
|
|
2016-08-26 16:18:50 +00:00
|
|
|
|
for (unsigned i = 0; i < vcount; i += 4)
|
2013-06-23 07:49:34 +00:00
|
|
|
|
{
|
2016-08-29 08:43:03 +00:00
|
|
|
|
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, voffset + i, 4);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
2016-08-29 08:43:03 +00:00
|
|
|
|
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, voffset + vcount, 10);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
2014-07-13 18:41:20 +00:00
|
|
|
|
gl_RenderState.EnableTextureMatrix(false);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
PortalAll.Unclock();
|
|
|
|
|
|
2016-01-11 14:07:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// Eternity-style horizon portal
|
|
|
|
|
//
|
|
|
|
|
// To the rest of the engine these masquerade as a skybox portal
|
|
|
|
|
// Internally they need to draw two horizon or sky portals
|
|
|
|
|
// and will use the respective classes to achieve that.
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void GLEEHorizonPortal::DrawContents()
|
|
|
|
|
{
|
|
|
|
|
PortalAll.Clock();
|
2016-04-20 18:08:53 +00:00
|
|
|
|
sector_t *sector = portal->mOrigin;
|
2016-04-20 09:39:41 +00:00
|
|
|
|
if (sector->GetTexture(sector_t::floor) == skyflatnum ||
|
|
|
|
|
sector->GetTexture(sector_t::ceiling) == skyflatnum)
|
2016-01-11 14:07:58 +00:00
|
|
|
|
{
|
|
|
|
|
GLSkyInfo skyinfo;
|
2016-04-20 09:39:41 +00:00
|
|
|
|
skyinfo.init(sector->sky, 0);
|
2016-01-11 14:07:58 +00:00
|
|
|
|
GLSkyPortal sky(&skyinfo, true);
|
|
|
|
|
sky.DrawContents();
|
|
|
|
|
}
|
2016-04-20 09:39:41 +00:00
|
|
|
|
if (sector->GetTexture(sector_t::ceiling) != skyflatnum)
|
2016-01-11 14:07:58 +00:00
|
|
|
|
{
|
|
|
|
|
GLHorizonInfo horz;
|
2016-10-03 14:09:32 +00:00
|
|
|
|
horz.plane.GetFromSector(sector, sector_t::ceiling);
|
2016-04-20 09:39:41 +00:00
|
|
|
|
horz.lightlevel = gl_ClampLight(sector->GetCeilingLight());
|
|
|
|
|
horz.colormap = sector->ColorMap;
|
2016-04-20 18:08:53 +00:00
|
|
|
|
if (portal->mType == PORTS_PLANE)
|
2016-01-11 14:07:58 +00:00
|
|
|
|
{
|
2016-04-02 21:17:16 +00:00
|
|
|
|
horz.plane.Texheight = ViewPos.Z + fabs(horz.plane.Texheight);
|
2016-01-11 14:07:58 +00:00
|
|
|
|
}
|
|
|
|
|
GLHorizonPortal ceil(&horz, true);
|
|
|
|
|
ceil.DrawContents();
|
|
|
|
|
}
|
2016-04-20 09:39:41 +00:00
|
|
|
|
if (sector->GetTexture(sector_t::floor) != skyflatnum)
|
2016-01-11 14:07:58 +00:00
|
|
|
|
{
|
|
|
|
|
GLHorizonInfo horz;
|
2016-10-03 14:09:32 +00:00
|
|
|
|
horz.plane.GetFromSector(sector, sector_t::floor);
|
2016-04-20 09:39:41 +00:00
|
|
|
|
horz.lightlevel = gl_ClampLight(sector->GetFloorLight());
|
|
|
|
|
horz.colormap = sector->ColorMap;
|
2016-04-20 18:08:53 +00:00
|
|
|
|
if (portal->mType == PORTS_PLANE)
|
2016-01-11 14:07:58 +00:00
|
|
|
|
{
|
2016-04-02 21:17:16 +00:00
|
|
|
|
horz.plane.Texheight = ViewPos.Z - fabs(horz.plane.Texheight);
|
2016-01-11 14:07:58 +00:00
|
|
|
|
}
|
|
|
|
|
GLHorizonPortal floor(&horz, true);
|
|
|
|
|
floor.DrawContents();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *GLSkyPortal::GetName() { return "Sky"; }
|
|
|
|
|
const char *GLSkyboxPortal::GetName() { return "Skybox"; }
|
|
|
|
|
const char *GLSectorStackPortal::GetName() { return "Sectorstack"; }
|
|
|
|
|
const char *GLPlaneMirrorPortal::GetName() { return "Planemirror"; }
|
|
|
|
|
const char *GLMirrorPortal::GetName() { return "Mirror"; }
|
2016-02-06 04:17:47 +00:00
|
|
|
|
const char *GLLineToLinePortal::GetName() { return "LineToLine"; }
|
2013-06-23 07:49:34 +00:00
|
|
|
|
const char *GLHorizonPortal::GetName() { return "Horizon"; }
|
2016-01-11 14:07:58 +00:00
|
|
|
|
const char *GLEEHorizonPortal::GetName() { return "EEHorizon"; }
|
|
|
|
|
|