2013-06-23 07:49:34 +00:00
|
|
|
/*
|
|
|
|
** gl_shader.cpp
|
|
|
|
**
|
|
|
|
** GLSL shader handling
|
|
|
|
**
|
|
|
|
**---------------------------------------------------------------------------
|
|
|
|
** Copyright 2004-2009 Christoph Oelckers
|
|
|
|
** All rights reserved.
|
|
|
|
**
|
|
|
|
** Redistribution and use in source and binary forms, with or without
|
|
|
|
** modification, are permitted provided that the following conditions
|
|
|
|
** are met:
|
|
|
|
**
|
|
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
|
|
** notice, this list of conditions and the following disclaimer.
|
|
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
|
|
** documentation and/or other materials provided with the distribution.
|
|
|
|
** 3. The name of the author may not be used to endorse or promote products
|
|
|
|
** derived from this software without specific prior written permission.
|
|
|
|
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
|
|
|
|
** covered by the terms of the GNU Lesser General Public License as published
|
|
|
|
** by the Free Software Foundation; either version 2.1 of the License, or (at
|
|
|
|
** your option) any later version.
|
|
|
|
** 5. Full disclosure of the entire project's source code, except for third
|
|
|
|
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
|
|
|
**
|
|
|
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
**---------------------------------------------------------------------------
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
#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"
|
2013-06-23 07:49:34 +00:00
|
|
|
#include "gl/data/gl_data.h"
|
|
|
|
#include "gl/renderer/gl_renderer.h"
|
|
|
|
#include "gl/renderer/gl_renderstate.h"
|
|
|
|
#include "gl/system/gl_cvars.h"
|
|
|
|
#include "gl/shaders/gl_shader.h"
|
|
|
|
#include "gl/textures/gl_material.h"
|
|
|
|
|
|
|
|
// these will only have an effect on SM3 cards.
|
|
|
|
// For SM4 they are always on and for SM2 always off
|
|
|
|
CVAR(Bool, gl_warp_shader, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
|
|
|
|
CVAR(Bool, gl_fog_shader, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
|
|
|
|
CVAR(Bool, gl_colormap_shader, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
|
|
|
|
CVAR(Bool, gl_brightmap_shader, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
|
|
|
|
CVAR(Bool, gl_glow_shader, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
|
|
|
|
|
|
|
|
|
|
|
|
extern long gl_frameMS;
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (gl.shadermodel > 0)
|
|
|
|
{
|
|
|
|
int vp_lump = Wads.CheckNumForFullName(vert_prog_lump);
|
|
|
|
if (vp_lump == -1) I_Error("Unable to load '%s'", vert_prog_lump);
|
|
|
|
FMemLump vp_data = Wads.ReadLump(vp_lump);
|
|
|
|
|
|
|
|
int fp_lump = Wads.CheckNumForFullName(frag_prog_lump);
|
|
|
|
if (fp_lump == -1) I_Error("Unable to load '%s'", frag_prog_lump);
|
|
|
|
FMemLump fp_data = Wads.ReadLump(fp_lump);
|
|
|
|
|
|
|
|
|
|
|
|
FString vp_comb;
|
|
|
|
FString fp_comb;
|
|
|
|
vp_comb = defines;
|
|
|
|
if (gl.shadermodel < 4)
|
|
|
|
{
|
|
|
|
vp_comb << "#define NO_SM4\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
fp_comb = vp_comb;
|
|
|
|
// This uses GetChars on the strings to get rid of terminating 0 characters.
|
|
|
|
vp_comb << vp_data.GetString().GetChars() << "\n";
|
|
|
|
fp_comb << fp_data.GetString().GetChars() << "\n";
|
|
|
|
|
|
|
|
if (proc_prog_lump != NULL)
|
|
|
|
{
|
|
|
|
if (*proc_prog_lump != '#')
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
|
|
|
fp_comb << pp_data.GetString().GetChars();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Proc_prog_lump is not a lump name but the source itself (from generated shaders)
|
|
|
|
fp_comb << proc_prog_lump+1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-03 16:29:39 +00:00
|
|
|
hVertProg = glCreateShader(GL_VERTEX_SHADER);
|
|
|
|
hFragProg = glCreateShader(GL_FRAGMENT_SHADER);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
int vp_size = (int)vp_comb.Len();
|
|
|
|
int fp_size = (int)fp_comb.Len();
|
|
|
|
|
|
|
|
const char *vp_ptr = vp_comb.GetChars();
|
|
|
|
const char *fp_ptr = fp_comb.GetChars();
|
|
|
|
|
2013-09-03 16:29:39 +00:00
|
|
|
glShaderSource(hVertProg, 1, &vp_ptr, &vp_size);
|
|
|
|
glShaderSource(hFragProg, 1, &fp_ptr, &fp_size);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2013-09-03 16:29:39 +00:00
|
|
|
glCompileShader(hVertProg);
|
|
|
|
glCompileShader(hFragProg);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2013-09-03 16:29:39 +00:00
|
|
|
hShader = glCreateProgram();
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2013-09-03 16:29:39 +00:00
|
|
|
glAttachShader(hShader, hVertProg);
|
|
|
|
glAttachShader(hShader, hFragProg);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2013-09-03 16:29:39 +00:00
|
|
|
glBindAttribLocation(hShader, VATTR_GLOWDISTANCE, "glowdistance");
|
|
|
|
glBindAttribLocation(hShader, VATTR_FOGPARAMS, "fogparams");
|
|
|
|
glBindAttribLocation(hShader, VATTR_LIGHTLEVEL, "lightlevel_in"); // Korshun.
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2013-09-03 16:29:39 +00:00
|
|
|
glLinkProgram(hShader);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2013-09-03 16:29:39 +00:00
|
|
|
glGetShaderInfoLog(hVertProg, 10000, NULL, buffer);
|
2013-06-23 07:49:34 +00:00
|
|
|
if (*buffer)
|
|
|
|
{
|
|
|
|
error << "Vertex shader:\n" << buffer << "\n";
|
|
|
|
}
|
2013-09-03 16:29:39 +00:00
|
|
|
glGetShaderInfoLog(hFragProg, 10000, NULL, buffer);
|
2013-06-23 07:49:34 +00:00
|
|
|
if (*buffer)
|
|
|
|
{
|
2013-12-05 14:06:10 +00:00
|
|
|
error << "Fragment shader:\n" << buffer << "\n";
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
|
2013-09-03 16:29:39 +00:00
|
|
|
glGetProgramInfoLog(hShader, 10000, NULL, buffer);
|
2013-06-23 07:49:34 +00:00
|
|
|
if (*buffer)
|
|
|
|
{
|
|
|
|
error << "Linking:\n" << buffer << "\n";
|
|
|
|
}
|
|
|
|
int linked;
|
2013-09-03 16:29:39 +00:00
|
|
|
glGetObjectParameteriv(hShader, GL_LINK_STATUS, &linked);
|
2013-06-23 07:49:34 +00:00
|
|
|
if (linked == 0)
|
|
|
|
{
|
|
|
|
// only print message if there's an error.
|
|
|
|
Printf("Init Shader '%s':\n%s\n", name, error.GetChars());
|
|
|
|
}
|
2013-09-03 16:29:39 +00:00
|
|
|
timer_index = glGetUniformLocation(hShader, "timer");
|
|
|
|
desaturation_index = glGetUniformLocation(hShader, "desaturation_factor");
|
|
|
|
fogenabled_index = glGetUniformLocation(hShader, "fogenabled");
|
|
|
|
texturemode_index = glGetUniformLocation(hShader, "texturemode");
|
|
|
|
camerapos_index = glGetUniformLocation(hShader, "camerapos");
|
|
|
|
lightparms_index = glGetUniformLocation(hShader, "lightparms");
|
|
|
|
colormapstart_index = glGetUniformLocation(hShader, "colormapstart");
|
|
|
|
colormaprange_index = glGetUniformLocation(hShader, "colormaprange");
|
|
|
|
lightrange_index = glGetUniformLocation(hShader, "lightrange");
|
|
|
|
fogcolor_index = glGetUniformLocation(hShader, "fogcolor");
|
|
|
|
lights_index = glGetUniformLocation(hShader, "lights");
|
|
|
|
dlightcolor_index = glGetUniformLocation(hShader, "dlightcolor");
|
|
|
|
|
|
|
|
glowbottomcolor_index = glGetUniformLocation(hShader, "bottomglowcolor");
|
|
|
|
glowtopcolor_index = glGetUniformLocation(hShader, "topglowcolor");
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2013-09-03 16:29:39 +00:00
|
|
|
glUseProgram(hShader);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2013-09-03 16:29:39 +00:00
|
|
|
int texture_index = glGetUniformLocation(hShader, "texture2");
|
|
|
|
if (texture_index > 0) glUniform1i(texture_index, 1);
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2013-09-03 16:29:39 +00:00
|
|
|
glUseProgram(0);
|
2013-06-23 07:49:34 +00:00
|
|
|
return !!linked;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FShader::~FShader()
|
|
|
|
{
|
2013-09-03 16:29:39 +00:00
|
|
|
glDeleteProgram(hShader);
|
|
|
|
glDeleteShader(hVertProg);
|
|
|
|
glDeleteShader(hFragProg);
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
bool FShader::Bind(float Speed)
|
|
|
|
{
|
|
|
|
GLRenderer->mShaderManager->SetActiveShader(this);
|
2013-09-03 16:29:39 +00:00
|
|
|
if (timer_index >=0 && Speed > 0.f) glUniform1f(timer_index, gl_frameMS*Speed/1000.f);
|
2013-06-23 07:49:34 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FShaderContainer::FShaderContainer(const char *ShaderName, const char *ShaderPath)
|
|
|
|
{
|
|
|
|
const char * shaderdefines[] = {
|
|
|
|
"#define NO_GLOW\n#define NO_DESATURATE\n",
|
|
|
|
"#define NO_DESATURATE\n",
|
|
|
|
"#define NO_GLOW\n",
|
|
|
|
"\n",
|
|
|
|
"#define NO_GLOW\n#define NO_DESATURATE\n#define DYNLIGHT\n",
|
|
|
|
"#define NO_DESATURATE\n#define DYNLIGHT\n",
|
|
|
|
"#define NO_GLOW\n#define DYNLIGHT\n",
|
|
|
|
"\n#define DYNLIGHT\n",
|
|
|
|
"#define NO_GLOW\n#define NO_DESATURATE\n#define SOFTLIGHT\n",
|
|
|
|
"#define NO_DESATURATE\n#define SOFTLIGHT\n",
|
|
|
|
"#define NO_GLOW\n#define SOFTLIGHT\n",
|
|
|
|
"\n#define SOFTLIGHT\n",
|
|
|
|
"#define NO_GLOW\n#define NO_DESATURATE\n#define DYNLIGHT\n#define SOFTLIGHT\n",
|
|
|
|
"#define NO_DESATURATE\n#define DYNLIGHT\n#define SOFTLIGHT\n",
|
|
|
|
"#define NO_GLOW\n#define DYNLIGHT\n#define SOFTLIGHT\n",
|
|
|
|
"\n#define DYNLIGHT\n#define SOFTLIGHT\n"
|
|
|
|
};
|
|
|
|
|
|
|
|
const char * shaderdesc[] = {
|
|
|
|
"::default",
|
|
|
|
"::glow",
|
|
|
|
"::desaturate",
|
|
|
|
"::glow+desaturate",
|
|
|
|
"::default+dynlight",
|
|
|
|
"::glow+dynlight",
|
|
|
|
"::desaturate+dynlight",
|
|
|
|
"::glow+desaturate+dynlight",
|
|
|
|
"::softlight",
|
|
|
|
"::glow+softlight",
|
|
|
|
"::desaturate+softlight",
|
|
|
|
"::glow+desaturate+softlight",
|
|
|
|
"::default+dynlight+softlight",
|
|
|
|
"::glow+dynlight+softlight",
|
|
|
|
"::desaturate+dynlight+softlight",
|
|
|
|
"::glow+desaturate+dynlight+softlight",
|
|
|
|
};
|
|
|
|
|
|
|
|
FString name;
|
|
|
|
|
|
|
|
name << ShaderName << "::colormap";
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
shader_cm = new FShader;
|
|
|
|
if (!shader_cm->Load(name, "shaders/glsl/main.vp", "shaders/glsl/main_colormap.fp", ShaderPath, "#define NO_FOG\n#define NO_GLOW\n"))
|
|
|
|
{
|
|
|
|
delete shader_cm;
|
|
|
|
shader_cm = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(CRecoverableError &err)
|
|
|
|
{
|
|
|
|
shader_cm = NULL;
|
|
|
|
I_Error("Unable to load shader %s:\n%s\n", name.GetChars(), err.GetMessage());
|
|
|
|
}
|
|
|
|
|
2013-12-05 14:06:10 +00:00
|
|
|
name << ShaderName << "::foglayer";
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
shader_fl = new FShader;
|
|
|
|
if (!shader_fl->Load(name, "shaders/glsl/main.vp", "shaders/glsl/main_foglayer.fp", ShaderPath, "#define NO_GLOW\n"))
|
|
|
|
{
|
|
|
|
delete shader_fl;
|
|
|
|
shader_fl = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (CRecoverableError &err)
|
|
|
|
{
|
|
|
|
shader_fl = NULL;
|
|
|
|
I_Error("Unable to load shader %s:\n%s\n", name.GetChars(), err.GetMessage());
|
|
|
|
}
|
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
if (gl.shadermodel > 2)
|
|
|
|
{
|
|
|
|
for(int i = 0;i < NUM_SHADERS; i++)
|
|
|
|
{
|
|
|
|
FString name;
|
|
|
|
|
|
|
|
name << ShaderName << shaderdesc[i];
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
FString str;
|
|
|
|
if ((i&4) != 0)
|
|
|
|
{
|
|
|
|
if (gl.maxuniforms < 1024 || gl.shadermodel != 4)
|
|
|
|
{
|
|
|
|
shader[i] = NULL;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// this can't be in the shader code due to ATI strangeness.
|
|
|
|
str = "#version 120\n#extension GL_EXT_gpu_shader4 : enable\n";
|
|
|
|
if (gl.MaxLights() == 128) str += "#define MAXLIGHTS128\n";
|
|
|
|
}
|
|
|
|
if ((i&8) == 0)
|
|
|
|
{
|
|
|
|
if (gl.shadermodel != 4)
|
|
|
|
{
|
|
|
|
shader[i] = NULL;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
str += shaderdefines[i];
|
|
|
|
shader[i] = new FShader;
|
|
|
|
if (!shader[i]->Load(name, "shaders/glsl/main.vp", "shaders/glsl/main.fp", ShaderPath, str.GetChars()))
|
|
|
|
{
|
|
|
|
delete shader[i];
|
|
|
|
shader[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(CRecoverableError &err)
|
|
|
|
{
|
|
|
|
shader[i] = NULL;
|
|
|
|
I_Error("Unable to load shader %s:\n%s\n", name.GetChars(), err.GetMessage());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else memset(shader, 0, sizeof(shader));
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
FShaderContainer::~FShaderContainer()
|
|
|
|
{
|
2013-12-05 14:06:10 +00:00
|
|
|
if (shader_cm != NULL) delete shader_cm;
|
|
|
|
if (shader_fl != NULL) delete shader_fl;
|
|
|
|
for (int i = 0; i < NUM_SHADERS; i++)
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
|
|
|
if (shader[i] != NULL)
|
|
|
|
{
|
|
|
|
delete shader[i];
|
|
|
|
shader[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FShader *FShaderContainer::Bind(int cm, bool glowing, float Speed, bool lights)
|
|
|
|
{
|
|
|
|
FShader *sh=NULL;
|
|
|
|
|
2013-12-05 14:06:10 +00:00
|
|
|
if (cm == CM_FOGLAYER)
|
|
|
|
{
|
|
|
|
if (shader_fl)
|
|
|
|
{
|
|
|
|
shader_fl->Bind(Speed);
|
|
|
|
}
|
|
|
|
return shader_fl;
|
|
|
|
}
|
|
|
|
else if (cm >= CM_FIRSTSPECIALCOLORMAP && cm < CM_MAXCOLORMAP)
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
|
|
|
// these are never used with any kind of lighting or fog
|
|
|
|
sh = shader_cm;
|
|
|
|
// [BB] If there was a problem when loading the shader, sh is NULL here.
|
|
|
|
if( sh )
|
|
|
|
{
|
|
|
|
FSpecialColormap *map = &SpecialColormaps[cm - CM_FIRSTSPECIALCOLORMAP];
|
|
|
|
sh->Bind(Speed);
|
|
|
|
float m[3]= {map->ColorizeEnd[0] - map->ColorizeStart[0],
|
|
|
|
map->ColorizeEnd[1] - map->ColorizeStart[1], map->ColorizeEnd[2] - map->ColorizeStart[2]};
|
|
|
|
|
2013-09-03 16:29:39 +00:00
|
|
|
glUniform3fv(sh->colormapstart_index, 1, map->ColorizeStart);
|
|
|
|
glUniform3fv(sh->colormaprange_index, 1, m);
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bool desat = cm>=CM_DESAT1 && cm<=CM_DESAT31;
|
|
|
|
sh = shader[glowing + 2*desat + 4*lights + (glset.lightmode & 8)];
|
|
|
|
// [BB] If there was a problem when loading the shader, sh is NULL here.
|
|
|
|
if( sh )
|
|
|
|
{
|
|
|
|
sh->Bind(Speed);
|
|
|
|
if (desat)
|
|
|
|
{
|
2013-09-03 16:29:39 +00:00
|
|
|
glUniform1f(sh->desaturation_index, 1.f-float(cm-CM_DESAT0)/(CM_DESAT31-CM_DESAT0));
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sh;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
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[]=
|
|
|
|
{
|
|
|
|
{"fogboundary", "shaders/glsl/main.vp", "shaders/glsl/fogboundary.fp", NULL, "#define NO_GLOW\n"},
|
|
|
|
{"spheremap", "shaders/glsl/main.vp", "shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "#define NO_GLOW\n#define NO_DESATURATE\n#define SPHEREMAP\n#define SPHEREMAP_0\n"}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FShaderManager::FShaderManager()
|
|
|
|
{
|
|
|
|
CompileShaders();
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FShaderManager::~FShaderManager()
|
|
|
|
{
|
|
|
|
Clean();
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void FShaderManager::Recompile()
|
|
|
|
{
|
|
|
|
Clean();
|
|
|
|
CompileShaders();
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void FShaderManager::CompileShaders()
|
|
|
|
{
|
|
|
|
mActiveShader = mEffectShaders[0] = mEffectShaders[1] = NULL;
|
|
|
|
if (gl.shadermodel > 0)
|
|
|
|
{
|
|
|
|
for(int i=0;defaultshaders[i].ShaderName != NULL;i++)
|
|
|
|
{
|
|
|
|
FShaderContainer * shc = new FShaderContainer(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc);
|
|
|
|
mTextureEffects.Push(shc);
|
|
|
|
if (gl.shadermodel <= 2) return; // SM2 will only initialize the default shader
|
|
|
|
}
|
|
|
|
|
|
|
|
for(unsigned i = 0; i < usershaders.Size(); i++)
|
|
|
|
{
|
|
|
|
FString name = ExtractFileBase(usershaders[i]);
|
|
|
|
FName sfn = name;
|
|
|
|
|
|
|
|
if (gl.shadermodel > 2)
|
|
|
|
{
|
|
|
|
FShaderContainer * shc = new FShaderContainer(sfn, usershaders[i]);
|
|
|
|
mTextureEffects.Push(shc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gl.shadermodel > 2)
|
|
|
|
{
|
|
|
|
for(int i=0;i<NUM_EFFECTS;i++)
|
|
|
|
{
|
|
|
|
FShader *eff = new FShader();
|
|
|
|
if (!eff->Load(effectshaders[i].ShaderName, effectshaders[i].vp, effectshaders[i].fp1,
|
|
|
|
effectshaders[i].fp2, effectshaders[i].defines))
|
|
|
|
{
|
|
|
|
delete eff;
|
|
|
|
}
|
|
|
|
else mEffectShaders[i] = eff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void FShaderManager::Clean()
|
|
|
|
{
|
|
|
|
SetActiveShader(NULL);
|
|
|
|
for(unsigned int i=0;i<mTextureEffects.Size();i++)
|
|
|
|
{
|
|
|
|
if (mTextureEffects[i] != NULL) delete mTextureEffects[i];
|
|
|
|
}
|
|
|
|
for(int i=0;i<NUM_EFFECTS;i++)
|
|
|
|
{
|
|
|
|
if (mEffectShaders[i] != NULL) delete mEffectShaders[i];
|
|
|
|
mEffectShaders[i] = NULL;
|
|
|
|
}
|
|
|
|
mTextureEffects.Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
int FShaderManager::Find(const char * shn)
|
|
|
|
{
|
|
|
|
FName sfn = shn;
|
|
|
|
|
|
|
|
for(unsigned int i=0;i<mTextureEffects.Size();i++)
|
|
|
|
{
|
|
|
|
if (mTextureEffects[i]->Name == sfn)
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void FShaderManager::SetActiveShader(FShader *sh)
|
|
|
|
{
|
|
|
|
// shadermodel needs to be tested here because without it UseProgram will be NULL.
|
|
|
|
if (gl.shadermodel > 0 && mActiveShader != sh)
|
|
|
|
{
|
2013-09-03 16:29:39 +00:00
|
|
|
glUseProgram(sh == NULL? 0 : sh->GetHandle());
|
2013-06-23 07:49:34 +00:00
|
|
|
mActiveShader = sh;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FShader *FShaderManager::BindEffect(int effect)
|
|
|
|
{
|
|
|
|
if (effect > 0 && effect <= NUM_EFFECTS && mEffectShaders[effect-1] != NULL)
|
|
|
|
{
|
|
|
|
mEffectShaders[effect-1]->Bind(0);
|
|
|
|
return mEffectShaders[effect-1];
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
Printf("Cannot combine warping with hardware shader on texture '%s'\n", tex->Name);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|