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_shader.cpp
|
|
|
|
**
|
|
|
|
** GLSL shader handling
|
|
|
|
**
|
|
|
|
*/
|
2016-09-14 18:01:13 +00:00
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
#include "gl/system/gl_system.h"
|
|
|
|
#include "c_cvars.h"
|
|
|
|
#include "v_video.h"
|
|
|
|
#include "name.h"
|
|
|
|
#include "w_wad.h"
|
|
|
|
#include "i_system.h"
|
|
|
|
#include "doomerrors.h"
|
|
|
|
#include "v_palette.h"
|
|
|
|
#include "sc_man.h"
|
|
|
|
#include "cmdlib.h"
|
|
|
|
|
2013-09-03 16:29:39 +00:00
|
|
|
#include "gl/system/gl_interface.h"
|
2016-08-17 21:18:47 +00:00
|
|
|
#include "gl/system/gl_debug.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
#include "gl/data/gl_data.h"
|
2014-07-13 21:13:40 +00:00
|
|
|
#include "gl/data/gl_matrix.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
#include "gl/renderer/gl_renderer.h"
|
|
|
|
#include "gl/renderer/gl_renderstate.h"
|
|
|
|
#include "gl/system/gl_cvars.h"
|
|
|
|
#include "gl/shaders/gl_shader.h"
|
2016-07-29 19:31:20 +00:00
|
|
|
#include "gl/shaders/gl_shaderprogram.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
#include "gl/textures/gl_material.h"
|
2014-08-01 18:59:39 +00:00
|
|
|
#include "gl/dynlights/gl_lightbuffer.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
bool FShader::Load(const char * name, const char * vert_prog_lump, const char * frag_prog_lump, const char * proc_prog_lump, const char * defines)
|
|
|
|
{
|
|
|
|
static char buffer[10000];
|
|
|
|
FString error;
|
|
|
|
|
2017-01-23 00:56:15 +00:00
|
|
|
int i_lump = Wads.CheckNumForFullName("shaders/glsl/shaderdefs.i", 0);
|
2014-06-21 13:50:32 +00:00
|
|
|
if (i_lump == -1) I_Error("Unable to load 'shaders/glsl/shaderdefs.i'");
|
|
|
|
FMemLump i_data = Wads.ReadLump(i_lump);
|
2014-05-12 12:45:41 +00:00
|
|
|
|
2017-01-23 00:56:15 +00:00
|
|
|
int vp_lump = Wads.CheckNumForFullName(vert_prog_lump, 0);
|
2014-06-21 13:50:32 +00:00
|
|
|
if (vp_lump == -1) I_Error("Unable to load '%s'", vert_prog_lump);
|
|
|
|
FMemLump vp_data = Wads.ReadLump(vp_lump);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2017-01-23 00:56:15 +00:00
|
|
|
int fp_lump = Wads.CheckNumForFullName(frag_prog_lump, 0);
|
2014-06-21 13:50:32 +00:00
|
|
|
if (fp_lump == -1) I_Error("Unable to load '%s'", frag_prog_lump);
|
|
|
|
FMemLump fp_data = Wads.ReadLump(fp_lump);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
//
|
|
|
|
// The following code uses GetChars on the strings to get rid of terminating 0 characters. Do not remove or the code may break!
|
|
|
|
//
|
2014-08-01 18:59:39 +00:00
|
|
|
FString vp_comb;
|
|
|
|
|
2016-09-01 09:52:52 +00:00
|
|
|
assert(GLRenderer->mLights != NULL);
|
|
|
|
// On the shader side there is no difference between LM_DEFERRED and LM_DIRECT, it only decides how the buffer is initialized.
|
|
|
|
unsigned int lightbuffertype = GLRenderer->mLights->GetBufferType();
|
|
|
|
unsigned int lightbuffersize = GLRenderer->mLights->GetBlockSize();
|
|
|
|
if (lightbuffertype == GL_UNIFORM_BUFFER)
|
2014-08-01 18:59:39 +00:00
|
|
|
{
|
2016-09-01 09:52:52 +00:00
|
|
|
// This differentiation is for some Intel drivers which fail on #extension, so use of #version 140 is necessary
|
|
|
|
if (gl.glslversion < 1.4f)
|
2014-10-22 14:54:26 +00:00
|
|
|
{
|
2016-09-01 09:52:52 +00:00
|
|
|
vp_comb.Format("#version 130\n#extension GL_ARB_uniform_buffer_object : require\n#define NUM_UBO_LIGHTS %d\n", lightbuffersize);
|
2014-10-22 14:54:26 +00:00
|
|
|
}
|
2016-04-26 13:01:23 +00:00
|
|
|
else
|
|
|
|
{
|
2016-09-01 09:52:52 +00:00
|
|
|
vp_comb.Format("#version 140\n#define NUM_UBO_LIGHTS %d\n", lightbuffersize);
|
2016-04-26 13:01:23 +00:00
|
|
|
}
|
2014-08-01 18:59:39 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-09-01 09:52:52 +00:00
|
|
|
vp_comb = "#version 400 core\n#extension GL_ARB_shader_storage_buffer_object : require\n#define SHADER_STORAGE_LIGHTS\n";
|
2014-06-30 16:10:55 +00:00
|
|
|
}
|
2016-09-01 09:52:52 +00:00
|
|
|
|
2016-08-29 08:43:03 +00:00
|
|
|
if (gl.buffermethod == BM_DEFERRED)
|
2016-08-22 13:31:23 +00:00
|
|
|
{
|
|
|
|
vp_comb << "#define USE_QUAD_DRAWER\n";
|
|
|
|
}
|
2014-06-30 16:10:55 +00:00
|
|
|
|
2017-03-10 18:10:40 +00:00
|
|
|
if (!!(gl.flags & RFL_SHADER_STORAGE_BUFFER))
|
|
|
|
{
|
|
|
|
vp_comb << "#define SUPPORTS_SHADOWMAPS\n";
|
|
|
|
}
|
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
vp_comb << defines << i_data.GetString().GetChars();
|
|
|
|
FString fp_comb = vp_comb;
|
2014-05-12 12:45:41 +00:00
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
vp_comb << vp_data.GetString().GetChars() << "\n";
|
|
|
|
fp_comb << fp_data.GetString().GetChars() << "\n";
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
if (proc_prog_lump != NULL)
|
|
|
|
{
|
|
|
|
if (*proc_prog_lump != '#')
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2014-06-21 13:50:32 +00:00
|
|
|
int pp_lump = Wads.CheckNumForFullName(proc_prog_lump);
|
|
|
|
if (pp_lump == -1) I_Error("Unable to load '%s'", proc_prog_lump);
|
|
|
|
FMemLump pp_data = Wads.ReadLump(pp_lump);
|
|
|
|
|
|
|
|
if (pp_data.GetString().IndexOf("ProcessTexel") < 0)
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2014-06-21 13:50:32 +00:00
|
|
|
// this looks like an old custom hardware shader.
|
|
|
|
// We need to replace the ProcessTexel call to make it work.
|
|
|
|
|
|
|
|
fp_comb.Substitute("vec4 frag = ProcessTexel();", "vec4 frag = Process(vec4(1.0));");
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
2014-06-21 13:50:32 +00:00
|
|
|
fp_comb << pp_data.GetString().GetChars();
|
2014-07-14 22:37:13 +00:00
|
|
|
fp_comb.Substitute("gl_TexCoord[0]", "vTexCoord"); // fix old custom shaders.
|
2014-06-21 13:50:32 +00:00
|
|
|
|
|
|
|
if (pp_data.GetString().IndexOf("ProcessLight") < 0)
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2014-06-21 13:50:32 +00:00
|
|
|
int pl_lump = Wads.CheckNumForFullName("shaders/glsl/func_defaultlight.fp");
|
|
|
|
if (pl_lump == -1) I_Error("Unable to load '%s'", "shaders/glsl/func_defaultlight.fp");
|
|
|
|
FMemLump pl_data = Wads.ReadLump(pl_lump);
|
|
|
|
fp_comb << "\n" << pl_data.GetString().GetChars();
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-21 13:50:32 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// Proc_prog_lump is not a lump name but the source itself (from generated shaders)
|
|
|
|
fp_comb << proc_prog_lump + 1;
|
|
|
|
}
|
|
|
|
}
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2016-09-01 09:52:52 +00:00
|
|
|
if (gl.flags & RFL_NO_CLIP_PLANES)
|
2016-08-08 10:55:09 +00:00
|
|
|
{
|
|
|
|
// On ATI's GL3 drivers we have to disable gl_ClipDistance because it's hopelessly broken.
|
|
|
|
// This will cause some glitches and regressions but is the only way to avoid total display garbage.
|
|
|
|
vp_comb.Substitute("gl_ClipDistance", "//");
|
|
|
|
}
|
2016-04-26 13:01:23 +00:00
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
hVertProg = glCreateShader(GL_VERTEX_SHADER);
|
|
|
|
hFragProg = glCreateShader(GL_FRAGMENT_SHADER);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2016-08-17 21:18:47 +00:00
|
|
|
FGLDebug::LabelObject(GL_SHADER, hVertProg, vert_prog_lump);
|
|
|
|
FGLDebug::LabelObject(GL_SHADER, hFragProg, frag_prog_lump);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
int vp_size = (int)vp_comb.Len();
|
|
|
|
int fp_size = (int)fp_comb.Len();
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
const char *vp_ptr = vp_comb.GetChars();
|
|
|
|
const char *fp_ptr = fp_comb.GetChars();
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
glShaderSource(hVertProg, 1, &vp_ptr, &vp_size);
|
|
|
|
glShaderSource(hFragProg, 1, &fp_ptr, &fp_size);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
glCompileShader(hVertProg);
|
|
|
|
glCompileShader(hFragProg);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
hShader = glCreateProgram();
|
2016-08-17 21:18:47 +00:00
|
|
|
FGLDebug::LabelObject(GL_PROGRAM, hShader, name);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
glAttachShader(hShader, hVertProg);
|
|
|
|
glAttachShader(hShader, hFragProg);
|
2014-07-14 22:59:01 +00:00
|
|
|
|
2014-07-14 23:02:48 +00:00
|
|
|
glBindAttribLocation(hShader, VATTR_VERTEX, "aPosition");
|
2014-07-14 22:59:01 +00:00
|
|
|
glBindAttribLocation(hShader, VATTR_TEXCOORD, "aTexCoord");
|
2014-07-14 22:37:13 +00:00
|
|
|
glBindAttribLocation(hShader, VATTR_COLOR, "aColor");
|
|
|
|
glBindAttribLocation(hShader, VATTR_VERTEX2, "aVertex2");
|
2016-10-03 14:09:32 +00:00
|
|
|
glBindAttribLocation(hShader, VATTR_NORMAL, "aNormal");
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2016-09-20 00:57:57 +00:00
|
|
|
glBindFragDataLocation(hShader, 0, "FragColor");
|
2016-10-05 05:57:27 +00:00
|
|
|
glBindFragDataLocation(hShader, 1, "FragFog");
|
|
|
|
glBindFragDataLocation(hShader, 2, "FragNormal");
|
2016-09-20 00:57:57 +00:00
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
glLinkProgram(hShader);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
glGetShaderInfoLog(hVertProg, 10000, NULL, buffer);
|
|
|
|
if (*buffer)
|
|
|
|
{
|
|
|
|
error << "Vertex shader:\n" << buffer << "\n";
|
|
|
|
}
|
|
|
|
glGetShaderInfoLog(hFragProg, 10000, NULL, buffer);
|
|
|
|
if (*buffer)
|
|
|
|
{
|
|
|
|
error << "Fragment shader:\n" << buffer << "\n";
|
|
|
|
}
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
glGetProgramInfoLog(hShader, 10000, NULL, buffer);
|
|
|
|
if (*buffer)
|
|
|
|
{
|
|
|
|
error << "Linking:\n" << buffer << "\n";
|
|
|
|
}
|
|
|
|
int linked;
|
|
|
|
glGetProgramiv(hShader, GL_LINK_STATUS, &linked);
|
|
|
|
if (linked == 0)
|
|
|
|
{
|
|
|
|
// only print message if there's an error.
|
|
|
|
I_Error("Init Shader '%s':\n%s\n", name, error.GetChars());
|
|
|
|
}
|
2014-05-12 12:45:41 +00:00
|
|
|
|
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
muDesaturation.Init(hShader, "uDesaturationFactor");
|
|
|
|
muFogEnabled.Init(hShader, "uFogEnabled");
|
2017-01-24 18:44:12 +00:00
|
|
|
muPalLightLevels.Init(hShader, "uPalLightLevels");
|
2014-06-21 13:50:32 +00:00
|
|
|
muTextureMode.Init(hShader, "uTextureMode");
|
|
|
|
muCameraPos.Init(hShader, "uCameraPos");
|
|
|
|
muLightParms.Init(hShader, "uLightAttr");
|
2015-04-05 16:55:21 +00:00
|
|
|
muClipSplit.Init(hShader, "uClipSplit");
|
2014-06-21 13:50:32 +00:00
|
|
|
muColormapStart.Init(hShader, "uFixedColormapStart");
|
|
|
|
muColormapRange.Init(hShader, "uFixedColormapRange");
|
2014-08-01 18:59:39 +00:00
|
|
|
muLightIndex.Init(hShader, "uLightIndex");
|
2014-06-21 13:50:32 +00:00
|
|
|
muFogColor.Init(hShader, "uFogColor");
|
|
|
|
muDynLightColor.Init(hShader, "uDynLightColor");
|
|
|
|
muObjectColor.Init(hShader, "uObjectColor");
|
2017-01-28 17:19:58 +00:00
|
|
|
muObjectColor2.Init(hShader, "uObjectColor2");
|
2014-06-21 13:50:32 +00:00
|
|
|
muGlowBottomColor.Init(hShader, "uGlowBottomColor");
|
|
|
|
muGlowTopColor.Init(hShader, "uGlowTopColor");
|
|
|
|
muGlowBottomPlane.Init(hShader, "uGlowBottomPlane");
|
|
|
|
muGlowTopPlane.Init(hShader, "uGlowTopPlane");
|
2016-01-30 22:01:11 +00:00
|
|
|
muSplitBottomPlane.Init(hShader, "uSplitBottomPlane");
|
|
|
|
muSplitTopPlane.Init(hShader, "uSplitTopPlane");
|
2016-04-28 23:48:06 +00:00
|
|
|
muClipLine.Init(hShader, "uClipLine");
|
2014-06-21 13:50:32 +00:00
|
|
|
muFixedColormap.Init(hShader, "uFixedColormap");
|
2014-06-29 09:00:21 +00:00
|
|
|
muInterpolationFactor.Init(hShader, "uInterpolationFactor");
|
2016-04-26 22:41:00 +00:00
|
|
|
muClipHeight.Init(hShader, "uClipHeight");
|
|
|
|
muClipHeightDirection.Init(hShader, "uClipHeightDirection");
|
2014-07-14 19:14:43 +00:00
|
|
|
muAlphaThreshold.Init(hShader, "uAlphaThreshold");
|
2014-07-26 18:56:10 +00:00
|
|
|
muTimer.Init(hShader, "timer");
|
2014-05-12 12:45:41 +00:00
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
lights_index = glGetUniformLocation(hShader, "lights");
|
2014-06-30 16:10:55 +00:00
|
|
|
fakevb_index = glGetUniformLocation(hShader, "fakeVB");
|
2014-07-13 21:13:40 +00:00
|
|
|
projectionmatrix_index = glGetUniformLocation(hShader, "ProjectionMatrix");
|
|
|
|
viewmatrix_index = glGetUniformLocation(hShader, "ViewMatrix");
|
2014-07-13 18:41:20 +00:00
|
|
|
modelmatrix_index = glGetUniformLocation(hShader, "ModelMatrix");
|
|
|
|
texturematrix_index = glGetUniformLocation(hShader, "TextureMatrix");
|
2016-08-22 12:00:25 +00:00
|
|
|
vertexmatrix_index = glGetUniformLocation(hShader, "uQuadVertices");
|
|
|
|
texcoordmatrix_index = glGetUniformLocation(hShader, "uQuadTexCoords");
|
2016-10-03 14:09:32 +00:00
|
|
|
normalviewmatrix_index = glGetUniformLocation(hShader, "NormalViewMatrix");
|
|
|
|
normalmodelmatrix_index = glGetUniformLocation(hShader, "NormalModelMatrix");
|
2016-08-22 12:00:25 +00:00
|
|
|
quadmode_index = glGetUniformLocation(hShader, "uQuadMode");
|
2013-09-03 16:29:39 +00:00
|
|
|
|
2016-09-01 09:52:52 +00:00
|
|
|
if (!gl.legacyMode && !(gl.flags & RFL_SHADER_STORAGE_BUFFER))
|
2016-05-01 08:46:49 +00:00
|
|
|
{
|
|
|
|
int tempindex = glGetUniformBlockIndex(hShader, "LightBufferUBO");
|
|
|
|
if (tempindex != -1) glUniformBlockBinding(hShader, tempindex, LIGHTBUF_BINDINGPOINT);
|
|
|
|
}
|
2014-08-01 18:59:39 +00:00
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
glUseProgram(hShader);
|
2016-08-22 13:31:23 +00:00
|
|
|
if (quadmode_index > 0) glUniform1i(quadmode_index, 0);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2014-09-09 08:03:34 +00:00
|
|
|
// set up other texture units (if needed by the shader)
|
|
|
|
for (int i = 2; i<16; i++)
|
|
|
|
{
|
|
|
|
char stringbuf[20];
|
|
|
|
mysnprintf(stringbuf, 20, "texture%d", i);
|
2016-05-01 08:46:49 +00:00
|
|
|
int tempindex = glGetUniformLocation(hShader, stringbuf);
|
2014-09-09 08:03:34 +00:00
|
|
|
if (tempindex > 0) glUniform1i(tempindex, i - 1);
|
|
|
|
}
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2017-03-02 18:10:57 +00:00
|
|
|
int shadowmapindex = glGetUniformLocation(hShader, "ShadowMap");
|
|
|
|
if (shadowmapindex > 0) glUniform1i(shadowmapindex, 16);
|
|
|
|
|
2014-06-21 13:50:32 +00:00
|
|
|
glUseProgram(0);
|
|
|
|
return !!linked;
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FShader::~FShader()
|
|
|
|
{
|
2014-06-21 13:50:32 +00:00
|
|
|
glDeleteProgram(hShader);
|
|
|
|
glDeleteShader(hVertProg);
|
|
|
|
glDeleteShader(hFragProg);
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2014-05-12 12:45:41 +00:00
|
|
|
bool FShader::Bind()
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
|
|
|
GLRenderer->mShaderManager->SetActiveShader(this);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
2014-05-12 12:45:41 +00:00
|
|
|
// Since all shaders are REQUIRED, any error here needs to be fatal
|
2013-06-23 07:49:34 +00:00
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2016-09-20 00:57:57 +00:00
|
|
|
FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderPath, bool usediscard, EPassType passType)
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2014-07-13 11:25:42 +00:00
|
|
|
FString defines;
|
2014-05-12 12:45:41 +00:00
|
|
|
// this can't be in the shader code due to ATI strangeness.
|
2014-07-13 11:25:42 +00:00
|
|
|
if (gl.MaxLights() == 128) defines += "#define MAXLIGHTS128\n";
|
2014-07-30 22:44:22 +00:00
|
|
|
if (!usediscard) defines += "#define NO_ALPHATEST\n";
|
2016-09-20 00:57:57 +00:00
|
|
|
if (passType == GBUFFER_PASS) defines += "#define GBUFFER_PASS\n";
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2014-05-12 12:45:41 +00:00
|
|
|
FShader *shader = NULL;
|
2013-06-23 07:49:34 +00:00
|
|
|
try
|
|
|
|
{
|
2014-05-12 12:45:41 +00:00
|
|
|
shader = new FShader(ShaderName);
|
2014-07-13 11:25:42 +00:00
|
|
|
if (!shader->Load(ShaderName, "shaders/glsl/main.vp", "shaders/glsl/main.fp", ShaderPath, defines.GetChars()))
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2014-06-23 07:26:29 +00:00
|
|
|
I_FatalError("Unable to load shader %s\n", ShaderName);
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(CRecoverableError &err)
|
|
|
|
{
|
2014-05-12 12:45:41 +00:00
|
|
|
if (shader != NULL) delete shader;
|
|
|
|
shader = NULL;
|
2014-06-23 07:26:29 +00:00
|
|
|
I_FatalError("Unable to load shader %s:\n%s\n", ShaderName, err.GetMessage());
|
2013-12-05 14:06:10 +00:00
|
|
|
}
|
2014-05-12 12:45:41 +00:00
|
|
|
return shader;
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
|
2014-07-13 21:13:40 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2016-10-03 14:09:32 +00:00
|
|
|
void FShader::ApplyMatrices(VSMatrix *proj, VSMatrix *view, VSMatrix *norm)
|
2014-07-13 21:13:40 +00:00
|
|
|
{
|
2014-08-02 09:57:42 +00:00
|
|
|
Bind();
|
|
|
|
glUniformMatrix4fv(projectionmatrix_index, 1, false, proj->get());
|
|
|
|
glUniformMatrix4fv(viewmatrix_index, 1, false, view->get());
|
2016-10-03 14:09:32 +00:00
|
|
|
glUniformMatrix4fv(normalviewmatrix_index, 1, false, norm->get());
|
2014-07-13 21:13:40 +00:00
|
|
|
}
|
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
struct FDefaultShader
|
|
|
|
{
|
|
|
|
const char * ShaderName;
|
|
|
|
const char * gettexelfunc;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Note: the FIRST_USER_SHADER constant in gl_shader.h needs
|
|
|
|
// to be updated whenever the size of this array is modified.
|
|
|
|
static const FDefaultShader defaultshaders[]=
|
|
|
|
{
|
|
|
|
{"Default", "shaders/glsl/func_normal.fp"},
|
|
|
|
{"Warp 1", "shaders/glsl/func_warp1.fp"},
|
|
|
|
{"Warp 2", "shaders/glsl/func_warp2.fp"},
|
|
|
|
{"Brightmap","shaders/glsl/func_brightmap.fp"},
|
|
|
|
{"No Texture", "shaders/glsl/func_notexture.fp"},
|
|
|
|
{"Basic Fuzz", "shaders/glsl/fuzz_standard.fp"},
|
|
|
|
{"Smooth Fuzz", "shaders/glsl/fuzz_smooth.fp"},
|
|
|
|
{"Swirly Fuzz", "shaders/glsl/fuzz_swirly.fp"},
|
|
|
|
{"Translucent Fuzz", "shaders/glsl/fuzz_smoothtranslucent.fp"},
|
|
|
|
{"Jagged Fuzz", "shaders/glsl/fuzz_jagged.fp"},
|
|
|
|
{"Noise Fuzz", "shaders/glsl/fuzz_noise.fp"},
|
|
|
|
{"Smooth Noise Fuzz", "shaders/glsl/fuzz_smoothnoise.fp"},
|
|
|
|
{NULL,NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static TArray<FString> usershaders;
|
|
|
|
|
|
|
|
struct FEffectShader
|
|
|
|
{
|
|
|
|
const char *ShaderName;
|
|
|
|
const char *vp;
|
|
|
|
const char *fp1;
|
|
|
|
const char *fp2;
|
|
|
|
const char *defines;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const FEffectShader effectshaders[]=
|
|
|
|
{
|
2014-07-30 22:44:22 +00:00
|
|
|
{ "fogboundary", "shaders/glsl/main.vp", "shaders/glsl/fogboundary.fp", NULL, "#define NO_ALPHATEST\n" },
|
|
|
|
{ "spheremap", "shaders/glsl/main.vp", "shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "#define SPHEREMAP\n#define NO_ALPHATEST\n" },
|
|
|
|
{ "burn", "shaders/glsl/main.vp", "shaders/glsl/burn.fp", NULL, "#define SIMPLE\n#define NO_ALPHATEST\n" },
|
|
|
|
{ "stencil", "shaders/glsl/main.vp", "shaders/glsl/stencil.fp", NULL, "#define SIMPLE\n#define NO_ALPHATEST\n" },
|
2013-06-23 07:49:34 +00:00
|
|
|
};
|
|
|
|
|
2016-09-20 00:57:57 +00:00
|
|
|
FShaderManager::FShaderManager()
|
|
|
|
{
|
|
|
|
if (!gl.legacyMode)
|
|
|
|
{
|
|
|
|
for (int passType = 0; passType < MAX_PASS_TYPES; passType++)
|
|
|
|
mPassShaders.Push(new FShaderCollection((EPassType)passType));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FShaderManager::~FShaderManager()
|
|
|
|
{
|
|
|
|
if (!gl.legacyMode)
|
|
|
|
{
|
|
|
|
glUseProgram(0);
|
|
|
|
mActiveShader = NULL;
|
|
|
|
|
|
|
|
for (auto collection : mPassShaders)
|
|
|
|
delete collection;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FShaderManager::SetActiveShader(FShader *sh)
|
|
|
|
{
|
|
|
|
if (mActiveShader != sh)
|
|
|
|
{
|
|
|
|
glUseProgram(sh!= NULL? sh->GetHandle() : 0);
|
|
|
|
mActiveShader = sh;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FShader *FShaderManager::BindEffect(int effect, EPassType passType)
|
|
|
|
{
|
|
|
|
if (passType < mPassShaders.Size())
|
|
|
|
return mPassShaders[passType]->BindEffect(effect);
|
|
|
|
else
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
FShader *FShaderManager::Get(unsigned int eff, bool alphateston, EPassType passType)
|
|
|
|
{
|
|
|
|
if (passType < mPassShaders.Size())
|
|
|
|
return mPassShaders[passType]->Get(eff, alphateston);
|
|
|
|
else
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FShaderManager::ApplyMatrices(VSMatrix *proj, VSMatrix *view, EPassType passType)
|
|
|
|
{
|
|
|
|
if (gl.legacyMode)
|
|
|
|
{
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadMatrixf(proj->get());
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadMatrixf(view->get());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (passType < mPassShaders.Size())
|
|
|
|
mPassShaders[passType]->ApplyMatrices(proj, view);
|
|
|
|
|
|
|
|
if (mActiveShader)
|
|
|
|
mActiveShader->Bind();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FShaderManager::ResetFixedColormap()
|
|
|
|
{
|
|
|
|
for (auto &collection : mPassShaders)
|
|
|
|
collection->ResetFixedColormap();
|
|
|
|
}
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2016-09-20 00:57:57 +00:00
|
|
|
FShaderCollection::FShaderCollection(EPassType passType)
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2016-09-20 00:57:57 +00:00
|
|
|
CompileShaders(passType);
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2016-09-20 00:57:57 +00:00
|
|
|
FShaderCollection::~FShaderCollection()
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2016-09-20 00:57:57 +00:00
|
|
|
Clean();
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2016-09-20 00:57:57 +00:00
|
|
|
void FShaderCollection::CompileShaders(EPassType passType)
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2014-08-02 19:06:34 +00:00
|
|
|
mTextureEffects.Clear();
|
|
|
|
mTextureEffectsNAT.Clear();
|
2014-07-13 11:25:42 +00:00
|
|
|
for (int i = 0; i < MAX_EFFECTS; i++)
|
|
|
|
{
|
|
|
|
mEffectShaders[i] = NULL;
|
|
|
|
}
|
2014-06-23 07:26:29 +00:00
|
|
|
|
|
|
|
for(int i=0;defaultshaders[i].ShaderName != NULL;i++)
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2016-09-20 00:57:57 +00:00
|
|
|
FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, true, passType);
|
2014-06-23 07:26:29 +00:00
|
|
|
mTextureEffects.Push(shc);
|
2014-08-02 19:06:34 +00:00
|
|
|
if (i <= 3)
|
|
|
|
{
|
2016-09-20 00:57:57 +00:00
|
|
|
FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, false, passType);
|
2014-08-02 19:06:34 +00:00
|
|
|
mTextureEffectsNAT.Push(shc);
|
|
|
|
}
|
2014-06-23 07:26:29 +00:00
|
|
|
}
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2014-06-23 07:26:29 +00:00
|
|
|
for(unsigned i = 0; i < usershaders.Size(); i++)
|
|
|
|
{
|
|
|
|
FString name = ExtractFileBase(usershaders[i]);
|
|
|
|
FName sfn = name;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2016-09-20 00:57:57 +00:00
|
|
|
FShader *shc = Compile(sfn, usershaders[i], true, passType);
|
2014-06-23 07:26:29 +00:00
|
|
|
mTextureEffects.Push(shc);
|
|
|
|
}
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2014-06-23 07:26:29 +00:00
|
|
|
for(int i=0;i<MAX_EFFECTS;i++)
|
|
|
|
{
|
|
|
|
FShader *eff = new FShader(effectshaders[i].ShaderName);
|
|
|
|
if (!eff->Load(effectshaders[i].ShaderName, effectshaders[i].vp, effectshaders[i].fp1,
|
|
|
|
effectshaders[i].fp2, effectshaders[i].defines))
|
2014-06-21 13:50:32 +00:00
|
|
|
{
|
2014-06-23 07:26:29 +00:00
|
|
|
delete eff;
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
2014-06-23 07:26:29 +00:00
|
|
|
else mEffectShaders[i] = eff;
|
2014-05-12 12:45:41 +00:00
|
|
|
}
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2016-09-20 00:57:57 +00:00
|
|
|
void FShaderCollection::Clean()
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2014-08-02 19:06:34 +00:00
|
|
|
for (unsigned int i = 0; i < mTextureEffectsNAT.Size(); i++)
|
|
|
|
{
|
|
|
|
if (mTextureEffectsNAT[i] != NULL) delete mTextureEffectsNAT[i];
|
|
|
|
}
|
2014-06-21 13:50:32 +00:00
|
|
|
for (unsigned int i = 0; i < mTextureEffects.Size(); i++)
|
|
|
|
{
|
|
|
|
if (mTextureEffects[i] != NULL) delete mTextureEffects[i];
|
|
|
|
}
|
|
|
|
for (int i = 0; i < MAX_EFFECTS; i++)
|
|
|
|
{
|
|
|
|
if (mEffectShaders[i] != NULL) delete mEffectShaders[i];
|
|
|
|
mEffectShaders[i] = NULL;
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
2014-06-21 13:50:32 +00:00
|
|
|
mTextureEffects.Clear();
|
2014-08-02 19:06:34 +00:00
|
|
|
mTextureEffectsNAT.Clear();
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2016-09-20 00:57:57 +00:00
|
|
|
int FShaderCollection::Find(const char * shn)
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
|
|
|
FName sfn = shn;
|
|
|
|
|
|
|
|
for(unsigned int i=0;i<mTextureEffects.Size();i++)
|
|
|
|
{
|
2014-05-12 12:45:41 +00:00
|
|
|
if (mTextureEffects[i]->mName == sfn)
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-05-12 12:45:41 +00:00
|
|
|
|
2014-06-23 07:26:29 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
2013-06-23 07:49:34 +00:00
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2016-09-20 00:57:57 +00:00
|
|
|
FShader *FShaderCollection::BindEffect(int effect)
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2014-05-12 12:45:41 +00:00
|
|
|
if (effect >= 0 && effect < MAX_EFFECTS && mEffectShaders[effect] != NULL)
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2014-05-12 12:45:41 +00:00
|
|
|
mEffectShaders[effect]->Bind();
|
|
|
|
return mEffectShaders[effect];
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-13 21:13:40 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
EXTERN_CVAR(Int, gl_fuzztype)
|
|
|
|
|
2016-09-20 00:57:57 +00:00
|
|
|
void FShaderCollection::ApplyMatrices(VSMatrix *proj, VSMatrix *view)
|
2014-07-13 21:13:40 +00:00
|
|
|
{
|
2016-10-03 22:01:03 +00:00
|
|
|
VSMatrix norm;
|
|
|
|
norm.computeNormalMatrix(*view);
|
|
|
|
|
2016-09-20 00:57:57 +00:00
|
|
|
for (int i = 0; i < 4; i++)
|
2014-07-13 21:13:40 +00:00
|
|
|
{
|
2016-10-03 22:01:03 +00:00
|
|
|
mTextureEffects[i]->ApplyMatrices(proj, view, &norm);
|
|
|
|
mTextureEffectsNAT[i]->ApplyMatrices(proj, view, &norm);
|
2014-07-13 21:13:40 +00:00
|
|
|
}
|
2016-10-03 22:01:03 +00:00
|
|
|
mTextureEffects[4]->ApplyMatrices(proj, view, &norm);
|
2016-09-20 00:57:57 +00:00
|
|
|
if (gl_fuzztype != 0)
|
2014-07-13 21:13:40 +00:00
|
|
|
{
|
2016-10-03 22:01:03 +00:00
|
|
|
mTextureEffects[4 + gl_fuzztype]->ApplyMatrices(proj, view, &norm);
|
2016-09-20 00:57:57 +00:00
|
|
|
}
|
|
|
|
for (unsigned i = 12; i < mTextureEffects.Size(); i++)
|
|
|
|
{
|
2016-10-03 22:01:03 +00:00
|
|
|
mTextureEffects[i]->ApplyMatrices(proj, view, &norm);
|
2016-09-20 00:57:57 +00:00
|
|
|
}
|
|
|
|
for (int i = 0; i < MAX_EFFECTS; i++)
|
|
|
|
{
|
2016-10-03 22:01:03 +00:00
|
|
|
mEffectShaders[i]->ApplyMatrices(proj, view, &norm);
|
2014-07-13 21:13:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void gl_DestroyUserShaders()
|
|
|
|
{
|
|
|
|
// todo
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Parses a shader definition
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void gl_ParseHardwareShader(FScanner &sc, int deflump)
|
|
|
|
{
|
|
|
|
int type = FTexture::TEX_Any;
|
|
|
|
bool disable_fullbright=false;
|
|
|
|
bool thiswad = false;
|
|
|
|
bool iwad = false;
|
|
|
|
int maplump = -1;
|
|
|
|
FString maplumpname;
|
|
|
|
float speed = 1.f;
|
|
|
|
|
|
|
|
sc.MustGetString();
|
|
|
|
if (sc.Compare("texture")) type = FTexture::TEX_Wall;
|
|
|
|
else if (sc.Compare("flat")) type = FTexture::TEX_Flat;
|
|
|
|
else if (sc.Compare("sprite")) type = FTexture::TEX_Sprite;
|
|
|
|
else sc.UnGet();
|
|
|
|
|
|
|
|
sc.MustGetString();
|
|
|
|
FTextureID no = TexMan.CheckForTexture(sc.String, type);
|
|
|
|
FTexture *tex = TexMan[no];
|
|
|
|
|
|
|
|
sc.MustGetToken('{');
|
|
|
|
while (!sc.CheckToken('}'))
|
|
|
|
{
|
|
|
|
sc.MustGetString();
|
|
|
|
if (sc.Compare("shader"))
|
|
|
|
{
|
|
|
|
sc.MustGetString();
|
|
|
|
maplumpname = sc.String;
|
|
|
|
}
|
|
|
|
else if (sc.Compare("speed"))
|
|
|
|
{
|
|
|
|
sc.MustGetFloat();
|
|
|
|
speed = float(sc.Float);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!tex)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (maplumpname.IsNotEmpty())
|
|
|
|
{
|
|
|
|
if (tex->bWarped != 0)
|
|
|
|
{
|
2014-06-01 07:27:16 +00:00
|
|
|
Printf("Cannot combine warping with hardware shader on texture '%s'\n", tex->Name.GetChars());
|
2013-06-23 07:49:34 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
tex->gl_info.shaderspeed = speed;
|
|
|
|
for(unsigned i=0;i<usershaders.Size();i++)
|
|
|
|
{
|
|
|
|
if (!usershaders[i].CompareNoCase(maplumpname))
|
|
|
|
{
|
|
|
|
tex->gl_info.shaderindex = i + FIRST_USER_SHADER;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tex->gl_info.shaderindex = usershaders.Push(maplumpname) + FIRST_USER_SHADER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|