OpenGL shader code rearrangement and shader pre-preprocessor

This commit is contained in:
Hannu Hanhi 2021-05-11 01:13:28 +03:00
parent 8b021ec16b
commit de37df1be0
17 changed files with 980 additions and 633 deletions

View file

@ -508,6 +508,7 @@ if(${SRB2_CONFIG_HWRENDER})
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2load.c
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md3load.c
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_model.c
${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_shaders.c
${CMAKE_CURRENT_SOURCE_DIR}/hardware/u_list.c
)

View file

@ -288,7 +288,8 @@ else
OPTS+=-DHWRENDER
OBJS+=$(OBJDIR)/hw_bsp.o $(OBJDIR)/hw_draw.o $(OBJDIR)/hw_light.o \
$(OBJDIR)/hw_main.o $(OBJDIR)/hw_clip.o $(OBJDIR)/hw_md2.o $(OBJDIR)/hw_cache.o \
$(OBJDIR)/hw_md2load.o $(OBJDIR)/hw_md3load.o $(OBJDIR)/hw_model.o $(OBJDIR)/u_list.o $(OBJDIR)/hw_batching.o
$(OBJDIR)/hw_md2load.o $(OBJDIR)/hw_md3load.o $(OBJDIR)/hw_model.o \
$(OBJDIR)/hw_shaders.o $(OBJDIR)/u_list.o $(OBJDIR)/hw_batching.o
endif
OPTS += -DCOMPVERSION

View file

@ -76,7 +76,7 @@ void HWR_SetCurrentTexture(GLMipmap_t *texture)
// If batching is enabled, this function collects the polygon data and the chosen texture
// for later use in HWR_RenderBatches. Otherwise the rendering backend is used to
// render the polygon immediately.
void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, int shader, boolean horizonSpecial)
void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, int shader_target, boolean horizonSpecial)
{
if (currently_batching)
{
@ -114,7 +114,7 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt
polygonArray[polygonArraySize].numVerts = iNumPts;
polygonArray[polygonArraySize].polyFlags = PolyFlags;
polygonArray[polygonArraySize].texture = current_texture;
polygonArray[polygonArraySize].shader = shader;
polygonArray[polygonArraySize].shader = (shader_target != -1) ? HWR_GetShaderFromTarget(shader_target) : shader_target;
polygonArray[polygonArraySize].horizonSpecial = horizonSpecial;
polygonArraySize++;
@ -123,8 +123,8 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt
}
else
{
if (shader)
HWD.pfnSetShader(shader);
if (shader_target != -1)
HWD.pfnSetShader(HWR_GetShaderFromTarget(shader_target));
HWD.pfnDrawPolygon(pSurf, pOutVerts, iNumPts, PolyFlags);
}
}

View file

@ -133,32 +133,26 @@ typedef struct
} FOutVector;
#ifdef GL_SHADERS
// Predefined shader types
// Shader targets used to render specific types of geometry.
// A shader target is resolved to an actual shader with HWR_GetShaderFromTarget.
// The shader returned may be a base shader or a custom shader.
enum
{
SHADER_DEFAULT = 0,
SHADER_FLOOR,
SHADER_WALL,
SHADER_SPRITE,
SHADER_MODEL, SHADER_MODEL_LIGHTING,
SHADER_MODEL,
SHADER_WATER,
SHADER_FOG,
SHADER_SKY,
NUMBASESHADERS,
NUMSHADERTARGETS,
};
// Maximum amount of shader programs
// Must be higher than NUMBASESHADERS
#define HWR_MAXSHADERS 16
// Shader sources (vertex and fragment)
typedef struct
{
char *vertex;
char *fragment;
} shadersource_t;
// Must be at least NUMSHADERTARGETS*2 to fit base and custom shaders for each shader target.
#define HWR_MAXSHADERS NUMSHADERTARGETS*2
// Custom shader reference table
typedef struct
@ -300,6 +294,14 @@ enum hwdsetspecialstate
typedef enum hwdsetspecialstate hwdspecialstate_t;
enum hwdshaderstage
{
HWD_SHADERSTAGE_VERTEX,
HWD_SHADERSTAGE_FRAGMENT,
};
typedef enum hwdshaderstage hwdshaderstage_t;
// Lactozilla: Shader options
enum hwdshaderoption
{

View file

@ -68,13 +68,13 @@ EXPORT void HWRAPI(DrawScreenFinalTexture) (int width, int height);
#define SCREENVERTS 10
EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]);
EXPORT boolean HWRAPI(CompileShaders) (void);
EXPORT void HWRAPI(CleanShaders) (void);
EXPORT void HWRAPI(SetShader) (int type);
EXPORT boolean HWRAPI(InitShaders) (void);
EXPORT void HWRAPI(LoadShader) (int slot, char *code, hwdshaderstage_t stage);
EXPORT boolean HWRAPI(CompileShader) (int slot);
EXPORT void HWRAPI(SetShader) (int slot);
EXPORT void HWRAPI(UnSetShader) (void);
EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value);
EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boolean isfragment);
// ==========================================================================
// HWR DRIVER OBJECT, FOR CLIENT PROGRAM
@ -120,13 +120,13 @@ struct hwdriver_s
MakeScreenFinalTexture pfnMakeScreenFinalTexture;
DrawScreenFinalTexture pfnDrawScreenFinalTexture;
CompileShaders pfnCompileShaders;
CleanShaders pfnCleanShaders;
InitShaders pfnInitShaders;
LoadShader pfnLoadShader;
CompileShader pfnCompileShader;
SetShader pfnSetShader;
UnSetShader pfnUnSetShader;
SetShaderInfo pfnSetShaderInfo;
LoadCustomShader pfnLoadCustomShader;
};
extern struct hwdriver_s hwdriver;

View file

@ -136,4 +136,18 @@ void HWR_SetPalette(RGBA_t *palette);
extern INT32 patchformat;
extern INT32 textureformat;
// --------
// hw_shaders.c
// --------
boolean HWR_InitShaders(void);
void HWR_CompileShaders(void);
int HWR_GetShaderFromTarget(int shader_target);
void HWR_LoadAllCustomShaders(void);
void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3);
const char *HWR_GetShaderName(INT32 shader);
extern customshaderxlat_t shaderxlat[];
#endif //_HW_GLOB_

View file

