Try to make sense of hl2 materials.

This commit is contained in:
Shpoike 2021-04-26 00:22:50 +01:00
parent 6658565956
commit 586a92ec47
4 changed files with 377 additions and 19 deletions

View File

@ -355,7 +355,7 @@ void GL_DeselectVAO(void);
typedef struct texture_s
{
char name[64];
char name[128];
unsigned vwidth, vheight; //used for lightmap coord generation
struct shader_s *shader;

View File

@ -627,7 +627,10 @@ qboolean Shader_ParseSkySides (char *shadername, char *texturename, texid_t *ima
"%s_%s",
"%s%s",
"env/%s%s",
"gfx/env/%s%s"
"gfx/env/%s%s",
#ifdef HL2BSPS
"materials/skybox/%s%s",
#endif
};
if (*texturename == '$')
@ -663,7 +666,8 @@ qboolean Shader_ParseSkySides (char *shadername, char *texturename, texid_t *ima
}
if (!images[i]->width)
{
Con_Printf("Sky \"%s\" missing texture: %s\n", shadername, path);
if (allokay)
Con_Printf("Sky \"%s\" missing texture: [gfx/env/]%s%s\n", shadername, texturename, skyname_suffix[countof(skyname_suffix)-1][i]);
images[i] = missing_texture;
allokay = false;
}
@ -7069,8 +7073,12 @@ void Shader_DefaultSkinShell(parsestate_t *ps, const char *shortname, const void
void Shader_Default2D(parsestate_t *ps, const char *shortname, const void *genargs)
{
shader_t *s = ps->s;
qboolean wrap;
if (Shader_ParseShader(ps, "default2d"))
return;
wrap = Com_FloatArgument(s->name, "WRAP", 4, 0);
if (sh_config.progs_supported && qrenderer != QR_DIRECT3D9
#ifdef HAVE_LEGACY
&& !dpcompat_nopremulpics.ival
@ -7080,35 +7088,35 @@ void Shader_Default2D(parsestate_t *ps, const char *shortname, const void *genar
//hexen2 needs premultiplied alpha to avoid looking ugly
//but that results in problems where things are drawn with alpha not 0, so scale vertex colour by alpha in the fragment program
Shader_DefaultScript(ps, shortname,
"{\n"
va("{\n"
"affine\n"
"nomipmaps\n"
"program default2d#PREMUL\n"
"{\n"
"clampmap $diffuse\n"
"%s $diffuse\n"
"blendfunc gl_one gl_one_minus_src_alpha\n"
"}\n"
"sort additive\n"
"}\n"
);
TEXASSIGN(s->defaulttextures->base, R_LoadHiResTexture(s->name, genargs, IF_PREMULTIPLYALPHA|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_CLAMP|IF_HIGHPRIORITY));
"}\n", (wrap?"map":"clampmap")
));
TEXASSIGN(s->defaulttextures->base, R_LoadHiResTexture(s->name, genargs, IF_PREMULTIPLYALPHA|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|(wrap?0:IF_CLAMP)|IF_HIGHPRIORITY));
}
else
{
Shader_DefaultScript(ps, shortname,
"{\n"
va("{\n"
"affine\n"
"nomipmaps\n"
"{\n"
"clampmap $diffuse\n"
"%s $diffuse\n"
"rgbgen vertex\n"
"alphagen vertex\n"
"blendfunc gl_src_alpha gl_one_minus_src_alpha\n"
"}\n"
"sort additive\n"
"}\n"
);
TEXASSIGN(s->defaulttextures->base, R_LoadHiResTexture(s->name, genargs, IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_CLAMP|IF_HIGHPRIORITY));
"}\n", (wrap?"map":"clampmap")
));
TEXASSIGN(s->defaulttextures->base, R_LoadHiResTexture(s->name, genargs, IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|(wrap?0:IF_CLAMP)|IF_HIGHPRIORITY));
}
}
void Shader_PolygonShader(struct shaderparsestate_s *ps, const char *shortname, const void *args)
@ -7276,6 +7284,305 @@ static void Shader_ReadShader(parsestate_t *ps, const char *shadersource, shader
}
}
#ifdef MATERIAL_VMT
typedef struct
{
char type[MAX_QPATH];
struct
{
char name[MAX_QPATH];
} tex[5];
char envmap[MAX_QPATH];
float alphatestref;
qboolean alphatest;
qboolean culldisable;
qboolean ignorez;
char *replaceblock;
} vmtstate_t;
static qboolean R_ReadVMT(const char *materialname, vmtstate_t *st);
static char *R_ParseVMTBlock(const char *fname, vmtstate_t *st, char *line)
{ //assumes the open { was already parsed, but will parse the close.
char *replace = NULL;
com_tokentype_t ttype;
char key[MAX_OSPATH];
char value[MAX_OSPATH];
char *qmark;
qboolean cond;
for(;line;)
{
line = COM_ParseType(line, key, sizeof(key), &ttype);
if (ttype == TTP_RAWTOKEN && !strcmp(key, "}"))
break; //end-of-block
line = COM_ParseType(line, value, sizeof(value), &ttype);
if (ttype == TTP_RAWTOKEN && !strcmp(value, "{"))
{ //sub block. we don't go into details here.
if (!Q_strcasecmp(key, "replace"))
replace = line;
else
Con_DPrintf("%s: Unknown block \"%s\"\n", fname, key);
line = R_ParseVMTBlock(fname, NULL, line);
continue;
}
while ((qmark = strchr(key, '?')))
{
*qmark++ = 0;
if (!Q_strcasecmp(key, "srgb"))
cond = !!(vid.flags & VID_SRGBAWARE);
else
{
Con_DPrintf("%s: Unknown vmt conditional \"%s\"\n", fname, key);
cond = false;
}
if (!cond)
{
*key = 0;
break;
}
else
memmove(key, qmark, strlen(qmark)+1);
}
if (!*key || !st)
;
else if (!Q_strcasecmp(key, "include"))
{
if (!R_ReadVMT(value, st))
return NULL;
}
else if (!Q_strcasecmp(key, "$basetexture") || !Q_strcasecmp(key, "$hdrbasetexture")) //fixme: hdr version should probably override the other. order matters.
Q_strncpyz(st->tex[0].name, value, sizeof(st->tex[0].name));
else if (!Q_strcasecmp(key, "$hdrcompressedtexture")) //named texture is R8G8B8E8 and needs to be decompressed manually... should probably just use e5bgr9 but we don't have a way to transcode it here.
;
else if (!Q_strcasecmp(key, "$basetexturetransform"))
;
else if (!Q_strcasecmp(key, "$bumpmap"))
;
else if (!Q_strcasecmp(key, "$ssbump"))
;
else if (!Q_strcasecmp(key, "$ssbumpmathfix"))
;
else if (!Q_strcasecmp(key, "$basetexture2") || !strcmp(key, "$texture2"))
Q_strncpyz(st->tex[1].name, value, sizeof(st->tex[1].name));
else if (!Q_strcasecmp(key, "$basetexturetransform2"))
;
else if (!Q_strcasecmp(key, "$surfaceprop"))
;
else if (!Q_strcasecmp(key, "$ignorez"))
st->ignorez = !!atoi(value);
else if (!Q_strcasecmp(key, "$nocull") && (!strcmp(value, "1")||!strcmp(value, "0")))
st->culldisable = atoi(value);
else if (!Q_strcasecmp(key, "$alphatest") && (!strcmp(value, "1")||!strcmp(value, "0")))
st->alphatest = atoi(value);
else if (!Q_strcasecmp(key, "$alphatestreference"))
st->alphatestref = atof(value);
else if (!Q_strcasecmp(key, "$alphafunc"))
{
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
}
else if (!Q_strcasecmp(key, "$alpha"))
{
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
}
else if (!Q_strcasecmp(key, "$translucent"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$additive"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$color"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$vertexcolor"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$vertexalpha"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$decal"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$decalscale"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$decalsize"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$envmap"))
Q_strncpyz(st->envmap, value, sizeof(st->envmap));
else if (!Q_strcasecmp(key, "$envmaptint"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$envmapmask"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$envmapcontrast"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$envmaptint"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$envmapsaturation"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$basealphaenvmapmask"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$normalmapalphaenvmapmask"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$crackmaterial"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$selfillum"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$selfillummask"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$selfillumtint"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$nofog"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$nomip"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$nodecal"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$detail"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$detailscale"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$detailtint"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$detailblendfactor"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$detailblendmode"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$surfaceprop2"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$AllowAlphaToCoverage"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$blendmodulatetexture"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
//water/reflection stuff
else if (!Q_strcasecmp(key, "$refracttexture"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$refractamount"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$refracttint"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$reflecttexture"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$reflectamount"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$reflecttint"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$fresnelpower"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$minreflectivity"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$maxreflectivity"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$normalmap"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$bumpframe"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$fogenable"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$fogcolor"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$fogstart"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$fogend"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$abovewater"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$underwateroverlay"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$reflectentities"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$scale"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$bottommaterial"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$scroll1"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (!Q_strcasecmp(key, "$scroll2"))
Con_DPrintf("%s: %s \"%s\"\n", fname, key, value);
else if (*key == '%')
; //editor lines
else
Con_Printf("%s: Unknown field \"%s\"\n", fname, key);
}
if (replace)
R_ParseVMTBlock(fname, st, replace);
return line;
}
static void Shader_GenerateFromVMT(parsestate_t *ps, vmtstate_t *st, const char *shortname)
{
size_t offset = 0;
char script[8192];
if (!*st->tex[0].name)
Q_strncpyz(st->tex[0].name, shortname, sizeof(st->tex[0].name));
//Q_strlcatfz(script, &offset, sizeof(script), "{\n");
if (!Q_strcasecmp(st->type, "WorldVertexTransition"))
{ //attempt to do terrain blending
Q_strncpyz(st->type, "defaultwall#TWOWAY", sizeof(st->type));
Q_strlcatfz(script, &offset, sizeof(script), "program \"%s\"\n", st->type);
Q_strlcatfz(script, &offset, sizeof(script), "diffusemap \"%s%s.vtf\"\n", strcmp(st->tex[0].name, "materials/")?"materials/":"", st->tex[0].name);
Q_strlcatfz(script, &offset, sizeof(script), "uppermap \"%s%s.vtf\"\n", strcmp(st->tex[1].name, "materials/")?"materials/":"", st->tex[1].name);
}
else
{
Q_strncpyz(st->type, "defaultwall", sizeof(st->type)); //FIXME
Q_strlcatfz(script, &offset, sizeof(script), "program \"%s\"\n", st->type);
Q_strlcatfz(script, &offset, sizeof(script), "diffusemap \"%s%s.vtf\"\n", strcmp(st->tex[0].name, "materials/")?"materials/":"", st->tex[0].name);
}
if (*st->envmap)
Q_strlcatfz(script, &offset, sizeof(script), "reflectcube \"%s%s.vtf\"\n", strcmp(st->envmap, "materials/")?"materials/":"", st->envmap);
if (st->alphatest)
Q_strlcatfz(script, &offset, sizeof(script), "alphatest ge128\n");
if (st->culldisable)
Q_strlcatfz(script, &offset, sizeof(script), "cull disable\n");
if (st->ignorez)
Q_strlcatfz(script, &offset, sizeof(script), "nodepth\n");
Q_strlcatfz(script, &offset, sizeof(script), "}\n");
Shader_Reset(ps->s);
Shader_ReadShader(ps, script, NULL);
}
static qboolean R_ReadVMT(const char *fname, vmtstate_t *st)
{
char *line, *file = NULL;
com_tokentype_t ttype;
char token[MAX_QPATH];
char *prefix="", *postfix="";
//don't dupe the mandatory materials/ prefix
if (strncmp(fname, "materials/", 10))
prefix = "materials/";
if (strcmp(COM_GetFileExtension(fname, NULL), ".vmt"))
postfix = ".vmt";
Q_snprintfz(token, sizeof(token), "%s%s%s", prefix, fname, postfix);
file = FS_LoadMallocFile(token, NULL);
if (file)
{
line = file;
line = COM_ParseType(line, st->type, sizeof(st->type), &ttype);
line = COM_ParseType(line, token, sizeof(token), &ttype);
if (!strcmp(token, "{"))
{
line = R_ParseVMTBlock(fname, st, line);
}
BZ_Free(file);
return !!line;
}
return false;
}
static qboolean Shader_ReadVMT(parsestate_t *ps, const char *filename)
{
vmtstate_t st;
memset(&st, 0, sizeof(st));
if (!R_ReadVMT(filename, &st))
return false;
Shader_GenerateFromVMT(ps, &st, filename);
return true;
}
#endif
static qboolean Shader_ParseShader(parsestate_t *ps, const char *parsename)
{
size_t offset = 0, length;
@ -7293,6 +7600,11 @@ static qboolean Shader_ParseShader(parsestate_t *ps, const char *parsename)
char shaderfile[MAX_QPATH];
if (!*token)
{
#ifdef MATERIAL_VMT
if (Shader_ReadVMT(ps, parsename))
return true;
#endif
Q_snprintfz(shaderfile, sizeof(shaderfile), "%s.mat", parsename);
file = COM_LoadTempMoreFile(shaderfile, &length);
}

View File

@ -42,6 +42,9 @@ cvar_t r_skyboxname = CVARFC ("r_skybox", "", CVAR_RENDERERCALLBACK | CVAR
cvar_t r_skybox_orientation = CVARFD ("r_glsl_skybox_orientation", "0 0 0 0", CVAR_SHADERSYSTEM, "Defines the axis around which skyboxes will rotate (the first three values). The fourth value defines the speed the skybox rotates at, in degrees per second.");
cvar_t r_skyfog = CVARD ("r_skyfog", "0.5", "This controls an alpha-blend value for fog on skyboxes, cumulative with regular fog alpha.");
#ifdef MATERIAL_VMT
static shader_t *forcedskyfaces[6];
#endif
static shader_t *forcedsky;
static shader_t *skyboxface;
static shader_t *skygridface;
@ -55,6 +58,9 @@ void R_SkyShutdown(void)
skyboxface = NULL;
skygridface = NULL;
forcedsky = NULL;
#ifdef MATERIAL_VMT
memset(forcedskyfaces, 0, sizeof(forcedskyfaces));
#endif
}
//lets the backend know which fallback envmap it can use.
@ -89,8 +95,21 @@ void R_SetSky(const char *sky)
if (!*sky)
return; //no need to do anything
#ifdef MATERIAL_VMT //hl2 skies have specific shaders (with their own maps) for each face. can't automatically use cubemap optimisations - we would need to interrogate the shaders. :(
for (i = 0; i < 6; i++)
{
static const char *facenames[] = {"rt", "bk", "lf", "ft", "up", "dn"};
forcedskyfaces[i] = R_RegisterCustom(va("materials/skybox/%s%s", sky, facenames[i]), SUF_NONE, NULL, NULL); //don't allow a fallback, so we know when it fails.
if (!forcedskyfaces[i])
break;
}
if (i == 6)
return; //okay, we have all 6 faces okay...
memset(forcedskyfaces, 0, sizeof(forcedskyfaces));
#endif
memset(&tex, 0, sizeof(tex));
//equirectangular skies
tex.base = R_LoadHiResTexture(sky, "env:gfx/env", IF_LOADNOW|IF_NOMIPMAP);
if (tex.reflectcube && tex.reflectcube->status == TEX_LOADING)
COM_WorkerPartialSync(tex.reflectcube, &tex.reflectcube->status, TEX_LOADING);
@ -442,6 +461,13 @@ qboolean R_DrawSkyChain (batch_t *batch)
if (!opaque)
GL_DrawSkySphere(batch, skyshader);
}
#ifdef MATERIAL_VMT
else if (forcedskyfaces[0])
{
R_CalcSkyChainBounds(batch);
GL_DrawSkyBox (NULL, batch);
}
#endif
else if (skyboxtex && TEXVALID(*skyboxtex))
{ //draw a skybox if we were given the textures
R_CalcSkyChainBounds(batch);
@ -1130,7 +1156,7 @@ static void GL_DrawSkyBox (texid_t *texnums, batch_t *s)
skyfacemesh.numindexes = 6;
skyfacemesh.numvertexes = 4;
if (!skyboxface)
if (texnums && !skyboxface)
skyboxface = R_RegisterShader("skyboxface", SUF_NONE,
"{\n"
"program default2d\n"
@ -1152,8 +1178,15 @@ static void GL_DrawSkyBox (texid_t *texnums, batch_t *s)
GL_MakeSkyVec (skymaxs[0][i], skymaxs[1][i], i, skyface_vertex[2], skyface_texcoord[2]);
GL_MakeSkyVec (skymaxs[0][i], skymins[1][i], i, skyface_vertex[3], skyface_texcoord[3]);
skyboxface->defaulttextures->base = texnums[skytexorder[i]];
R_DrawSkyMesh(s, &skyfacemesh, skyboxface);
#ifdef MATERIAL_VMT
if (!texnums)
R_DrawSkyMesh(s, &skyfacemesh, forcedskyfaces[skytexorder[i]]);
else
#endif
{
skyboxface->defaulttextures->base = texnums[skytexorder[i]];
R_DrawSkyMesh(s, &skyfacemesh, skyboxface);
}
}
}

View File

@ -7,6 +7,8 @@
!!permu BUMP
!!permu SPECULAR
!!permu REFLECTCUBEMASK
//!!permu TWOWAY //blend between diffuse and the 'upper' texture.
//!!permu EIGHTBIT //our fancy software banding.
!!permu FAKESHADOWS
!!cvarf r_glsl_offsetmapping_scale
!!cvardf r_glsl_pcf
@ -16,12 +18,14 @@
!!samps !EIGHTBIT =BUMP normalmap
!!samps !EIGHTBIT =REFLECTCUBEMASK reflectmask reflectcube
//diffuse gives us alpha, and prevents dlight from bugging out when there's no diffuse.
!!samps =EIGHTBIT paletted 1
!!samps =EIGHTBIT colourmap=0
!!samps =EIGHTBIT paletted
!!samps =SPECULAR specular
!!samps !VERTEXLIT lightmap
!!samps =LIGHTSTYLED lightmap1 lightmap2 lightmap3
!!samps =DELUXE deluxemap
!!samps =LIGHTSTYLED =DELUXE deluxemap1 deluxemap2 deluxemap3
!!samps =TWOWAY upper
!!samps =FAKESHADOWS shadowmap
#if defined(ORM) || defined(SG)
@ -56,7 +60,9 @@
varying vec2 lm0;
#endif
#endif
#ifdef TWOWAY
varying float alpha;
#endif
#ifdef FAKESHADOWS
varying vec4 vtexprojcoord;
#endif
@ -81,6 +87,9 @@ void main ()
#ifdef FLOW
tc.s += e_time * -0.5;
#endif
#ifdef TWOWAY
alpha = v_colour.a;
#endif
#ifdef VERTEXLIT
#ifdef LIGHTSTYLED
//FIXME, only one colour.
@ -249,7 +258,6 @@ void main()
#ifdef FRAGMENT_SHADER
#define s_colourmap s_t0
#include "sys/pbr.h"
#include "sys/pcf.h"
@ -283,6 +291,11 @@ void main ()
//Read the base texture (with EIGHTBIT only alpha is needed)
vec4 col = texture2D(s_diffuse, tc);
#ifdef TWOWAY
gl_FragColor *= (1.0-alpha);
gl_FragColor += alpha*texture2D(s_upper, tc);
#endif
#if defined(BUMP) && (defined(DELUXE) || defined(SPECULAR) || defined(REFLECTCUBEMASK))
vec3 norm = normalize(texture2D(s_normalmap, tc).rgb - 0.5);
#elif defined(PBR) || defined(SPECULAR) || defined(DELUXE) || defined(REFLECTCUBEMASK)