2016-09-14 18:01:13 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Copyright(C) 2005-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/
|
|
|
|
//
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
//
|
2016-04-26 16:24:02 +00:00
|
|
|
/*
|
|
|
|
** gl_20.cpp
|
|
|
|
**
|
|
|
|
** Fallback code for ancient hardware
|
|
|
|
** This file collects everything larger that is only needed for
|
|
|
|
** OpenGL 2.0/no shader compatibility.
|
|
|
|
**
|
|
|
|
*/
|
2016-09-14 18:01:13 +00:00
|
|
|
|
2016-04-26 16:24:02 +00:00
|
|
|
#include "gl/system/gl_system.h"
|
2016-05-01 15:43:30 +00:00
|
|
|
#include "menu/menu.h"
|
2016-04-26 16:24:02 +00:00
|
|
|
#include "tarray.h"
|
|
|
|
#include "doomtype.h"
|
|
|
|
#include "m_argv.h"
|
|
|
|
#include "zstring.h"
|
|
|
|
#include "i_system.h"
|
|
|
|
#include "v_text.h"
|
|
|
|
#include "r_utility.h"
|
2017-01-08 17:45:30 +00:00
|
|
|
#include "g_levellocals.h"
|
2017-03-10 08:57:10 +00:00
|
|
|
#include "actorinlines.h"
|
2017-03-14 12:54:24 +00:00
|
|
|
#include "g_levellocals.h"
|
2016-04-27 22:58:44 +00:00
|
|
|
#include "gl/dynlights/gl_dynlight.h"
|
|
|
|
#include "gl/utility/gl_geometric.h"
|
|
|
|
#include "gl/renderer/gl_renderer.h"
|
2016-05-03 21:28:42 +00:00
|
|
|
#include "gl/renderer/gl_lightdata.h"
|
2016-04-26 16:24:02 +00:00
|
|
|
#include "gl/system/gl_interface.h"
|
|
|
|
#include "gl/system/gl_cvars.h"
|
|
|
|
#include "gl/renderer/gl_renderstate.h"
|
2016-04-27 22:58:44 +00:00
|
|
|
#include "gl/scene/gl_drawinfo.h"
|
2017-03-12 11:03:54 +00:00
|
|
|
#include "gl/scene/gl_scenedrawer.h"
|
2016-05-04 22:24:47 +00:00
|
|
|
#include "gl/data/gl_vertexbuffer.h"
|
2016-04-26 16:24:02 +00:00
|
|
|
|
2016-05-01 11:09:13 +00:00
|
|
|
|
2016-09-04 10:35:26 +00:00
|
|
|
CVAR(Bool, gl_lights_additive, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
2017-05-08 17:30:51 +00:00
|
|
|
CVAR(Bool, gl_legacy_mode, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOSET)
|
2016-09-04 10:35:26 +00:00
|
|
|
|
2016-05-01 11:09:13 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Do some tinkering with the menus so that certain options only appear
|
|
|
|
// when they are actually valid.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void gl_PatchMenu()
|
|
|
|
{
|
2016-09-01 15:14:51 +00:00
|
|
|
// Radial fog and Doom lighting are not available without full shader support.
|
2017-05-08 17:30:51 +00:00
|
|
|
if (!gl_legacy_mode) return;
|
2016-05-01 11:09:13 +00:00
|
|
|
|
2016-09-01 15:14:51 +00:00
|
|
|
FOptionValues **opt = OptionValues.CheckKey("LightingModes");
|
|
|
|
if (opt != NULL)
|
|
|
|
{
|
|
|
|
for(int i = (*opt)->mValues.Size()-1; i>=0; i--)
|
2016-05-01 11:09:13 +00:00
|
|
|
{
|
2016-09-01 15:14:51 +00:00
|
|
|
// Delete 'Doom' lighting mode
|
|
|
|
if ((*opt)->mValues[i].Value == 2.0 || (*opt)->mValues[i].Value == 8.0)
|
2016-05-01 11:09:13 +00:00
|
|
|
{
|
2016-09-01 15:14:51 +00:00
|
|
|
(*opt)->mValues.Delete(i);
|
2016-05-01 11:09:13 +00:00
|
|
|
}
|
|
|
|
}
|
2016-09-01 15:14:51 +00:00
|
|
|
}
|
2016-05-01 11:09:13 +00:00
|
|
|
|
2016-09-01 15:14:51 +00:00
|
|
|
opt = OptionValues.CheckKey("FogMode");
|
|
|
|
if (opt != NULL)
|
|
|
|
{
|
|
|
|
for(int i = (*opt)->mValues.Size()-1; i>=0; i--)
|
2016-05-01 11:09:13 +00:00
|
|
|
{
|
2016-09-01 15:14:51 +00:00
|
|
|
// Delete 'Radial' fog mode
|
|
|
|
if ((*opt)->mValues[i].Value == 2.0)
|
2016-05-01 11:09:13 +00:00
|
|
|
{
|
2016-09-01 15:14:51 +00:00
|
|
|
(*opt)->mValues.Delete(i);
|
2016-05-01 11:09:13 +00:00
|
|
|
}
|
|
|
|
}
|
2016-09-01 15:14:51 +00:00
|
|
|
}
|
2016-05-01 11:09:13 +00:00
|
|
|
|
2016-09-01 15:14:51 +00:00
|
|
|
// disable features that don't work without shaders.
|
|
|
|
if (gl_lightmode == 2 || gl_lightmode == 8) gl_lightmode = 3;
|
|
|
|
if (gl_fogmode == 2) gl_fogmode = 1;
|
2016-09-01 09:52:52 +00:00
|
|
|
|
2017-03-13 00:17:46 +00:00
|
|
|
// remove more unsupported stuff like postprocessing options.
|
|
|
|
// This cannot be done with a menu filter because the renderer gets initialized long after the menu is set up.
|
|
|
|
DMenuDescriptor **desc = MenuDescriptors.CheckKey("OpenGLOptions");
|
|
|
|
if (desc != nullptr && (*desc)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor)))
|
|
|
|
{
|
|
|
|
auto md = static_cast<DOptionMenuDescriptor*>(*desc);
|
|
|
|
for (int i = md->mItems.Size() - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
if (!stricmp(md->mItems[i]->mAction.GetChars(), "gl_multisample") ||
|
|
|
|
!stricmp(md->mItems[i]->mAction.GetChars(), "gl_tonemap") ||
|
|
|
|
!stricmp(md->mItems[i]->mAction.GetChars(), "gl_bloom") ||
|
|
|
|
!stricmp(md->mItems[i]->mAction.GetChars(), "gl_lens") ||
|
|
|
|
!stricmp(md->mItems[i]->mAction.GetChars(), "gl_ssao") ||
|
|
|
|
!stricmp(md->mItems[i]->mAction.GetChars(), "gl_ssao_portals") ||
|
|
|
|
!stricmp(md->mItems[i]->mAction.GetChars(), "gl_fxaa") ||
|
|
|
|
!stricmp(md->mItems[i]->mAction.GetChars(), "gl_paltonemap_powtable") ||
|
|
|
|
!stricmp(md->mItems[i]->mAction.GetChars(), "vr_mode") ||
|
|
|
|
!stricmp(md->mItems[i]->mAction.GetChars(), "vr_enable_quadbuffered") ||
|
|
|
|
!stricmp(md->mItems[i]->mAction.GetChars(), "gl_paltonemap_reverselookup"))
|
|
|
|
{
|
|
|
|
md->mItems.Delete(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-05-01 11:09:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-27 22:58:44 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2016-04-26 16:24:02 +00:00
|
|
|
|
|
|
|
void gl_SetTextureMode(int type)
|
|
|
|
{
|
|
|
|
if (type == TM_MASK)
|
|
|
|
{
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
|
|
|
|
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE0);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
|
|
|
|
}
|
|
|
|
else if (type == TM_OPAQUE)
|
|
|
|
{
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
|
|
|
|
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
|
|
|
}
|
|
|
|
else if (type == TM_INVERSE)
|
|
|
|
{
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
|
|
|
|
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE0);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
|
|
|
|
}
|
|
|
|
else if (type == TM_INVERTOPAQUE)
|
|
|
|
{
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
|
|
|
|
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
|
|
|
}
|
|
|
|
else // if (type == TM_MODULATE)
|
|
|
|
{
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-27 22:58:44 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2016-04-26 16:24:02 +00:00
|
|
|
|
|
|
|
static int ffTextureMode;
|
|
|
|
static bool ffTextureEnabled;
|
|
|
|
static bool ffFogEnabled;
|
|
|
|
static PalEntry ffFogColor;
|
|
|
|
static int ffSpecialEffect;
|
|
|
|
static float ffFogDensity;
|
2016-04-26 18:45:56 +00:00
|
|
|
static bool currentTextureMatrixState;
|
|
|
|
static bool currentModelMatrixState;
|
2016-04-26 16:24:02 +00:00
|
|
|
|
|
|
|
void FRenderState::ApplyFixedFunction()
|
|
|
|
{
|
|
|
|
if (mTextureMode != ffTextureMode)
|
|
|
|
{
|
|
|
|
ffTextureMode = mTextureMode;
|
|
|
|
if (ffTextureMode == TM_CLAMPY) ffTextureMode = TM_MODULATE; // this cannot be replicated. Too bad if it creates visual artifacts
|
|
|
|
gl_SetTextureMode(ffTextureMode);
|
|
|
|
}
|
|
|
|
if (mTextureEnabled != ffTextureEnabled)
|
|
|
|
{
|
|
|
|
if ((ffTextureEnabled = mTextureEnabled)) glEnable(GL_TEXTURE_2D);
|
|
|
|
else glDisable(GL_TEXTURE_2D);
|
|
|
|
}
|
|
|
|
if (mFogEnabled != ffFogEnabled)
|
|
|
|
{
|
|
|
|
if ((ffFogEnabled = mFogEnabled))
|
|
|
|
{
|
|
|
|
glEnable(GL_FOG);
|
|
|
|
}
|
|
|
|
else glDisable(GL_FOG);
|
|
|
|
}
|
|
|
|
if (mFogEnabled)
|
|
|
|
{
|
|
|
|
if (ffFogColor != mFogColor)
|
|
|
|
{
|
|
|
|
ffFogColor = mFogColor;
|
|
|
|
GLfloat FogColor[4] = { mFogColor.r / 255.0f,mFogColor.g / 255.0f,mFogColor.b / 255.0f,0.0f };
|
|
|
|
glFogfv(GL_FOG_COLOR, FogColor);
|
|
|
|
}
|
|
|
|
if (ffFogDensity != mLightParms[2])
|
|
|
|
{
|
|
|
|
glFogf(GL_FOG_DENSITY, mLightParms[2] * -0.6931471f); // = 1/log(2)
|
|
|
|
ffFogDensity = mLightParms[2];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mSpecialEffect != ffSpecialEffect)
|
|
|
|
{
|
|
|
|
switch (ffSpecialEffect)
|
|
|
|
{
|
|
|
|
case EFF_SPHEREMAP:
|
|
|
|
glDisable(GL_TEXTURE_GEN_T);
|
|
|
|
glDisable(GL_TEXTURE_GEN_S);
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch (mSpecialEffect)
|
|
|
|
{
|
|
|
|
case EFF_SPHEREMAP:
|
|
|
|
// Use sphere mapping for this
|
|
|
|
glEnable(GL_TEXTURE_GEN_T);
|
|
|
|
glEnable(GL_TEXTURE_GEN_S);
|
|
|
|
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
|
|
|
|
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ffSpecialEffect = mSpecialEffect;
|
|
|
|
}
|
|
|
|
|
|
|
|
FStateVec4 col = mColor;
|
|
|
|
|
|
|
|
col.vec[0] += mDynColor.vec[0];
|
|
|
|
col.vec[1] += mDynColor.vec[1];
|
|
|
|
col.vec[2] += mDynColor.vec[2];
|
|
|
|
col.vec[0] = clamp(col.vec[0], 0.f, 1.f);
|
|
|
|
|
|
|
|
col.vec[0] = clamp(col.vec[0], 0.f, 1.f);
|
|
|
|
col.vec[1] = clamp(col.vec[1], 0.f, 1.f);
|
|
|
|
col.vec[2] = clamp(col.vec[2], 0.f, 1.f);
|
|
|
|
col.vec[3] = clamp(col.vec[3], 0.f, 1.f);
|
|
|
|
|
|
|
|
col.vec[0] *= (mObjectColor.r / 255.f);
|
|
|
|
col.vec[1] *= (mObjectColor.g / 255.f);
|
|
|
|
col.vec[2] *= (mObjectColor.b / 255.f);
|
|
|
|
col.vec[3] *= (mObjectColor.a / 255.f);
|
|
|
|
glColor4fv(col.vec);
|
|
|
|
|
2016-04-26 17:11:32 +00:00
|
|
|
glEnable(GL_BLEND);
|
2016-04-26 16:24:02 +00:00
|
|
|
if (mAlphaThreshold > 0)
|
|
|
|
{
|
|
|
|
glEnable(GL_ALPHA_TEST);
|
2016-04-26 18:45:56 +00:00
|
|
|
glAlphaFunc(GL_GREATER, mAlphaThreshold * col.vec[3]);
|
2016-04-26 16:24:02 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
glDisable(GL_ALPHA_TEST);
|
|
|
|
}
|
|
|
|
|
2016-04-26 18:45:56 +00:00
|
|
|
if (mTextureMatrixEnabled)
|
|
|
|
{
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
|
|
glLoadMatrixf(mTextureMatrix.get());
|
|
|
|
currentTextureMatrixState = true;
|
|
|
|
}
|
|
|
|
else if (currentTextureMatrixState)
|
|
|
|
{
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
|
|
glLoadIdentity();
|
|
|
|
currentTextureMatrixState = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mModelMatrixEnabled)
|
|
|
|
{
|
|
|
|
VSMatrix mult = mViewMatrix;
|
|
|
|
mult.multMatrix(mModelMatrix);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadMatrixf(mult.get());
|
|
|
|
currentModelMatrixState = true;
|
|
|
|
}
|
|
|
|
else if (currentModelMatrixState)
|
|
|
|
{
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadMatrixf(mViewMatrix.get());
|
|
|
|
currentModelMatrixState = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-26 16:24:02 +00:00
|
|
|
}
|
2016-04-26 18:02:57 +00:00
|
|
|
|
2016-04-27 22:58:44 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2016-04-26 18:02:57 +00:00
|
|
|
void gl_FillScreen();
|
|
|
|
|
|
|
|
void FRenderState::DrawColormapOverlay()
|
|
|
|
{
|
|
|
|
float r, g, b;
|
|
|
|
if (mColormapState > CM_DEFAULT && mColormapState < CM_MAXCOLORMAP)
|
|
|
|
{
|
2017-03-12 20:57:39 +00:00
|
|
|
FSpecialColormap *scm = &SpecialColormaps[mColormapState - CM_FIRSTSPECIALCOLORMAP];
|
2016-04-26 18:02:57 +00:00
|
|
|
float m[] = { scm->ColorizeEnd[0] - scm->ColorizeStart[0],
|
|
|
|
scm->ColorizeEnd[1] - scm->ColorizeStart[1], scm->ColorizeEnd[2] - scm->ColorizeStart[2], 0.f };
|
|
|
|
|
|
|
|
if (m[0] < 0 && m[1] < 0 && m[2] < 0)
|
|
|
|
{
|
|
|
|
gl_RenderState.SetColor(1, 1, 1, 1);
|
|
|
|
gl_RenderState.BlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
|
|
|
|
gl_FillScreen();
|
|
|
|
|
|
|
|
r = scm->ColorizeStart[0];
|
|
|
|
g = scm->ColorizeStart[1];
|
|
|
|
b = scm->ColorizeStart[2];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
r = scm->ColorizeEnd[0];
|
|
|
|
g = scm->ColorizeEnd[1];
|
|
|
|
b = scm->ColorizeEnd[2];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (mColormapState == CM_LITE)
|
|
|
|
{
|
|
|
|
if (gl_enhanced_nightvision)
|
|
|
|
{
|
|
|
|
r = 0.375f, g = 1.0f, b = 0.375f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (mColormapState >= CM_TORCH)
|
|
|
|
{
|
|
|
|
int flicker = mColormapState - CM_TORCH;
|
|
|
|
r = (0.8f + (7 - flicker) / 70.0f);
|
|
|
|
if (r > 1.0f) r = 1.0f;
|
|
|
|
b = g = r;
|
|
|
|
if (gl_enhanced_nightvision) b = g * 0.75f;
|
|
|
|
}
|
|
|
|
else return;
|
|
|
|
|
|
|
|
gl_RenderState.SetColor(r, g, b, 1.f);
|
|
|
|
gl_RenderState.BlendFunc(GL_DST_COLOR, GL_ZERO);
|
|
|
|
gl_FillScreen();
|
|
|
|
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
2016-04-27 22:58:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Sets up the parameters to render one dynamic light onto one plane
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2016-05-04 22:24:47 +00:00
|
|
|
|
2017-03-12 18:44:00 +00:00
|
|
|
bool gl_SetupLight(int group, Plane & p, ADynamicLight * light, FVector3 & nearPt, FVector3 & up, FVector3 & right,
|
2016-09-01 09:52:52 +00:00
|
|
|
float & scale, bool checkside, bool additive)
|
2016-04-27 22:58:44 +00:00
|
|
|
{
|
2017-03-12 18:44:00 +00:00
|
|
|
FVector3 fn, pos;
|
2016-04-27 22:58:44 +00:00
|
|
|
|
|
|
|
DVector3 lpos = light->PosRelative(group);
|
|
|
|
|
|
|
|
float dist = fabsf(p.DistToPoint(lpos.X, lpos.Z, lpos.Y));
|
2016-09-04 10:45:09 +00:00
|
|
|
float radius = light->GetRadius();
|
2016-04-27 22:58:44 +00:00
|
|
|
|
|
|
|
if (radius <= 0.f) return false;
|
|
|
|
if (dist > radius) return false;
|
|
|
|
if (checkside && gl_lights_checkside && p.PointOnSide(lpos.X, lpos.Z, lpos.Y))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2016-05-04 09:33:18 +00:00
|
|
|
if (!light->visibletoplayer)
|
2016-04-27 22:58:44 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
scale = 1.0f / ((2.f * radius) - dist);
|
|
|
|
|
|
|
|
// project light position onto plane (find closest point on plane)
|
|
|
|
|
|
|
|
|
2017-03-12 18:44:00 +00:00
|
|
|
pos = { (float)lpos.X, (float)lpos.Z, (float)lpos.Y };
|
2016-04-27 22:58:44 +00:00
|
|
|
fn = p.Normal();
|
|
|
|
fn.GetRightUp(right, up);
|
|
|
|
|
2017-03-12 18:44:00 +00:00
|
|
|
FVector3 tmpVec = fn * dist;
|
2016-04-27 22:58:44 +00:00
|
|
|
nearPt = pos + tmpVec;
|
|
|
|
|
|
|
|
float cs = 1.0f - (dist / radius);
|
2016-05-05 09:32:21 +00:00
|
|
|
if (additive) cs *= 0.2f; // otherwise the light gets too strong.
|
2016-09-04 10:45:09 +00:00
|
|
|
float r = light->GetRed() / 255.0f * cs;
|
|
|
|
float g = light->GetGreen() / 255.0f * cs;
|
|
|
|
float b = light->GetBlue() / 255.0f * cs;
|
2016-04-27 22:58:44 +00:00
|
|
|
|
|
|
|
if (light->IsSubtractive())
|
|
|
|
{
|
|
|
|
gl_RenderState.BlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
2017-03-12 18:44:00 +00:00
|
|
|
float length = float(FVector3(r, g, b).Length());
|
|
|
|
r = length - r;
|
|
|
|
g = length - g;
|
|
|
|
b = length - b;
|
2016-04-27 22:58:44 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gl_RenderState.BlendEquation(GL_FUNC_ADD);
|
|
|
|
}
|
2016-05-05 10:18:09 +00:00
|
|
|
gl_RenderState.SetColor(r, g, b);
|
2016-04-27 22:58:44 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
bool gl_SetupLightTexture()
|
|
|
|
{
|
2016-05-03 21:28:42 +00:00
|
|
|
if (GLRenderer->gllight == nullptr) return false;
|
2016-04-27 22:58:44 +00:00
|
|
|
FMaterial * pat = FMaterial::ValidateTexture(GLRenderer->gllight, false);
|
2016-06-19 08:19:31 +00:00
|
|
|
gl_RenderState.SetMaterial(pat, CLAMP_XY_NOMIP, 0, -1, false);
|
2016-04-27 22:58:44 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-03-14 12:54:24 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Check fog in current sector for placing into the proper draw list.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static bool gl_CheckFog(FColormap *cm, int lightlevel)
|
|
|
|
{
|
|
|
|
bool frontfog;
|
|
|
|
|
|
|
|
PalEntry fogcolor = cm->FadeColor;
|
|
|
|
|
|
|
|
if ((fogcolor.d & 0xffffff) == 0)
|
|
|
|
{
|
|
|
|
frontfog = false;
|
|
|
|
}
|
|
|
|
else if (level.outsidefogdensity != 0 && APART(level.info->outsidefog) != 0xff && (fogcolor.d & 0xffffff) == (level.info->outsidefog & 0xffffff))
|
|
|
|
{
|
|
|
|
frontfog = true;
|
|
|
|
}
|
2017-03-15 15:47:42 +00:00
|
|
|
else if (level.fogdensity != 0 || (glset.lightmode & 4) || cm->FogDensity > 0)
|
2017-03-14 12:54:24 +00:00
|
|
|
{
|
|
|
|
// case 3: level has fog density set
|
|
|
|
frontfog = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// case 4: use light level
|
|
|
|
frontfog = lightlevel < 248;
|
|
|
|
}
|
|
|
|
return frontfog;
|
|
|
|
}
|
|
|
|
|
2016-04-27 22:58:44 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2016-05-03 21:28:42 +00:00
|
|
|
bool GLWall::PutWallCompat(int passflag)
|
|
|
|
{
|
|
|
|
static int list_indices[2][2] =
|
|
|
|
{ { GLLDL_WALLS_PLAIN, GLLDL_WALLS_FOG },{ GLLDL_WALLS_MASKED, GLLDL_WALLS_FOGMASKED } };
|
|
|
|
|
|
|
|
// are lights possible?
|
2017-03-12 20:57:39 +00:00
|
|
|
if (mDrawer->FixedColormap != CM_DEFAULT || !gl_lights || seg->sidedef == nullptr || type == RENDERWALL_M2SNF || !gltexture) return false;
|
2016-05-03 21:28:42 +00:00
|
|
|
|
|
|
|
// multipassing these is problematic.
|
|
|
|
if ((flags&GLWF_SKYHACK && type == RENDERWALL_M2S)) return false;
|
|
|
|
|
|
|
|
// Any lights affecting this wall?
|
|
|
|
if (!(seg->sidedef->Flags & WALLF_POLYOBJ))
|
|
|
|
{
|
|
|
|
if (seg->sidedef->lighthead == nullptr) return false;
|
|
|
|
}
|
|
|
|
else if (sub)
|
|
|
|
{
|
2016-06-28 07:44:48 +00:00
|
|
|
if (sub->lighthead == nullptr) return false;
|
2016-05-03 21:28:42 +00:00
|
|
|
}
|
|
|
|
|
2016-09-04 10:35:26 +00:00
|
|
|
bool foggy = gl_CheckFog(&Colormap, lightlevel) || (level.flags&LEVEL_HASFADETABLE) || gl_lights_additive;
|
2016-05-03 21:28:42 +00:00
|
|
|
bool masked = passflag == 2 && gltexture->isMasked();
|
|
|
|
|
|
|
|
int list = list_indices[masked][foggy];
|
|
|
|
gl_drawinfo->dldrawlists[list].AddWall(this);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-05-04 21:07:16 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
bool GLFlat::PutFlatCompat(bool fog)
|
|
|
|
{
|
|
|
|
// are lights possible?
|
2017-03-12 20:57:39 +00:00
|
|
|
if (mDrawer->FixedColormap != CM_DEFAULT || !gl_lights || !gltexture || renderstyle != STYLE_Translucent || alpha < 1.f - FLT_EPSILON || sector->lighthead == NULL) return false;
|
2016-05-04 21:07:16 +00:00
|
|
|
|
|
|
|
static int list_indices[2][2] =
|
|
|
|
{ { GLLDL_FLATS_PLAIN, GLLDL_FLATS_FOG },{ GLLDL_FLATS_MASKED, GLLDL_FLATS_FOGMASKED } };
|
|
|
|
|
|
|
|
bool masked = gltexture->isMasked() && ((renderflags&SSRF_RENDER3DPLANES) || stack);
|
2016-05-05 10:18:09 +00:00
|
|
|
bool foggy = gl_CheckFog(&Colormap, lightlevel) || (level.flags&LEVEL_HASFADETABLE) || gl_lights_additive;
|
2016-05-04 21:07:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
int list = list_indices[masked][foggy];
|
|
|
|
gl_drawinfo->dldrawlists[list].AddFlat(this);
|
2016-05-05 09:48:39 +00:00
|
|
|
return true;
|
2016-05-04 21:07:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-03 21:28:42 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Fog boundary without any shader support
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void GLWall::RenderFogBoundaryCompat()
|
|
|
|
{
|
|
|
|
// without shaders some approximation is needed. This won't look as good
|
|
|
|
// as the shader version but it's an acceptable compromise.
|
2017-03-15 15:47:42 +00:00
|
|
|
float fogdensity = gl_GetFogDensity(lightlevel, Colormap.FadeColor, Colormap.FogDensity);
|
2016-05-03 21:28:42 +00:00
|
|
|
|
2017-03-11 22:28:07 +00:00
|
|
|
float dist1 = Dist2(r_viewpoint.Pos.X, r_viewpoint.Pos.Y, glseg.x1, glseg.y1);
|
|
|
|
float dist2 = Dist2(r_viewpoint.Pos.X, r_viewpoint.Pos.Y, glseg.x2, glseg.y2);
|
2016-05-03 21:28:42 +00:00
|
|
|
|
|
|
|
// these values were determined by trial and error and are scale dependent!
|
|
|
|
float fogd1 = (0.95f - exp(-fogdensity*dist1 / 62500.f)) * 1.05f;
|
|
|
|
float fogd2 = (0.95f - exp(-fogdensity*dist2 / 62500.f)) * 1.05f;
|
|
|
|
|
|
|
|
float fc[4] = { Colormap.FadeColor.r / 255.0f,Colormap.FadeColor.g / 255.0f,Colormap.FadeColor.b / 255.0f,fogd2 };
|
|
|
|
|
|
|
|
gl_RenderState.EnableTexture(false);
|
|
|
|
gl_RenderState.EnableFog(false);
|
|
|
|
gl_RenderState.AlphaFunc(GL_GEQUAL, 0);
|
|
|
|
gl_RenderState.Apply();
|
|
|
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
|
|
|
glPolygonOffset(-1.0f, -128.0f);
|
|
|
|
glDepthFunc(GL_LEQUAL);
|
|
|
|
glColor4f(fc[0], fc[1], fc[2], fogd1);
|
|
|
|
glBegin(GL_TRIANGLE_FAN);
|
2016-05-05 09:48:39 +00:00
|
|
|
glTexCoord2f(tcs[LOLFT].u, tcs[LOLFT].v);
|
2016-05-03 21:28:42 +00:00
|
|
|
glVertex3f(glseg.x1, zbottom[0], glseg.y1);
|
2016-05-05 09:48:39 +00:00
|
|
|
glTexCoord2f(tcs[UPLFT].u, tcs[UPLFT].v);
|
2016-05-03 21:28:42 +00:00
|
|
|
glVertex3f(glseg.x1, ztop[0], glseg.y1);
|
|
|
|
glColor4f(fc[0], fc[1], fc[2], fogd2);
|
2016-05-05 09:48:39 +00:00
|
|
|
glTexCoord2f(tcs[UPRGT].u, tcs[UPRGT].v);
|
2016-05-03 21:28:42 +00:00
|
|
|
glVertex3f(glseg.x2, ztop[1], glseg.y2);
|
2016-05-05 09:48:39 +00:00
|
|
|
glTexCoord2f(tcs[LORGT].u, tcs[LORGT].v);
|
2016-05-03 21:28:42 +00:00
|
|
|
glVertex3f(glseg.x2, zbottom[1], glseg.y2);
|
|
|
|
glEnd();
|
|
|
|
glDepthFunc(GL_LESS);
|
|
|
|
glPolygonOffset(0.0f, 0.0f);
|
|
|
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
|
|
|
gl_RenderState.EnableFog(true);
|
|
|
|
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.5f);
|
|
|
|
gl_RenderState.EnableTexture(true);
|
|
|
|
}
|
|
|
|
|
2016-05-04 22:24:47 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Flats
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void GLFlat::DrawSubsectorLights(subsector_t * sub, int pass)
|
|
|
|
{
|
|
|
|
Plane p;
|
2017-03-12 18:44:00 +00:00
|
|
|
FVector3 nearPt, up, right, t1;
|
2016-05-04 22:24:47 +00:00
|
|
|
float scale;
|
|
|
|
|
|
|
|
FLightNode * node = sub->lighthead;
|
|
|
|
while (node)
|
|
|
|
{
|
|
|
|
ADynamicLight * light = node->lightsource;
|
|
|
|
|
2016-05-05 08:28:21 +00:00
|
|
|
if (light->flags2&MF2_DORMANT ||
|
|
|
|
(pass == GLPASS_LIGHTTEX && light->IsAdditive()) ||
|
|
|
|
(pass == GLPASS_LIGHTTEX_ADDITIVE && !light->IsAdditive()))
|
2016-05-04 22:24:47 +00:00
|
|
|
{
|
|
|
|
node = node->nextLight;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// we must do the side check here because gl_SetupLight needs the correct plane orientation
|
|
|
|
// which we don't have for Legacy-style 3D-floors
|
|
|
|
double planeh = plane.plane.ZatPoint(light);
|
|
|
|
if (gl_lights_checkside && ((planeh<light->Z() && ceiling) || (planeh>light->Z() && !ceiling)))
|
|
|
|
{
|
|
|
|
node = node->nextLight;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
p.Set(plane.plane);
|
2016-09-01 09:52:52 +00:00
|
|
|
if (!gl_SetupLight(sub->sector->PortalGroup, p, light, nearPt, up, right, scale, false, pass != GLPASS_LIGHTTEX))
|
2016-05-04 22:24:47 +00:00
|
|
|
{
|
|
|
|
node = node->nextLight;
|
|
|
|
continue;
|
|
|
|
}
|
2016-05-05 10:18:09 +00:00
|
|
|
gl_RenderState.Apply();
|
2016-05-04 22:24:47 +00:00
|
|
|
|
|
|
|
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
|
|
|
|
for (unsigned int k = 0; k < sub->numlines; k++)
|
|
|
|
{
|
|
|
|
vertex_t *vt = sub->firstline[k].v1;
|
|
|
|
ptr->x = vt->fX();
|
|
|
|
ptr->z = plane.plane.ZatPoint(vt) + dz;
|
|
|
|
ptr->y = vt->fY();
|
2017-03-12 18:44:00 +00:00
|
|
|
t1 = { ptr->x, ptr->z, ptr->y };
|
|
|
|
FVector3 nearToVert = t1 - nearPt;
|
2016-05-04 22:24:47 +00:00
|
|
|
|
2017-03-12 18:44:00 +00:00
|
|
|
ptr->u = ((nearToVert | right) * scale) + 0.5f;
|
|
|
|
ptr->v = ((nearToVert | up) * scale) + 0.5f;
|
2016-05-04 22:24:47 +00:00
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN);
|
|
|
|
node = node->nextLight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-05 08:28:21 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void GLFlat::DrawLightsCompat(int pass)
|
|
|
|
{
|
|
|
|
gl_RenderState.Apply();
|
2016-08-25 22:04:29 +00:00
|
|
|
// Draw the subsectors belonging to this sector
|
|
|
|
for (int i = 0; i<sector->subsectorcount; i++)
|
2016-05-05 08:28:21 +00:00
|
|
|
{
|
2016-08-25 22:04:29 +00:00
|
|
|
subsector_t * sub = sector->subsectors[i];
|
2017-03-16 23:22:52 +00:00
|
|
|
if (gl_drawinfo->ss_renderflags[sub->Index()] & renderflags)
|
2016-05-05 08:28:21 +00:00
|
|
|
{
|
2016-08-25 22:04:29 +00:00
|
|
|
DrawSubsectorLights(sub, pass);
|
2016-05-05 08:28:21 +00:00
|
|
|
}
|
2016-08-25 22:04:29 +00:00
|
|
|
}
|
2016-05-05 08:28:21 +00:00
|
|
|
|
2016-08-25 22:04:29 +00:00
|
|
|
// Draw the subsectors assigned to it due to missing textures
|
|
|
|
if (!(renderflags&SSRF_RENDER3DPLANES))
|
|
|
|
{
|
|
|
|
gl_subsectorrendernode * node = (renderflags&SSRF_RENDERFLOOR) ?
|
|
|
|
gl_drawinfo->GetOtherFloorPlanes(sector->sectornum) :
|
|
|
|
gl_drawinfo->GetOtherCeilingPlanes(sector->sectornum);
|
2016-05-05 08:28:21 +00:00
|
|
|
|
2016-08-25 22:04:29 +00:00
|
|
|
while (node)
|
|
|
|
{
|
|
|
|
DrawSubsectorLights(node->sub, pass);
|
|
|
|
node = node->next;
|
2016-05-05 08:28:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-05 09:32:21 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Sets up the texture coordinates for one light to be rendered
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2016-05-05 10:18:09 +00:00
|
|
|
bool GLWall::PrepareLight(ADynamicLight * light, int pass)
|
2016-05-05 09:32:21 +00:00
|
|
|
{
|
|
|
|
float vtx[] = { glseg.x1,zbottom[0],glseg.y1, glseg.x1,ztop[0],glseg.y1, glseg.x2,ztop[1],glseg.y2, glseg.x2,zbottom[1],glseg.y2 };
|
|
|
|
Plane p;
|
2017-03-12 18:44:00 +00:00
|
|
|
FVector3 nearPt, up, right;
|
2016-05-05 09:32:21 +00:00
|
|
|
float scale;
|
|
|
|
|
2017-03-12 18:44:00 +00:00
|
|
|
p.Set(&glseg);
|
2016-05-05 09:32:21 +00:00
|
|
|
|
|
|
|
if (!p.ValidNormal())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-09-01 09:52:52 +00:00
|
|
|
if (!gl_SetupLight(seg->frontsector->PortalGroup, p, light, nearPt, up, right, scale, true, pass != GLPASS_LIGHTTEX))
|
2016-05-05 09:32:21 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-03-12 18:44:00 +00:00
|
|
|
FVector3 t1;
|
2016-07-30 07:25:42 +00:00
|
|
|
int outcnt[4] = { 0,0,0,0 };
|
2016-05-05 09:32:21 +00:00
|
|
|
|
2016-07-30 07:25:42 +00:00
|
|
|
for (int i = 0; i<4; i++)
|
|
|
|
{
|
2017-03-12 18:44:00 +00:00
|
|
|
t1 = &vtx[i * 3];
|
|
|
|
FVector3 nearToVert = t1 - nearPt;
|
|
|
|
tcs[i].u = ((nearToVert | right) * scale) + 0.5f;
|
|
|
|
tcs[i].v = ((nearToVert | up) * scale) + 0.5f;
|
2016-05-05 09:32:21 +00:00
|
|
|
|
2016-07-30 07:25:42 +00:00
|
|
|
// quick check whether the light touches this polygon
|
|
|
|
if (tcs[i].u<0) outcnt[0]++;
|
|
|
|
if (tcs[i].u>1) outcnt[1]++;
|
|
|
|
if (tcs[i].v<0) outcnt[2]++;
|
|
|
|
if (tcs[i].v>1) outcnt[3]++;
|
2016-05-05 09:32:21 +00:00
|
|
|
|
|
|
|
}
|
2016-07-30 07:25:42 +00:00
|
|
|
// The light doesn't touch this polygon
|
|
|
|
if (outcnt[0] == 4 || outcnt[1] == 4 || outcnt[2] == 4 || outcnt[3] == 4) return false;
|
2016-05-05 09:32:21 +00:00
|
|
|
|
|
|
|
draw_dlight++;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-05 10:18:09 +00:00
|
|
|
void GLWall::RenderLightsCompat(int pass)
|
|
|
|
{
|
|
|
|
FLightNode * node;
|
|
|
|
|
|
|
|
// black fog is diminishing light and should affect lights less than the rest!
|
2017-03-12 20:57:39 +00:00
|
|
|
if (pass == GLPASS_LIGHTTEX) mDrawer->SetFog((255 + lightlevel) >> 1, 0, NULL, false);
|
|
|
|
else mDrawer->SetFog(lightlevel, 0, &Colormap, true);
|
2016-05-05 10:18:09 +00:00
|
|
|
|
|
|
|
if (seg->sidedef == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (!(seg->sidedef->Flags & WALLF_POLYOBJ))
|
|
|
|
{
|
|
|
|
// Iterate through all dynamic lights which touch this wall and render them
|
|
|
|
node = seg->sidedef->lighthead;
|
|
|
|
}
|
|
|
|
else if (sub)
|
|
|
|
{
|
|
|
|
// To avoid constant rechecking for polyobjects use the subsector's lightlist instead
|
|
|
|
node = sub->lighthead;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
texcoord save[4];
|
|
|
|
memcpy(save, tcs, sizeof(tcs));
|
|
|
|
while (node)
|
|
|
|
{
|
|
|
|
ADynamicLight * light = node->lightsource;
|
|
|
|
|
|
|
|
if (light->flags2&MF2_DORMANT ||
|
|
|
|
(pass == GLPASS_LIGHTTEX && light->IsAdditive()) ||
|
|
|
|
(pass == GLPASS_LIGHTTEX_ADDITIVE && !light->IsAdditive()))
|
|
|
|
{
|
|
|
|
node = node->nextLight;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (PrepareLight(light, pass))
|
|
|
|
{
|
2016-08-25 20:23:31 +00:00
|
|
|
vertcount = 0;
|
2016-08-25 21:02:43 +00:00
|
|
|
RenderWall(RWF_TEXTURED);
|
2016-05-05 10:18:09 +00:00
|
|
|
}
|
|
|
|
node = node->nextLight;
|
|
|
|
}
|
|
|
|
memcpy(tcs, save, sizeof(tcs));
|
2016-08-25 20:23:31 +00:00
|
|
|
vertcount = 0;
|
2016-05-05 10:18:09 +00:00
|
|
|
}
|
|
|
|
|
2016-05-03 21:28:42 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2017-03-12 11:03:54 +00:00
|
|
|
void GLSceneDrawer::RenderMultipassStuff()
|
2016-04-27 22:58:44 +00:00
|
|
|
{
|
|
|
|
// First pass: empty background with sector light only
|
|
|
|
|
|
|
|
// Part 1: solid geometry. This is set up so that there are no transparent parts
|
|
|
|
|
|
|
|
// remove any remaining texture bindings and shaders whick may get in the way.
|
|
|
|
gl_RenderState.EnableTexture(false);
|
|
|
|
gl_RenderState.EnableBrightmap(false);
|
|
|
|
gl_RenderState.Apply();
|
2016-05-04 20:14:39 +00:00
|
|
|
gl_drawinfo->dldrawlists[GLLDL_WALLS_PLAIN].DrawWalls(GLPASS_PLAIN);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_FLATS_PLAIN].DrawFlats(GLPASS_PLAIN);
|
2016-04-27 22:58:44 +00:00
|
|
|
|
|
|
|
// Part 2: masked geometry. This is set up so that only pixels with alpha>0.5 will show
|
|
|
|
// This creates a blank surface that only fills the nontransparent parts of the texture
|
|
|
|
gl_RenderState.EnableTexture(true);
|
|
|
|
gl_RenderState.SetTextureMode(TM_MASK);
|
|
|
|
gl_RenderState.EnableBrightmap(true);
|
2016-05-04 20:14:39 +00:00
|
|
|
gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_threshold);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_WALLS_MASKED].DrawWalls(GLPASS_PLAIN);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_FLATS_MASKED].DrawFlats(GLPASS_PLAIN);
|
2016-04-27 22:58:44 +00:00
|
|
|
|
|
|
|
// Part 3: The base of fogged surfaces, including the texture
|
|
|
|
gl_RenderState.EnableBrightmap(false);
|
|
|
|
gl_RenderState.SetTextureMode(TM_MODULATE);
|
2016-05-04 20:14:39 +00:00
|
|
|
gl_RenderState.AlphaFunc(GL_GEQUAL, 0);
|
2016-04-27 22:58:44 +00:00
|
|
|
gl_drawinfo->dldrawlists[GLLDL_WALLS_FOG].DrawWalls(GLPASS_PLAIN);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_FLATS_FOG].DrawFlats(GLPASS_PLAIN);
|
2016-05-04 20:14:39 +00:00
|
|
|
gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_threshold);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_WALLS_FOGMASKED].DrawWalls(GLPASS_PLAIN);
|
2016-04-27 22:58:44 +00:00
|
|
|
gl_drawinfo->dldrawlists[GLLDL_FLATS_FOGMASKED].DrawFlats(GLPASS_PLAIN);
|
|
|
|
|
|
|
|
// second pass: draw lights
|
|
|
|
glDepthMask(false);
|
2017-03-12 20:57:39 +00:00
|
|
|
if (GLRenderer->mLightCount && !FixedColormap)
|
2016-04-27 22:58:44 +00:00
|
|
|
{
|
|
|
|
if (gl_SetupLightTexture())
|
|
|
|
{
|
|
|
|
gl_RenderState.BlendFunc(GL_ONE, GL_ONE);
|
|
|
|
glDepthFunc(GL_EQUAL);
|
|
|
|
if (glset.lightmode == 8) gl_RenderState.SetSoftLightLevel(255);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_WALLS_PLAIN].DrawWalls(GLPASS_LIGHTTEX);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_WALLS_MASKED].DrawWalls(GLPASS_LIGHTTEX);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_FLATS_PLAIN].DrawFlats(GLPASS_LIGHTTEX);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_FLATS_MASKED].DrawFlats(GLPASS_LIGHTTEX);
|
|
|
|
gl_RenderState.BlendEquation(GL_FUNC_ADD);
|
|
|
|
}
|
|
|
|
else gl_lights = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// third pass: modulated texture
|
|
|
|
gl_RenderState.SetColor(0xffffffff);
|
|
|
|
gl_RenderState.BlendFunc(GL_DST_COLOR, GL_ZERO);
|
|
|
|
gl_RenderState.EnableFog(false);
|
|
|
|
gl_RenderState.AlphaFunc(GL_GEQUAL, 0);
|
|
|
|
glDepthFunc(GL_LEQUAL);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_WALLS_PLAIN].DrawWalls(GLPASS_TEXONLY);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_FLATS_PLAIN].DrawFlats(GLPASS_TEXONLY);
|
|
|
|
gl_RenderState.AlphaFunc(GL_GREATER, gl_mask_threshold);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_WALLS_MASKED].DrawWalls(GLPASS_TEXONLY);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_FLATS_MASKED].DrawFlats(GLPASS_TEXONLY);
|
|
|
|
|
|
|
|
// fourth pass: additive lights
|
|
|
|
gl_RenderState.EnableFog(true);
|
|
|
|
gl_RenderState.BlendFunc(GL_ONE, GL_ONE);
|
|
|
|
glDepthFunc(GL_EQUAL);
|
|
|
|
if (gl_SetupLightTexture())
|
|
|
|
{
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_WALLS_PLAIN].DrawWalls(GLPASS_LIGHTTEX_ADDITIVE);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_WALLS_MASKED].DrawWalls(GLPASS_LIGHTTEX_ADDITIVE);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_FLATS_PLAIN].DrawFlats(GLPASS_LIGHTTEX_ADDITIVE);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_FLATS_MASKED].DrawFlats(GLPASS_LIGHTTEX_ADDITIVE);
|
2016-05-05 10:18:09 +00:00
|
|
|
gl_drawinfo->dldrawlists[GLLDL_WALLS_FOG].DrawWalls(GLPASS_LIGHTTEX_FOGGY);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_WALLS_FOGMASKED].DrawWalls(GLPASS_LIGHTTEX_FOGGY);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_FLATS_FOG].DrawFlats(GLPASS_LIGHTTEX_FOGGY);
|
|
|
|
gl_drawinfo->dldrawlists[GLLDL_FLATS_FOGMASKED].DrawFlats(GLPASS_LIGHTTEX_FOGGY);
|
2016-04-27 22:58:44 +00:00
|
|
|
}
|
|
|
|
else gl_lights = false;
|
2016-05-04 20:14:39 +00:00
|
|
|
|
|
|
|
glDepthFunc(GL_LESS);
|
|
|
|
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
|
|
|
|
gl_RenderState.EnableFog(true);
|
|
|
|
gl_RenderState.BlendFunc(GL_ONE, GL_ZERO);
|
|
|
|
glDepthMask(true);
|
|
|
|
|
2016-05-01 11:09:13 +00:00
|
|
|
}
|
|
|
|
|