@ -167,13 +167,15 @@ precise_t ps_hw_batchdrawtime = 0;
boolean gl_init = false;
boolean gl_maploaded = false;
boolean gl_sessioncommandsadded = false;
boolean gl_shadersavailable = true;
// false if shaders have not been initialized yet, or if shaders are not available
boolean gl_shadersavailable = false;
// ==========================================================================
// Lighting
// ==========================================================================
static boolean HWR_UseShader(void)
// Returns true if shaders can be used.
boolean HWR_UseShader(void)
{
return (cv_glshaders.value && gl_shadersavailable);
}
@ -376,7 +378,7 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool
static FOutVector *planeVerts = NULL;
static UINT16 numAllocedPlaneVerts = 0;
INT32 shader = SHADER_DEFAULT;
INT32 shader = -1;
// no convex poly were generated for this subsector
if (!xsub->planepoly)
@ -798,7 +800,7 @@ static void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, I
//
static void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blendmode, INT32 lightlevel, extracolormap_t *wallcolormap)
{
INT32 shader = SHADER_DEFAULT;
INT32 shader = -1;
HWR_Lighting(pSurf, lightlevel, wallcolormap);
@ -2687,7 +2689,7 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling,
{
FSurfaceInfo Surf;
FOutVector *v3d;
INT32 shader = SHADER_DEFAULT;
INT32 shader = -1;
size_t nrPlaneVerts = polysector->numVertices;
INT32 i;
@ -3598,7 +3600,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
float fscale; float fx; float fy; float offset;
extracolormap_t *colormap = NULL;
FBITFIELD blendmode = PF_Translucent|PF_Modulated;
INT32 shader = SHADER_DEFAULT;
INT32 shader = -1;
UINT8 i;
SINT8 flip = P_MobjFlip(thing);
@ -3745,7 +3747,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
boolean lightset = true;
FBITFIELD blend = 0;
FBITFIELD occlusion;
INT32 shader = SHADER_DEFAULT;
INT32 shader = -1;
boolean use_linkdraw_hack = false;
UINT8 alpha;
@ -4259,7 +4261,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
}
{
INT32 shader = SHADER_DEFAULT;
INT32 shader = -1;
FBITFIELD blend = 0;
FBITFIELD occlusion;
boolean use_linkdraw_hack = false;
@ -4327,7 +4329,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
// Sprite drawer for precipitation
static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr)
{
INT32 shader = SHADER_DEFAULT;
INT32 shader = -1;
FBITFIELD blend = 0;
FOutVector wallVerts[4];
patch_t *gpatch;
@ -4765,7 +4767,6 @@ static void HWR_CreateDrawNodes(void)
// Okay! Let's draw it all! Woo!
HWD.pfnSetTransform(&atransform);
HWD.pfnSetShader(SHADER_DEFAULT);
for (i = 0; i < p; i++)
{
@ -5674,7 +5675,8 @@ static void HWR_DrawSkyBackground(player_t *player)
HWR_BuildSkyDome();
}
HWD.pfnSetShader(SHADER_SKY); // sky shader
if (HWR_UseShader())
HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_SKY));
HWD.pfnSetTransform(&dometransform);
HWD.pfnRenderSkyDome(&gl_sky);
}
@ -5760,8 +5762,6 @@ static void HWR_DrawSkyBackground(player_t *player)
HWD.pfnUnSetShader();
HWD.pfnDrawPolygon(NULL, v, 4, 0);
}
HWD.pfnSetShader(SHADER_DEFAULT);
}
@ -5851,13 +5851,7 @@ static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean
//
static void HWR_SetShaderState(void)
{
hwdshaderoption_t state = cv_glshaders.value;
if (!cv_glallowshaders.value)
state = (cv_glshaders.value == HWD_SHADEROPTION_ON ? HWD_SHADEROPTION_NOCUSTOM : cv_glshaders.value);
HWD.pfnSetSpecialState(HWD_SET_SHADERS, (INT32)state);
HWD.pfnSetShader(SHADER_DEFAULT);
HWD.pfnSetSpecialState(HWD_SET_SHADERS, (INT32)HWR_UseShader());
}
// ==========================================================================
@ -6303,13 +6297,14 @@ void HWR_LoadLevel(void)
// 3D ENGINE COMMANDS
// ==========================================================================
static CV_PossibleValue_t glshaders_cons_t[] = {{HWD_SHADEROPTION_OFF, "Off"}, {HWD_SHADEROPTION_ON, "On"}, {HWD_SHADEROPTION_NOCUSTOM, "Ignore custom shaders"}, {0, NULL}};
static CV_PossibleValue_t glshaders_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Ignore custom shaders"}, {0, NULL}};
static CV_PossibleValue_t glmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}};
static CV_PossibleValue_t glfakecontrast_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Smooth"}, {0, NULL}};
static CV_PossibleValue_t glshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Third-person"}, {0, NULL}};
static void CV_glfiltermode_OnChange(void);
static void CV_glanisotropic_OnChange(void);
static void CV_glmodellighting_OnChange(void);
static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"},
{HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"},
@ -6332,7 +6327,7 @@ consvar_t cv_glcoronasize = CVAR_INIT ("gr_coronasize", "1", CV_SAVE|CV_FLOAT, 0
consvar_t cv_glmodels = CVAR_INIT ("gr_models", "Off", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_glmodelinterpolation = CVAR_INIT ("gr_modelinterpolation", "Sometimes", CV_SAVE, glmodelinterpolation_cons_t, NULL);
consvar_t cv_glmodellighting = CVAR_INIT ("gr_modellighting", "Off", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_glmodellighting = CVAR_INIT ("gr_modellighting", "Off", CV_SAVE|CV_CALL, CV_OnOff, CV_glmodellighting_OnChange);
consvar_t cv_glshearing = CVAR_INIT ("gr_shearing", "Off", CV_SAVE, glshearing_cons_t, NULL);
consvar_t cv_glspritebillboarding = CVAR_INIT ("gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL);
@ -6359,6 +6354,13 @@ static void CV_glanisotropic_OnChange(void)
HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_glanisotropicmode.value);
}
static void CV_glmodellighting_OnChange(void)
{
// if shaders have been compiled, then they now need to be recompiled.
if (gl_shadersavailable)
HWR_CompileShaders();
}
//added by Hurdler: console varibale that are saved
void HWR_AddCommands(void)
{
@ -6417,9 +6419,8 @@ void HWR_Startup(void)
HWR_InitLight();
#endif
gl_shadersavailable = HWR_InitShaders();
HWR_LoadAllCustomShaders();
if (!HWR_CompileShaders())
gl_shadersavailable = false;
}
if (rendermode == render_opengl)
@ -6518,7 +6519,7 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend,
FBITFIELD blendmode = blend;
UINT8 alpha = pSurf->PolyColor.s.alpha; // retain the alpha
INT32 shader = SHADER_DEFAULT;
INT32 shader = -1;
// Lighting is done here instead so that fog isn't drawn incorrectly on transparent walls after sorting
HWR_Lighting(pSurf, lightlevel, wallcolormap);
@ -6716,182 +6717,4 @@ void HWR_DrawScreenFinalTexture(int width, int height)
HWD.pfnDrawScreenFinalTexture(width, height);
}
static inline UINT16 HWR_FindShaderDefs(UINT16 wadnum)
{
UINT16 i;
lumpinfo_t *lump_p;
lump_p = wadfiles[wadnum]->lumpinfo;
for (i = 0; i < wadfiles[wadnum]->numlumps; i++, lump_p++)
if (memcmp(lump_p->name, "SHADERS", 7) == 0)
return i;
return INT16_MAX;
}
boolean HWR_CompileShaders(void)
{
return HWD.pfnCompileShaders();
}
customshaderxlat_t shaderxlat[] =
{
{"Flat", SHADER_FLOOR},
{"WallTexture", SHADER_WALL},
{"Sprite", SHADER_SPRITE},
{"Model", SHADER_MODEL},
{"ModelLighting", SHADER_MODEL_LIGHTING},
{"WaterRipple", SHADER_WATER},
{"Fog", SHADER_FOG},
{"Sky", SHADER_SKY},
{NULL, 0},
};
void HWR_LoadAllCustomShaders(void)
{
INT32 i;
// read every custom shader
for (i = 0; i < numwadfiles; i++)
HWR_LoadCustomShadersFromFile(i, (wadfiles[i]->type == RET_PK3));
}
void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3)
{
UINT16 lump;
char *shaderdef, *line;
char *stoken;
char *value;
size_t size;
int linenum = 1;
int shadertype = 0;
int i;
lump = HWR_FindShaderDefs(wadnum);
if (lump == INT16_MAX)
return;
shaderdef = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE);
size = W_LumpLengthPwad(wadnum, lump);
line = Z_Malloc(size+1, PU_STATIC, NULL);
M_Memcpy(line, shaderdef, size);
line[size] = '\0';
stoken = strtok(line, "\r\n ");
while (stoken)
{
if ((stoken[0] == '/' && stoken[1] == '/')
|| (stoken[0] == '#'))// skip comments
{
stoken = strtok(NULL, "\r\n");
goto skip_field;
}
if (!stricmp(stoken, "GLSL"))
{
value = strtok(NULL, "\r\n ");
if (!value)
{
CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
stoken = strtok(NULL, "\r\n"); // skip end of line
goto skip_lump;
}
if (!stricmp(value, "VERTEX"))
shadertype = 1;
else if (!stricmp(value, "FRAGMENT"))
shadertype = 2;
skip_lump:
stoken = strtok(NULL, "\r\n ");
linenum++;
}
else
{
value = strtok(NULL, "\r\n= ");
if (!value)
{
CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader target (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
stoken = strtok(NULL, "\r\n"); // skip end of line
goto skip_field;
}
if (!shadertype)
{
CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
Z_Free(line);
return;
}
for (i = 0; shaderxlat[i].type; i++)
{
if (!stricmp(shaderxlat[i].type, stoken))
{
size_t shader_size;
char *shader_source;
char *shader_lumpname;
UINT16 shader_lumpnum;
if (PK3)
{
shader_lumpname = Z_Malloc(strlen(value) + 12, PU_STATIC, NULL);
strcpy(shader_lumpname, "Shaders/sh_");
strcat(shader_lumpname, value);
shader_lumpnum = W_CheckNumForFullNamePK3(shader_lumpname, wadnum, 0);
}
else
{
shader_lumpname = Z_Malloc(strlen(value) + 4, PU_STATIC, NULL);
strcpy(shader_lumpname, "SH_");
strcat(shader_lumpname, value);
shader_lumpnum = W_CheckNumForNamePwad(shader_lumpname, wadnum, 0);
}
if (shader_lumpnum == INT16_MAX)
{
CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader source %s (file %s, line %d)\n", shader_lumpname, wadfiles[wadnum]->filename, linenum);
Z_Free(shader_lumpname);
continue;
}
shader_size = W_LumpLengthPwad(wadnum, shader_lumpnum);
shader_source = Z_Malloc(shader_size, PU_STATIC, NULL);
W_ReadLumpPwad(wadnum, shader_lumpnum, shader_source);
HWD.pfnLoadCustomShader(shaderxlat[i].id, shader_source, shader_size, (shadertype == 2));
Z_Free(shader_source);
Z_Free(shader_lumpname);
}
}
skip_field:
stoken = strtok(NULL, "\r\n= ");
linenum++;
}
}
Z_Free(line);
return;
}
const char *HWR_GetShaderName(INT32 shader)
{
INT32 i;
if (shader)
{
for (i = 0; shaderxlat[i].type; i++)
{
if (shaderxlat[i].id == shader)
return shaderxlat[i].type;
}
return "Unknown";
}
return "Default";
}
#endif // HWRENDER

View file

@ -65,6 +65,7 @@ void HWR_MakeScreenFinalTexture(void);
void HWR_DrawScreenFinalTexture(int width, int height);
// This stuff is put here so models can use them
boolean HWR_UseShader(void);
void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *colormap);
UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap); // Let's see if this can work
@ -73,14 +74,6 @@ FBITFIELD HWR_GetBlendModeFlag(INT32 ast);
FBITFIELD HWR_SurfaceBlend(INT32 style, INT32 transtablenum, FSurfaceInfo *pSurf);
FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf);
boolean HWR_CompileShaders(void);
void HWR_LoadAllCustomShaders(void);
void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3);
const char *HWR_GetShaderName(INT32 shader);
extern customshaderxlat_t shaderxlat[];
extern CV_PossibleValue_t glanisotropicmode_cons_t[];
#ifdef ALAM_LIGHTING

View file

@ -1644,7 +1644,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
p.mirror = atransform.mirror; // from Kart
#endif
HWD.pfnSetShader(SHADER_MODEL); // model shader
if (HWR_UseShader())
HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_MODEL));
HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, finalscale, flip, hflip, &Surf);
}

756
src/hardware/hw_shaders.c Normal file
View file

@ -0,0 +1,756 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2021 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file hw_shaders.h
/// \brief Handles the shaders used by the game.
#ifdef HWRENDER
#include "hw_glob.h"
#include "hw_drv.h"
#include "../z_zone.h"
// ================
// Vertex shaders
// ================
//
// Generic vertex shader
//
#define GLSL_DEFAULT_VERTEX_SHADER \
"void main()\n" \
"{\n" \
"gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \
"gl_FrontColor = gl_Color;\n" \
"gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \
"gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \
"}\0"
// replicates the way fixed function lighting is used by the model lighting option,
// stores the lighting result to gl_Color
// (ambient lighting of 0.75 and diffuse lighting from above)
#define GLSL_MODEL_VERTEX_SHADER \
"void main()\n" \
"{\n" \
"#ifdef MODEL_LIGHTING\n" \
"float nDotVP = dot(gl_Normal, vec3(0, 1, 0));\n" \
"float light = 0.75 + max(nDotVP, 0.0);\n" \
"gl_FrontColor = vec4(light, light, light, 1.0);\n" \
"#else\n" \
"gl_FrontColor = gl_Color;\n" \
"#endif\n" \
"gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \
"gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \
"gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \
"}\0"
// ==================
// Fragment shaders
// ==================
//
// Generic fragment shader
//
#define GLSL_DEFAULT_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"void main(void) {\n" \
"gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \
"}\0"
//
// Software fragment shader
//
#define GLSL_DOOM_COLORMAP \
"float R_DoomColormap(float light, float z)\n" \
"{\n" \
"float lightnum = clamp(light / 17.0, 0.0, 15.0);\n" \
"float lightz = clamp(z / 16.0, 0.0, 127.0);\n" \
"float startmap = (15.0 - lightnum) * 4.0;\n" \
"float scale = 160.0 / (lightz + 1.0);\n" \
"return startmap - scale * 0.5;\n" \
"}\n"
#define GLSL_DOOM_LIGHT_EQUATION \
"float R_DoomLightingEquation(float light)\n" \
"{\n" \
"float z = gl_FragCoord.z / gl_FragCoord.w;\n" \
"float colormap = floor(R_DoomColormap(light, z)) + 0.5;\n" \
"return clamp(colormap, 0.0, 31.0) / 32.0;\n" \
"}\n"
#define GLSL_SOFTWARE_TINT_EQUATION \
"if (tint_color.a > 0.0) {\n" \
"float color_bright = sqrt((base_color.r * base_color.r) + (base_color.g * base_color.g) + (base_color.b * base_color.b));\n" \
"float strength = sqrt(9.0 * tint_color.a);\n" \
"final_color.r = clamp((color_bright * (tint_color.r * strength)) + (base_color.r * (1.0 - strength)), 0.0, 1.0);\n" \
"final_color.g = clamp((color_bright * (tint_color.g * strength)) + (base_color.g * (1.0 - strength)), 0.0, 1.0);\n" \
"final_color.b = clamp((color_bright * (tint_color.b * strength)) + (base_color.b * (1.0 - strength)), 0.0, 1.0);\n" \
"}\n"
#define GLSL_SOFTWARE_FADE_EQUATION \
"float darkness = R_DoomLightingEquation(lighting);\n" \
"if (fade_start != 0.0 || fade_end != 31.0) {\n" \
"float fs = fade_start / 31.0;\n" \
"float fe = fade_end / 31.0;\n" \
"float fd = fe - fs;\n" \
"darkness = clamp((darkness - fs) * (1.0 / fd), 0.0, 1.0);\n" \
"}\n" \
"final_color = mix(final_color, fade_color, darkness);\n"
#define GLSL_SOFTWARE_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \
"uniform float fade_start;\n" \
"uniform float fade_end;\n" \
GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \
"vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
"vec4 base_color = texel * poly_color;\n" \
"vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \
"final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \
"}\0"
// same as above but multiplies results with the lighting value from the
// accompanying vertex shader (stored in gl_Color)
#define GLSL_SOFTWARE_MODEL_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \
"uniform float fade_start;\n" \
"uniform float fade_end;\n" \
GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \
"vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
"vec4 base_color = texel * poly_color;\n" \
"vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \
"#ifdef MODEL_LIGHTING\n" \
"final_color *= gl_Color;\n" \
"#endif\n" \
"final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \
"}\0"
//
// Water surface shader
//
// Mostly guesstimated, rather than the rest being built off Software science.
// Still needs to distort things underneath/around the water...
//
#define GLSL_WATER_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \
"uniform float fade_start;\n" \
"uniform float fade_end;\n" \
"uniform float leveltime;\n" \
"const float freq = 0.025;\n" \
"const float amp = 0.025;\n" \
"const float speed = 2.0;\n" \
"const float pi = 3.14159;\n" \
GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \
"float z = (gl_FragCoord.z / gl_FragCoord.w) / 2.0;\n" \
"float a = -pi * (z * freq) + (leveltime * speed);\n" \
"float sdistort = sin(a) * amp;\n" \
"float cdistort = cos(a) * amp;\n" \
"vec4 texel = texture2D(tex, vec2(gl_TexCoord[0].s - sdistort, gl_TexCoord[0].t - cdistort));\n" \
"vec4 base_color = texel * poly_color;\n" \
"vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \
"final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \
"}\0"
//
// Fog block shader
//
// Alpha of the planes themselves are still slightly off -- see HWR_FogBlockAlpha
//
#define GLSL_FOG_FRAGMENT_SHADER \
"uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \
"uniform float fade_start;\n" \
"uniform float fade_end;\n" \
GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \
"vec4 base_color = gl_Color;\n" \
"vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \
"gl_FragColor = final_color;\n" \
"}\0"
//
// Sky fragment shader
// Modulates poly_color with gl_Color
//
#define GLSL_SKY_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"void main(void) {\n" \
"gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \
"}\0"
// ================
// Shader sources
// ================
static struct {
const char *vertex;
const char *fragment;
} const gl_shadersources[] = {
// Floor shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER},
// Wall shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER},
// Sprite shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER},
// Model shader
{GLSL_MODEL_VERTEX_SHADER, GLSL_SOFTWARE_MODEL_FRAGMENT_SHADER},
// Water shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_WATER_FRAGMENT_SHADER},
// Fog shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_FOG_FRAGMENT_SHADER},
// Sky shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SKY_FRAGMENT_SHADER},
{NULL, NULL},
};
typedef struct
{
int base_shader; // index of base shader_t
int custom_shader; // index of custom shader_t
} shadertarget_t;
typedef struct
{
char *vertex;
char *fragment;
boolean compiled;
} shader_t; // these are in an array and accessed by indices
// the array has NUMSHADERTARGETS entries for base shaders and for custom shaders
// the array could be expanded in the future to fit "dynamic" custom shaders that
// aren't fixed to shader targets
static shader_t gl_shaders[NUMSHADERTARGETS*2];
static shadertarget_t gl_shadertargets[NUMSHADERTARGETS];
#define MODEL_LIGHTING_DEFINE "#define MODEL_LIGHTING"
// Initialize shader variables and the backend's shader system. Load the base shaders.
// Returns false if shaders cannot be used.
boolean HWR_InitShaders(void)
{
int i;
if (!HWD.pfnInitShaders())
return false;
for (i = 0; i < NUMSHADERTARGETS; i++)
{
// set up string pointers for base shaders
gl_shaders[i].vertex = Z_StrDup(gl_shadersources[i].vertex);
gl_shaders[i].fragment = Z_StrDup(gl_shadersources[i].fragment);
// set shader target indices to correct values
gl_shadertargets[i].base_shader = i;
gl_shadertargets[i].custom_shader = -1;
}
HWR_CompileShaders();
return true;
}
// helper function: strstr but returns an int with the substring position
// returns INT32_MAX if not found
static INT32 strstr_int(const char *str1, const char *str2)
{
char *location = strstr(str1, str2);
if (location)
return location - str1;
else
return INT32_MAX;
}
// Creates a preprocessed copy of the shader according to the current graphics settings
// Returns a pointer to the results on success and NULL on failure.
// Remember memory management of the returned string.
static char *HWR_PreprocessShader(char *original)
{
const char *line_ending = "\n";
int line_ending_len;
char *read_pos = original;
int insertion_pos = 0;
int original_len = strlen(original);
int distance_to_end = original_len;
int new_len;
char *new_shader;
char *write_pos;
if (strstr(original, "\r\n"))
{
line_ending = "\r\n";
// check that all line endings are same,
// otherwise the parsing code won't function correctly
while ((read_pos = strchr(read_pos, '\n')))
{
read_pos--;
if (*read_pos != '\r')
{
CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Shader contains mixed line ending types. Please use either only LF (Unix) or only CRLF (Windows) line endings.\n");
return NULL;
}
read_pos += 2;
}
read_pos = original;
}
line_ending_len = strlen(line_ending);
// We need to find a place to put the #define commands.
// To stay within GLSL specs, they must be *after* the #version define,
// if there is any. So we need to look for that. And also let's not
// get fooled if there is a #version inside a comment!
// Time for some string parsing :D
#define STARTSWITH(str, with_what) !strncmp(str, with_what, sizeof(with_what)-1)
#define ADVANCE(amount) read_pos += amount; distance_to_end -= amount;
while (true)
{
// we're at the start of a line or at the end of a block comment.
// first get any possible whitespace out of the way
int whitespace_len = strspn(read_pos, " \t");
if (whitespace_len == distance_to_end)
break; // we got to the end
ADVANCE(whitespace_len)
if (STARTSWITH(read_pos, "#version"))
{
// getting closer
INT32 newline_pos = strstr_int(read_pos, line_ending);
INT32 line_comment_pos = strstr_int(read_pos, "//");
INT32 block_comment_pos = strstr_int(read_pos, "/*");
if (newline_pos == INT32_MAX && line_comment_pos == INT32_MAX &&
block_comment_pos == INT32_MAX)
{
// #version is at the end of the file. Probably not a valid shader.
CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Shader unexpectedly ends after #version.\n");
return NULL;
}
else
{
// insert at the earliest occurence of newline or comment after #version
insertion_pos = min(line_comment_pos, block_comment_pos);
insertion_pos = min(newline_pos, insertion_pos);
insertion_pos += read_pos - original;
break;
}
}
else
{
// go to next newline or end of next block comment if it starts before the newline
// and is not inside a line comment
INT32 newline_pos = strstr_int(read_pos, line_ending);
INT32 line_comment_pos;
INT32 block_comment_pos;
// optimization: temporarily put a null at the line ending, so strstr does not needlessly
// look past it since we're only interested in the current line
if (newline_pos != INT32_MAX)
read_pos[newline_pos] = '\0';
line_comment_pos = strstr_int(read_pos, "//");
block_comment_pos = strstr_int(read_pos, "/*");
// restore the line ending, remove the null we just put there
if (newline_pos != INT32_MAX)
read_pos[newline_pos] = line_ending[0];
if (line_comment_pos < block_comment_pos)
{
// line comment found, skip rest of the line
if (newline_pos != INT32_MAX)
{
ADVANCE(newline_pos + line_ending_len)
}
else
{
// we got to the end
break;
}
}
else if (block_comment_pos < line_comment_pos)
{
// block comment found, skip past it
INT32 block_comment_end;
ADVANCE(block_comment_pos + 2)
block_comment_end = strstr_int(read_pos, "*/");
if (block_comment_end == INT32_MAX)
{
// could also leave insertion_pos at 0 and let the GLSL compiler
// output an error message for this broken comment
CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Encountered unclosed block comment in shader.\n");
return NULL;
}
ADVANCE(block_comment_end + 2)
}
else if (newline_pos == INT32_MAX)
{
// we got to the end
break;
}
else
{
// nothing special on this line, move to the next one
ADVANCE(newline_pos + line_ending_len)
}
}
}
#undef STARTSWITH
#undef ADVANCE
// Calculate length of modified shader.
new_len = original_len;
if (cv_glmodellighting.value)
new_len += sizeof(MODEL_LIGHTING_DEFINE) - 1 + 2 * line_ending_len;
// Allocate memory for modified shader.
new_shader = Z_Malloc(new_len + 1, PU_STATIC, NULL);
read_pos = original;
write_pos = new_shader;
// Copy the part before our additions.
M_Memcpy(write_pos, original, insertion_pos);
read_pos += insertion_pos;
write_pos += insertion_pos;
// Write the additions.
if (cv_glmodellighting.value)
{
strcpy(write_pos, line_ending);
write_pos += line_ending_len;
strcpy(write_pos, MODEL_LIGHTING_DEFINE);
write_pos += sizeof(MODEL_LIGHTING_DEFINE) - 1;
strcpy(write_pos, line_ending);
write_pos += line_ending_len;
}
// Copy the part after our additions.
M_Memcpy(write_pos, read_pos, original_len - insertion_pos);
// Terminate the new string.
new_shader[new_len] = '\0';
return new_shader;
}
// preprocess and compile shader at gl_shaders[index]
static void HWR_CompileShader(int index)
{
char *vertex_source = gl_shaders[index].vertex;
char *fragment_source = gl_shaders[index].fragment;
if (vertex_source)
{
char *preprocessed = HWR_PreprocessShader(vertex_source);
if (!preprocessed) return;
HWD.pfnLoadShader(index, preprocessed, HWD_SHADERSTAGE_VERTEX);
}
if (fragment_source)
{
char *preprocessed = HWR_PreprocessShader(fragment_source);
if (!preprocessed) return;
HWD.pfnLoadShader(index, preprocessed, HWD_SHADERSTAGE_FRAGMENT);
}
gl_shaders[index].compiled = HWD.pfnCompileShader(index);
}
// compile or recompile shaders
void HWR_CompileShaders(void)
{
int i;
for (i = 0; i < NUMSHADERTARGETS; i++)
{
int custom_index = gl_shadertargets[i].custom_shader;
HWR_CompileShader(i);
if (!gl_shaders[i].compiled)
CONS_Alert(CONS_ERROR, "HWR_CompileShaders: Compilation failed for base %s shader!\n", shaderxlat[i].type);
if (custom_index != -1)
{
HWR_CompileShader(custom_index);
if (!gl_shaders[custom_index].compiled)
CONS_Alert(CONS_ERROR, "HWR_CompileShaders: Recompilation failed for the custom %s shader! See the console messages above for more information.\n", shaderxlat[i].type);
}
}
}
int HWR_GetShaderFromTarget(int shader_target)
{
int custom_shader = gl_shadertargets[shader_target].custom_shader;
// use custom shader if following are true
// - custom shader exists
// - custom shader has been compiled successfully
// - custom shaders are enabled
// - custom shaders are allowed by the server
if (custom_shader != -1 && gl_shaders[custom_shader].compiled &&
cv_glshaders.value == 1 && cv_glallowshaders.value)
return custom_shader;
else
return gl_shadertargets[shader_target].base_shader;
}
static inline UINT16 HWR_FindShaderDefs(UINT16 wadnum)
{
UINT16 i;
lumpinfo_t *lump_p;
lump_p = wadfiles[wadnum]->lumpinfo;
for (i = 0; i < wadfiles[wadnum]->numlumps; i++, lump_p++)
if (memcmp(lump_p->name, "SHADERS", 7) == 0)
return i;
return INT16_MAX;
}
customshaderxlat_t shaderxlat[] =
{
{"Flat", SHADER_FLOOR},
{"WallTexture", SHADER_WALL},
{"Sprite", SHADER_SPRITE},
{"Model", SHADER_MODEL},
{"WaterRipple", SHADER_WATER},
{"Fog", SHADER_FOG},
{"Sky", SHADER_SKY},
{NULL, 0},
};
void HWR_LoadAllCustomShaders(void)
{
INT32 i;
// read every custom shader
for (i = 0; i < numwadfiles; i++)
HWR_LoadCustomShadersFromFile(i, (wadfiles[i]->type == RET_PK3));
}
void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3)
{
UINT16 lump;
char *shaderdef, *line;
char *stoken;
char *value;
size_t size;
int linenum = 1;
int shadertype = 0;
int i;
boolean modified_shaders[NUMSHADERTARGETS] = {0};
if (!gl_shadersavailable)
return;
lump = HWR_FindShaderDefs(wadnum);
if (lump == INT16_MAX)
return;
shaderdef = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE);
size = W_LumpLengthPwad(wadnum, lump);
line = Z_Malloc(size+1, PU_STATIC, NULL);
M_Memcpy(line, shaderdef, size);
line[size] = '\0';
stoken = strtok(line, "\r\n ");
while (stoken)
{
if ((stoken[0] == '/' && stoken[1] == '/')
|| (stoken[0] == '#'))// skip comments
{
stoken = strtok(NULL, "\r\n");
goto skip_field;
}
if (!stricmp(stoken, "GLSL"))
{
value = strtok(NULL, "\r\n ");
if (!value)
{
CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
stoken = strtok(NULL, "\r\n"); // skip end of line
goto skip_lump;
}
if (!stricmp(value, "VERTEX"))
shadertype = 1;
else if (!stricmp(value, "FRAGMENT"))
shadertype = 2;
skip_lump:
stoken = strtok(NULL, "\r\n ");
linenum++;
}
else
{
value = strtok(NULL, "\r\n= ");
if (!value)
{
CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader target (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
stoken = strtok(NULL, "\r\n"); // skip end of line
goto skip_field;
}
if (!shadertype)
{
CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
Z_Free(line);
return;
}
for (i = 0; shaderxlat[i].type; i++)
{
if (!stricmp(shaderxlat[i].type, stoken))
{
size_t shader_string_length;
char *shader_source;
char *shader_lumpname;
UINT16 shader_lumpnum;
int shader_index; // index in gl_shaders
if (PK3)
{
shader_lumpname = Z_Malloc(strlen(value) + 12, PU_STATIC, NULL);
strcpy(shader_lumpname, "Shaders/sh_");
strcat(shader_lumpname, value);
shader_lumpnum = W_CheckNumForFullNamePK3(shader_lumpname, wadnum, 0);
}
else
{
shader_lumpname = Z_Malloc(strlen(value) + 4, PU_STATIC, NULL);
strcpy(shader_lumpname, "SH_");
strcat(shader_lumpname, value);
shader_lumpnum = W_CheckNumForNamePwad(shader_lumpname, wadnum, 0);
}
if (shader_lumpnum == INT16_MAX)
{
CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader source %s (file %s, line %d)\n", shader_lumpname, wadfiles[wadnum]->filename, linenum);
Z_Free(shader_lumpname);
continue;
}
shader_string_length = W_LumpLengthPwad(wadnum, shader_lumpnum) + 1;
shader_source = Z_Malloc(shader_string_length, PU_STATIC, NULL);
W_ReadLumpPwad(wadnum, shader_lumpnum, shader_source);
shader_source[shader_string_length-1] = '\0';
shader_index = shaderxlat[i].id + NUMSHADERTARGETS;
if (!modified_shaders[shaderxlat[i].id])
{
// this will clear any old custom shaders from previously loaded files
// Z_Free checks if the pointer is NULL!
Z_Free(gl_shaders[shader_index].vertex);
gl_shaders[shader_index].vertex = NULL;
Z_Free(gl_shaders[shader_index].fragment);
gl_shaders[shader_index].fragment = NULL;
}
modified_shaders[shaderxlat[i].id] = true;
if (shadertype == 1)
{
if (gl_shaders[shader_index].vertex)
{
CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: %s is overwriting another %s vertex shader from the same addon! (file %s, line %d)\n", shader_lumpname, shaderxlat[i].type, wadfiles[wadnum]->filename, linenum);
Z_Free(gl_shaders[shader_index].vertex);
}
gl_shaders[shader_index].vertex = shader_source;
}
else
{
if (gl_shaders[shader_index].fragment)
{
CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: %s is overwriting another %s fragment shader from the same addon! (file %s, line %d)\n", shader_lumpname, shaderxlat[i].type, wadfiles[wadnum]->filename, linenum);
Z_Free(gl_shaders[shader_index].fragment);
}
gl_shaders[shader_index].fragment = shader_source;
}
Z_Free(shader_lumpname);
}
}
skip_field:
stoken = strtok(NULL, "\r\n= ");
linenum++;
}
}
for (i = 0; i < NUMSHADERTARGETS; i++)
{
if (modified_shaders[i])
{
int shader_index = i + NUMSHADERTARGETS; // index to gl_shaders
gl_shadertargets[i].custom_shader = shader_index;
HWR_CompileShader(shader_index);
if (!gl_shaders[shader_index].compiled)
CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: A compilation error occured for the %s shader in file %s. See the console messages above for more information.\n", shaderxlat[i].type, wadfiles[wadnum]->filename);
}
}
Z_Free(line);
return;
}
const char *HWR_GetShaderName(INT32 shader)
{
INT32 i;
if (shader)
{
for (i = 0; shaderxlat[i].type; i++)
{
if (shaderxlat[i].id == shader)
return shaderxlat[i].type;
}
return "Unknown";
}
return "Default";
}
#endif // HWRENDER

View file

@ -598,14 +598,15 @@ typedef enum
typedef struct gl_shader_s
{
char *vertex_shader;
char *fragment_shader;
GLuint program;
GLint uniforms[gluniform_max+1];
boolean custom;
} gl_shader_t;
static gl_shader_t gl_shaders[HWR_MAXSHADERS];
static gl_shader_t gl_usershaders[HWR_MAXSHADERS];
static shadersource_t gl_customshaders[HWR_MAXSHADERS];
static gl_shader_t gl_fallback_shader;
// 09102020
typedef struct gl_shaderstate_s
@ -621,21 +622,17 @@ static gl_shaderstate_t gl_shaderstate;
static INT32 shader_leveltime = 0;
// Lactozilla: Shader functions
static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader);
static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i);
static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum);
static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade);
static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f};
// ================
// Vertex shaders
// ================
//
// Generic vertex shader
//
#define GLSL_DEFAULT_VERTEX_SHADER \
#define GLSL_FALLBACK_VERTEX_SHADER \
"void main()\n" \
"{\n" \
"gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \
@ -644,226 +641,17 @@ static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f};
"gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \
"}\0"
// replicates the way fixed function lighting is used by the model lighting option,
// stores the lighting result to gl_Color
// (ambient lighting of 0.75 and diffuse lighting from above)
#define GLSL_MODEL_LIGHTING_VERTEX_SHADER \
"void main()\n" \
"{\n" \
"float nDotVP = dot(gl_Normal, vec3(0, 1, 0));\n" \
"float light = 0.75 + max(nDotVP, 0.0);\n" \
"gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \
"gl_FrontColor = vec4(light, light, light, 1.0);\n" \
"gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \
"gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \
"}\0"
// ==================
// Fragment shaders
// ==================
//
// Generic fragment shader
//
#define GLSL_DEFAULT_FRAGMENT_SHADER \
#define GLSL_FALLBACK_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"void main(void) {\n" \
"gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \
"}\0"
//
// Software fragment shader
//
#define GLSL_DOOM_COLORMAP \
"float R_DoomColormap(float light, float z)\n" \
"{\n" \
"float lightnum = clamp(light / 17.0, 0.0, 15.0);\n" \
"float lightz = clamp(z / 16.0, 0.0, 127.0);\n" \
"float startmap = (15.0 - lightnum) * 4.0;\n" \
"float scale = 160.0 / (lightz + 1.0);\n" \
"return startmap - scale * 0.5;\n" \
"}\n"
#define GLSL_DOOM_LIGHT_EQUATION \
"float R_DoomLightingEquation(float light)\n" \
"{\n" \
"float z = gl_FragCoord.z / gl_FragCoord.w;\n" \
"float colormap = floor(R_DoomColormap(light, z)) + 0.5;\n" \
"return clamp(colormap, 0.0, 31.0) / 32.0;\n" \
"}\n"
#define GLSL_SOFTWARE_TINT_EQUATION \
"if (tint_color.a > 0.0) {\n" \
"float color_bright = sqrt((base_color.r * base_color.r) + (base_color.g * base_color.g) + (base_color.b * base_color.b));\n" \
"float strength = sqrt(9.0 * tint_color.a);\n" \
"final_color.r = clamp((color_bright * (tint_color.r * strength)) + (base_color.r * (1.0 - strength)), 0.0, 1.0);\n" \
"final_color.g = clamp((color_bright * (tint_color.g * strength)) + (base_color.g * (1.0 - strength)), 0.0, 1.0);\n" \
"final_color.b = clamp((color_bright * (tint_color.b * strength)) + (base_color.b * (1.0 - strength)), 0.0, 1.0);\n" \
"}\n"
#define GLSL_SOFTWARE_FADE_EQUATION \
"float darkness = R_DoomLightingEquation(lighting);\n" \
"if (fade_start != 0.0 || fade_end != 31.0) {\n" \
"float fs = fade_start / 31.0;\n" \
"float fe = fade_end / 31.0;\n" \
"float fd = fe - fs;\n" \
"darkness = clamp((darkness - fs) * (1.0 / fd), 0.0, 1.0);\n" \
"}\n" \
"final_color = mix(final_color, fade_color, darkness);\n"
#define GLSL_SOFTWARE_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \
"uniform float fade_start;\n" \
"uniform float fade_end;\n" \
GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \
"vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
"vec4 base_color = texel * poly_color;\n" \
"vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \
"final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \
"}\0"
// same as above but multiplies results with the lighting value from the
// accompanying vertex shader (stored in gl_Color)
#define GLSL_SOFTWARE_MODEL_LIGHTING_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \
"uniform float fade_start;\n" \
"uniform float fade_end;\n" \
GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \
"vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
"vec4 base_color = texel * poly_color;\n" \
"vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \
"final_color *= gl_Color;\n" \
"final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \
"}\0"
//
// Water surface shader
//
// Mostly guesstimated, rather than the rest being built off Software science.
// Still needs to distort things underneath/around the water...
//
#define GLSL_WATER_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \
"uniform float fade_start;\n" \
"uniform float fade_end;\n" \
"uniform float leveltime;\n" \
"const float freq = 0.025;\n" \
"const float amp = 0.025;\n" \
"const float speed = 2.0;\n" \
"const float pi = 3.14159;\n" \
GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \
"float z = (gl_FragCoord.z / gl_FragCoord.w) / 2.0;\n" \
"float a = -pi * (z * freq) + (leveltime * speed);\n" \
"float sdistort = sin(a) * amp;\n" \
"float cdistort = cos(a) * amp;\n" \
"vec4 texel = texture2D(tex, vec2(gl_TexCoord[0].s - sdistort, gl_TexCoord[0].t - cdistort));\n" \
"vec4 base_color = texel * poly_color;\n" \
"vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \
"final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \
"}\0"
//
// Fog block shader
//
// Alpha of the planes themselves are still slightly off -- see HWR_FogBlockAlpha
//
#define GLSL_FOG_FRAGMENT_SHADER \
"uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \
"uniform float fade_start;\n" \
"uniform float fade_end;\n" \
GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \
"vec4 base_color = gl_Color;\n" \
"vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \
"gl_FragColor = final_color;\n" \
"}\0"
//
// Sky fragment shader
// Modulates poly_color with gl_Color
//
#define GLSL_SKY_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \
"void main(void) {\n" \
"gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \
"}\0"
// ================
// Shader sources
// ================
static struct {
const char *vertex;
const char *fragment;
} const gl_shadersources[] = {
// Default shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_DEFAULT_FRAGMENT_SHADER},
// Floor shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER},
// Wall shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER},
// Sprite shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER},
// Model shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER},
// Model shader + diffuse lighting from above
{GLSL_MODEL_LIGHTING_VERTEX_SHADER, GLSL_SOFTWARE_MODEL_LIGHTING_FRAGMENT_SHADER},
// Water shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_WATER_FRAGMENT_SHADER},
// Fog shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_FOG_FRAGMENT_SHADER},
// Sky shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SKY_FRAGMENT_SHADER},
{NULL, NULL},
};
#endif // GL_SHADERS
void SetupGLFunc4(void)
@ -910,55 +698,19 @@ void SetupGLFunc4(void)
pgluBuild2DMipmaps = GetGLFunc("gluBuild2DMipmaps");
}
EXPORT boolean HWRAPI(CompileShaders) (void)
EXPORT boolean HWRAPI(InitShaders) (void)
{
#ifdef GL_SHADERS
GLint i;
if (!pglUseProgram)
return false;
gl_fallback_shader.vertex_shader = Z_StrDup(GLSL_FALLBACK_VERTEX_SHADER);
gl_fallback_shader.fragment_shader = Z_StrDup(GLSL_FALLBACK_FRAGMENT_SHADER);
gl_customshaders[SHADER_DEFAULT].vertex = NULL;
gl_customshaders[SHADER_DEFAULT].fragment = NULL;
for (i = 0; gl_shadersources[i].vertex && gl_shadersources[i].fragment; i++)
if (!Shader_CompileProgram(&gl_fallback_shader, -1))
{
gl_shader_t *shader, *usershader;
const GLchar *vert_shader = gl_shadersources[i].vertex;
const GLchar *frag_shader = gl_shadersources[i].fragment;
if (i >= HWR_MAXSHADERS)
break;
shader = &gl_shaders[i];
usershader = &gl_usershaders[i];
if (shader->program)
pglDeleteProgram(shader->program);
if (usershader->program)
pglDeleteProgram(usershader->program);
shader->program = 0;
usershader->program = 0;
if (!Shader_CompileProgram(shader, i, vert_shader, frag_shader))
shader->program = 0;
// Compile custom shader
if ((i == SHADER_DEFAULT) || !(gl_customshaders[i].vertex || gl_customshaders[i].fragment))
continue;
// 18032019
if (gl_customshaders[i].vertex)
vert_shader = gl_customshaders[i].vertex;
if (gl_customshaders[i].fragment)
frag_shader = gl_customshaders[i].fragment;
if (!Shader_CompileProgram(usershader, i, vert_shader, frag_shader))
{
GL_MSG_Warning("CompileShaders: Could not compile custom shader program for %s\n", HWR_GetShaderName(i));
usershader->program = 0;
}
GL_MSG_Error("Failed to compile the fallback shader program!\n");
return false;
}
return true;
@ -967,6 +719,58 @@ EXPORT boolean HWRAPI(CompileShaders) (void)
#endif
}
EXPORT void HWRAPI(LoadShader) (int slot, char *code, hwdshaderstage_t stage)
{
#ifdef GL_SHADERS
gl_shader_t *shader;
if (slot < 0 || slot >= HWR_MAXSHADERS)
I_Error("LoadShader: Invalid slot %d", slot);
shader = &gl_shaders[slot];
#define LOADSHADER(source) { \
if (shader->source) \
Z_Free(shader->source); \
shader->source = code; \
}
if (stage == HWD_SHADERSTAGE_VERTEX)
LOADSHADER(vertex_shader)
else if (stage == HWD_SHADERSTAGE_FRAGMENT)
LOADSHADER(fragment_shader)
else
I_Error("LoadShader: invalid shader stage");
#undef LOADSHADER
#else
(void)slot;
(void)code;
(void)stage;
#endif
}
EXPORT boolean HWRAPI(CompileShader) (int slot)
{
#ifdef GL_SHADERS
if (slot < 0 || slot >= HWR_MAXSHADERS)
I_Error("CompileShader: Invalid slot %d", slot);
if (Shader_CompileProgram(&gl_shaders[slot], slot))
{
return true;
}
else
{
gl_shaders[slot].program = 0;
return false;
}
#else
(void)slot;
return false;
#endif
}
//
// Shader info
// Those are given to the uniforms.
@ -989,84 +793,31 @@ EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value)
#endif
}
//
// Custom shader loading
//
EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boolean isfragment)
{
#ifdef GL_SHADERS
shadersource_t *shader;
if (!pglUseProgram)
return;
if (number < 1 || number > HWR_MAXSHADERS)
I_Error("LoadCustomShader: cannot load shader %d (min 1, max %d)", number, HWR_MAXSHADERS);
else if (code == NULL)
I_Error("LoadCustomShader: empty shader");
shader = &gl_customshaders[number];
#define COPYSHADER(source) { \
if (shader->source) \
free(shader->source); \
shader->source = malloc(size+1); \
strncpy(shader->source, code, size); \
shader->source[size] = 0; \
}
if (isfragment)
COPYSHADER(fragment)
else
COPYSHADER(vertex)
#else
(void)number;
(void)shader;
(void)size;
(void)fragment;
#endif
}
EXPORT void HWRAPI(SetShader) (int type)
EXPORT void HWRAPI(SetShader) (int slot)
{
#ifdef GL_SHADERS
if (gl_allowshaders != HWD_SHADEROPTION_OFF)
{
gl_shader_t *shader = gl_shaderstate.current;
gl_shader_t *next_shader = &gl_shaders[slot]; // the gl_shader_t we are going to switch to
// If using model lighting, set the appropriate shader.
// However don't override a custom shader.
if (type == SHADER_MODEL && model_lighting
&& !(gl_shaders[SHADER_MODEL].custom && !gl_shaders[SHADER_MODEL_LIGHTING].custom))
type = SHADER_MODEL_LIGHTING;
if (!next_shader->program)
next_shader = &gl_fallback_shader; // unusable shader, use fallback instead
if ((shader == NULL) || (GLuint)type != gl_shaderstate.type)
// update gl_shaderstate if an actual shader switch is needed
if (gl_shaderstate.current != next_shader)
{
gl_shader_t *baseshader = &gl_shaders[type];
gl_shader_t *usershader = &gl_usershaders[type];
if (usershader->program)
shader = (gl_allowshaders == HWD_SHADEROPTION_NOCUSTOM) ? baseshader : usershader;
else
shader = baseshader;
gl_shaderstate.current = shader;
gl_shaderstate.type = type;
gl_shaderstate.current = next_shader;
gl_shaderstate.program = next_shader->program;
gl_shaderstate.type = slot;
gl_shaderstate.changed = true;
}
if (gl_shaderstate.program != shader->program)
{
gl_shaderstate.program = shader->program;
gl_shaderstate.changed = true;
}
gl_shadersenabled = true;
gl_shadersenabled = (shader->program != 0);
return;
}
#else
(void)type;
(void)slot;
#endif
gl_shadersenabled = false;
}
@ -1085,25 +836,6 @@ EXPORT void HWRAPI(UnSetShader) (void)
gl_shadersenabled = false;
}
EXPORT void HWRAPI(CleanShaders) (void)
{
INT32 i;
for (i = 1; i < HWR_MAXSHADERS; i++)
{
shadersource_t *shader = &gl_customshaders[i];
if (shader->vertex)
free(shader->vertex);
if (shader->fragment)
free(shader->fragment);
shader->vertex = NULL;
shader->fragment = NULL;
}
}
// -----------------+
// SetNoTexture : Disable texture
// -----------------+
@ -2052,69 +1784,91 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF
#endif
}
static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader)
static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i)
{
GLuint gl_vertShader, gl_fragShader;
GLuint gl_vertShader = 0;
GLuint gl_fragShader = 0;
GLint result;
const GLchar *vert_shader = shader->vertex_shader;
const GLchar *frag_shader = shader->fragment_shader;
//
// Load and compile vertex shader
//
gl_vertShader = pglCreateShader(GL_VERTEX_SHADER);
if (!gl_vertShader)
if (shader->program)
pglDeleteProgram(shader->program);
if (!vert_shader && !frag_shader)
{
GL_MSG_Error("Shader_CompileProgram: Error creating vertex shader %s\n", HWR_GetShaderName(i));
GL_MSG_Error("Shader_CompileProgram: Missing shaders for shader program %s\n", HWR_GetShaderName(i));
return false;
}
pglShaderSource(gl_vertShader, 1, &vert_shader, NULL);
pglCompileShader(gl_vertShader);
// check for compile errors
pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
if (vert_shader)
{
Shader_CompileError("Error compiling vertex shader", gl_vertShader, i);
pglDeleteShader(gl_vertShader);
return false;
//
// Load and compile vertex shader
//
gl_vertShader = pglCreateShader(GL_VERTEX_SHADER);
if (!gl_vertShader)
{
GL_MSG_Error("Shader_CompileProgram: Error creating vertex shader %s\n", HWR_GetShaderName(i));
return false;
}
pglShaderSource(gl_vertShader, 1, &vert_shader, NULL);
pglCompileShader(gl_vertShader);
// check for compile errors
pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
Shader_CompileError("Error compiling vertex shader", gl_vertShader, i);
pglDeleteShader(gl_vertShader);
return false;
}
}
//
// Load and compile fragment shader
//
gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER);
if (!gl_fragShader)
if (frag_shader)
{
GL_MSG_Error("Shader_CompileProgram: Error creating fragment shader %s\n", HWR_GetShaderName(i));
pglDeleteShader(gl_vertShader);
pglDeleteShader(gl_fragShader);
return false;
}
//
// Load and compile fragment shader
//
gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER);
if (!gl_fragShader)
{
GL_MSG_Error("Shader_CompileProgram: Error creating fragment shader %s\n", HWR_GetShaderName(i));
pglDeleteShader(gl_vertShader);
pglDeleteShader(gl_fragShader);
return false;
}
pglShaderSource(gl_fragShader, 1, &frag_shader, NULL);
pglCompileShader(gl_fragShader);
pglShaderSource(gl_fragShader, 1, &frag_shader, NULL);
pglCompileShader(gl_fragShader);
// check for compile errors
pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
Shader_CompileError("Error compiling fragment shader", gl_fragShader, i);
pglDeleteShader(gl_vertShader);
pglDeleteShader(gl_fragShader);
return false;
// check for compile errors
pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
Shader_CompileError("Error compiling fragment shader", gl_fragShader, i);
pglDeleteShader(gl_vertShader);
pglDeleteShader(gl_fragShader);
return false;
}
}
shader->program = pglCreateProgram();
pglAttachShader(shader->program, gl_vertShader);
pglAttachShader(shader->program, gl_fragShader);
if (vert_shader)
pglAttachShader(shader->program, gl_vertShader);
if (frag_shader)
pglAttachShader(shader->program, gl_fragShader);
pglLinkProgram(shader->program);
// check link status
pglGetProgramiv(shader->program, GL_LINK_STATUS, &result);
// delete the shader objects
pglDeleteShader(gl_vertShader);
pglDeleteShader(gl_fragShader);
if (vert_shader)
pglDeleteShader(gl_vertShader);
if (frag_shader)
pglDeleteShader(gl_fragShader);
// couldn't link?
if (result != GL_TRUE)

View file

@ -46,6 +46,7 @@
#define _CREATE_DLL_ // necessary for Unix AND Windows
#include "../../doomdef.h"
#include "../hw_drv.h"
#include "../../z_zone.h"
// ==========================================================================
// DEFINITIONS

View file

@ -392,6 +392,7 @@
<ClCompile Include="..\hardware\hw_md2load.c" />
<ClCompile Include="..\hardware\hw_md3load.c" />
<ClCompile Include="..\hardware\hw_model.c" />
<ClCompile Include="..\hardware\hw_shaders.c" />
<ClCompile Include="..\hardware\r_opengl\r_opengl.c" />
<ClCompile Include="..\hardware\u_list.c" />
<ClCompile Include="..\hu_stuff.c" />

View file

@ -684,6 +684,9 @@
<ClCompile Include="..\hardware\hw_model.c">
<Filter>Hw_Hardware</Filter>
</ClCompile>
<ClCompile Include="..\hardware\hw_shaders.c">
<Filter>Hw_Hardware</Filter>
</ClCompile>
<ClCompile Include="..\hardware\u_list.c">
<Filter>Hw_Hardware</Filter>
</ClCompile>

View file

@ -105,13 +105,13 @@ void *hwSym(const char *funcName,void *handle)
GETFUNC(MakeScreenFinalTexture);
GETFUNC(DrawScreenFinalTexture);
GETFUNC(CompileShaders);
GETFUNC(CleanShaders);
GETFUNC(InitShaders);
GETFUNC(LoadShader);
GETFUNC(CompileShader);
GETFUNC(SetShader);
GETFUNC(UnSetShader);
GETFUNC(SetShaderInfo);
GETFUNC(LoadCustomShader);
#else //HWRENDER
if (0 == strcmp("FinishUpdate", funcName))

View file

@ -1878,13 +1878,13 @@ void VID_StartupOpenGL(void)
HWD.pfnMakeScreenFinalTexture=hwSym("MakeScreenFinalTexture",NULL);
HWD.pfnDrawScreenFinalTexture=hwSym("DrawScreenFinalTexture",NULL);
HWD.pfnCompileShaders = hwSym("CompileShaders",NULL);
HWD.pfnCleanShaders = hwSym("CleanShaders",NULL);
HWD.pfnInitShaders = hwSym("InitShaders",NULL);
HWD.pfnLoadShader = hwSym("LoadShader",NULL);
HWD.pfnCompileShader = hwSym("CompileShader",NULL);
HWD.pfnSetShader = hwSym("SetShader",NULL);
HWD.pfnUnSetShader = hwSym("UnSetShader",NULL);
HWD.pfnSetShaderInfo = hwSym("SetShaderInfo",NULL);
HWD.pfnLoadCustomShader = hwSym("LoadCustomShader",NULL);
vid.glstate = HWD.pfnInit() ? VID_GL_LIBRARY_LOADED : VID_GL_LIBRARY_ERROR; // let load the OpenGL library

View file

@ -859,10 +859,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
#ifdef HWRENDER
// Read shaders from file
if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED))
{
HWR_LoadCustomShadersFromFile(numwadfiles - 1, (type == RET_PK3));
HWR_CompileShaders();
}
#endif // HWRENDER
// TODO: HACK ALERT - Load Lua & SOC stuff right here. I feel like this should be out of this place, but... Let's stick with this for now.