fteqw/engine/gl/r_bishaders.h
Spoike 54c0810d41 fix nq bob (also fixes show_speed in nq)
tweaked waterwarp+bloom to use fbos. this fixes any issues with viewsize 10 or whatever, but depends upon npot.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4727 fc73d0e0-1445-4013-8a0c-d673dee63da5
2014-08-19 06:08:23 +00:00

2595 lines
67 KiB
C

/*
WARNING: THIS FILE IS GENERATED BY 'generatebuiltinsl.c'.
YOU SHOULD NOT EDIT THIS FILE BY HAND
*/
#ifdef GLQUAKE
{QR_OPENGL, 110, "altwater",
"!!cvarf r_glsl_turbscale\n"
//modifier: REFLECT (s_t2 is a reflection instead of diffusemap)
//modifier: STRENGTH (0.1 = fairly gentle, 0.2 = big waves)
//modifier: FRESNEL (5=water)
//modifier: TXSCALE (0.2 - wave strength)
//modifier: RIPPLEMAP (s_t3 contains a ripplemap
//modifier: TINT (some colour value)
"uniform float cvar_r_glsl_turbscale;\n"
"#ifndef FRESNEL\n"
"#define FRESNEL 5.0\n"
"#endif\n"
"#ifndef STRENGTH\n"
"#define STRENGTH 0.1\n"
"#endif\n"
"#ifndef TXSCALE\n"
"#define TXSCALE 0.2\n"
"#endif\n"
"#ifndef TINT\n"
"#define TINT vec3(0.7, 0.8, 0.7)\n"
"#endif\n"
"#ifndef FOGTINT\n"
"#define FOGTINT vec3(0.2, 0.3, 0.2)\n"
"#endif\n"
"varying vec2 tc;\n"
"varying vec4 tf;\n"
"varying vec3 norm;\n"
"varying vec3 eye;\n"
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"attribute vec3 v_normal;\n"
"uniform vec3 e_eyepos;\n"
"void main (void)\n"
"{\n"
"tc = v_texcoord.st;\n"
"tf = ftetransform();\n"
"norm = v_normal;\n"
"eye = e_eyepos - v_position.xyz;\n"
"gl_Position = tf;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D s_t0; //refract\n"
"uniform sampler2D s_t1; //normalmap\n"
"uniform sampler2D s_t2; //diffuse/reflection\n"
"#ifdef DEPTH\n"
"uniform sampler2D s_t3; //refraction depth\n"
"#define s_ripplemap s_t4\n"
"#else\n"
"#define s_ripplemap s_t3\n"
"#endif\n"
"#ifdef RIPPLEMAP\n"
"uniform sampler2D s_ripplemap; //ripplemap\n"
"#endif\n"
"uniform float e_time;\n"
"void main (void)\n"
"{\n"
"vec2 stc, ntc;\n"
"vec3 n, refr, refl;\n"
"float fres;\n"
"float depth;\n"
"stc = (1.0 + (tf.xy / tf.w)) * 0.5;\n"
//hack the texture coords slightly so that there are no obvious gaps
"stc.t -= 1.5*norm.z/1080.0;\n"
//apply q1-style warp, just for kicks
"ntc.s = tc.s + sin(tc.t+e_time)*0.125;\n"
"ntc.t = tc.t + sin(tc.s+e_time)*0.125;\n"
//generate the two wave patterns from the normalmap
"n = (texture2D(s_t1, TXSCALE*tc + vec2(e_time*0.1, 0.0)).xyz);\n"
"n += (texture2D(s_t1, TXSCALE*tc - vec2(0, e_time*0.097)).xyz);\n"
"n -= 1.0 - 4.0/256.0;\n"
"#ifdef RIPPLEMAP\n"
"n += texture2D(s_ripplemap, stc).rgb*3.0;\n"
"#endif\n"
//the fresnel term decides how transparent the water should be
"fres = pow(1.0-abs(dot(normalize(n), normalize(eye))), float(FRESNEL));\n"
"#ifdef DEPTH\n"
"float far = #include \"cvar/gl_maxdist\";\n"
"float near = #include \"cvar/gl_mindist\";\n"
//get depth value at the surface
"float sdepth = gl_FragCoord.z;\n"
"sdepth = (2.0*near) / (far + near - sdepth * (far - near));\n"
"sdepth = mix(near, far, sdepth);\n"
//get depth value at the ground beyond the surface.
"float gdepth = texture2D(s_t3, stc).x;\n"
"gdepth = (2.0*near) / (far + near - gdepth * (far - near));\n"
"if (gdepth >= 0.5)\n"
"{\n"
"gdepth = sdepth;\n"
"depth = 0.0;\n"
"}\n"
"else\n"
"{\n"
"gdepth = mix(near, far, gdepth);\n"
"depth = gdepth - sdepth;\n"
"}\n"
//reduce the normals in shallow water (near walls, reduces the pain of linear sampling)
"if (depth < 100.0)\n"
"n *= depth/100.0;\n"
"#else\n"
"depth = 1.0;\n"
"#endif \n"
//refraction image (and water fog, if possible)
"refr = texture2D(s_t0, stc + n.st*STRENGTH*cvar_r_glsl_turbscale).rgb * TINT;\n"
"#ifdef DEPTH\n"
"refr = mix(refr, FOGTINT, min(depth/4096.0, 1.0));\n"
"#endif\n"
//reflection/diffuse
"#ifdef REFLECT\n"
"refl = texture2D(s_t2, stc - n.st*STRENGTH*cvar_r_glsl_turbscale).rgb;\n"
"#else\n"
"refl = texture2D(s_t2, ntc).xyz;\n"
"#endif\n"
//FIXME: add specular
//interplate by fresnel
"refr = mix(refr, refl, fres);\n"
//done
"gl_FragColor = vec4(refr, 1.0);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "bloom_blur",
//apply gaussian filter
"varying vec2 tc;\n"
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"void main ()\n"
"{\n"
"tc = v_texcoord;\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
/*offset should be 1.2 pixels away from the center*/
"uniform vec3 e_glowmod;\n"
"uniform sampler2D s_t0;\n"
"void main ()\n"
"{\n"
"gl_FragColor =\n"
"0.3125 * texture2D(s_t0, tc - e_glowmod.st) +\n"
"0.375 * texture2D(s_t0, tc) +\n"
"0.3125 * texture2D(s_t0, tc + e_glowmod.st);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "bloom_filter",
"!!cvarv r_bloom_filter\n"
//the bloom filter
//filter out any texels which are not to bloom
"uniform vec3 cvar_r_bloom_filter;\n"
"varying vec2 tc;\n"
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"void main ()\n"
"{\n"
"tc = v_texcoord;\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D s_t0;\n"
"void main ()\n"
"{\n"
"gl_FragColor.rgb = (texture2D(s_t0, tc).rgb - cvar_r_bloom_filter)/(1.0-cvar_r_bloom_filter);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "bloom_final",
"!!cvarf r_bloom\n"
"uniform float cvar_r_bloom;\n"
//add them together
//optionally apply tonemapping
"varying vec2 tc;\n"
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"void main ()\n"
"{\n"
"tc = v_texcoord;\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D s_t0;\n"
"uniform sampler2D s_t1;\n"
"uniform sampler2D s_t2;\n"
"uniform sampler2D s_t3;\n"
"void main ()\n"
"{\n"
"gl_FragColor = \n"
"texture2D(s_t0, tc) +\n"
"cvar_r_bloom*(\n"
"texture2D(s_t1, tc) +\n"
"texture2D(s_t2, tc) +\n"
"texture2D(s_t3, tc)\n"
") ;\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "colourtint",
//this glsl shader is useful for cubemapped post processing effects (see csaddon for an example)
"varying vec4 tf;\n"
"#ifdef VERTEX_SHADER\n"
"void main ()\n"
"{\n"
"gl_Position = tf = vec4(v_position.xy,-1.0, 1.0);\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D s_t0;\n"
"uniform sampler3D s_t1;\n"
"void main()\n"
"{\n"
"vec2 fc;\n"
"fc = tf.xy / tf.w;\n"
"vec3 raw = texture2D(s_t0, (1.0 + fc) / 2.0).rgb;\n"
"#define LUTSIZE 16.0\n"
"vec3 scale = vec3((LUTSIZE-1.0)/LUTSIZE);\n"
"vec3 bias = vec3(1.0/(2.0*LUTSIZE));\n"
"gl_FragColor = texture3D(s_t1, raw * scale + bias);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "crepuscular_opaque",
//opaque surfaces are drawn to the render target to mask out skies
"#ifdef VERTEX_SHADER\n"
"void main ()\n"
"{\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"void main()\n"
"{\n"
"gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "crepuscular_rays",
"!!cvarf crep_decay\n"
"!!cvarf crep_density\n"
"!!cvarf crep_weight\n"
//this is a post-processing shader, drawn in 2d
//there will be a render target containing sky surfaces drawn with crepuscular_sky, and everything else drawn with crepuscular_opaque (to mask out the sky)
//this shader then just smudges the sky out a bit as though its coming from the sun or whatever through the clouds.
//yoinked from http://fabiensanglard.net/lightScattering/index.php
"varying vec2 tc;\n"
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"void main ()\n"
"{\n"
"tc = v_texcoord;\n"
"gl_Position = v_position;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"const float crep_decay = 0.94;\n"
"const float crep_density = 0.5;\n"
"const float crep_weight = 0.2;\n"
"uniform vec3 l_lightcolour;\n"
"uniform vec3 l_lightscreen;\n"
"uniform sampler2D s_t0;\n"
"const int NUM_SAMPLES = 100;\n"
"void main()\n"
"{\n"
"vec2 deltaTextCoord = vec2(tc.st - l_lightscreen.xy);\n"
"vec2 textCoo = tc.st;\n"
"deltaTextCoord *= 1.0 / float(NUM_SAMPLES) * crep_density;\n"
"float illuminationDecay = 1.0;\n"
"for(int i=0; i < NUM_SAMPLES ; i++)\n"
"{\n"
"textCoo -= deltaTextCoord;\n"
"vec4 sample = texture2D(s_t0, textCoo);\n"
"sample *= illuminationDecay * crep_weight;\n"
"gl_FragColor += sample;\n"
"illuminationDecay *= crep_decay;\n"
"}\n"
"gl_FragColor *= vec4(l_lightcolour, 1.0);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "crepuscular_sky",
//pretty much a regular sky shader
//though in reality we should render a sun circle in the middle.
//still, its kinda cool to have scrolling clouds masking out parts of the sun.
"#ifdef VERTEX_SHADER\n"
"varying vec3 pos;\n"
"void main ()\n"
"{\n"
"pos = v_position.xyz;\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform float e_time;\n"
"uniform vec3 e_eyepos;\n"
"varying vec3 pos;\n"
"uniform sampler2D s_t0;\n"
"uniform sampler2D s_t1;\n"
"void main ()\n"
"{\n"
"vec2 tccoord;\n"
"vec3 dir = pos - e_eyepos;\n"
"dir.z *= 3.0;\n"
"dir.xy /= 0.5*length(dir);\n"
"tccoord = (dir.xy + e_time*0.03125);\n"
"vec3 solid = vec3(texture2D(s_t0, tccoord));\n"
"tccoord = (dir.xy + e_time*0.0625);\n"
"vec4 clouds = texture2D(s_t1, tccoord);\n"
"gl_FragColor.rgb = (solid.rgb*(1.0-clouds.a)) + (clouds.a*clouds.rgb);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "depthonly",
"!!permu FRAMEBLEND\n"
"!!permu SKELETAL\n"
//standard shader used for drawing shadowmap depth.
//also used for masking off portals and other things that want depth and no colour.
//must support skeletal and 2-way vertex blending or Bad Things Will Happen.
//the vertex shader is responsible for calculating lighting values.
"#ifdef VERTEX_SHADER\n"
"#include \"sys/skeletal.h\"\n"
"void main ()\n"
"{\n"
"gl_Position = skeletaltransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"void main ()\n"
"{\n"
//must always draw something, supposedly. It might as well be black.
"gl_FragColor = vec4(0, 0, 0, 1);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef D3D11QUAKE
{QR_DIRECT3D11, 11, "depthonly",
//used for generating shadowmaps and stuff that draws nothing.
"struct a2v\n"
"{\n"
"float4 pos: POSITION;\n"
"float3 normal: NORMAL;\n"
"#ifdef MASK\n"
"float4 tc: TEXCOORD0;\n"
"#endif\n"
"};\n"
"struct v2f\n"
"{\n"
"float4 pos: SV_POSITION;\n"
"#ifdef MASK\n"
"float2 tc: TEXCOORD0;\n"
"#endif\n"
"};\n"
"#include <ftedefs.h>\n"
"#ifdef VERTEX_SHADER\n"
"v2f main (a2v inp)\n"
"{\n"
"v2f outp;\n"
"outp.pos = mul(m_model, inp.pos);\n"
"outp.pos = mul(m_view, outp.pos);\n"
"outp.pos = mul(m_projection, outp.pos);\n"
"#ifdef MASK\n"
"outp.tc = inp.tc.xy;\n"
"#endif\n"
"return outp;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"#ifdef MASK\n"
"Texture2D shaderTexture[1];\n"
"SamplerState SampleType[1];\n"
"#endif\n"
"#if LEVEL < 1000\n"
//pre dx10 requires that we ALWAYS write to a target.
"float4 main (v2f inp) : SV_TARGET\n"
"#else\n"
//but on 10, it'll write depth automatically and we don't care about colour.
"void main (v2f inp) //dx10-level\n"
"#endif\n"
"{\n"
"#ifdef MASK\n"
"float alpha = shaderTexture[0].Sample(SampleType[0], inp.tc).a;\n"
"#ifndef MASKOP\n"
"#define MASKOP >= //drawn if (alpha OP ref) is true.\n"
"#endif\n"
//support for alpha masking
"if (!(alpha MASKOP MASK))\n"
"discard;\n"
"#endif\n"
"#if LEVEL < 1000\n"
"return float4(0, 0, 0, 1);\n"
"#endif\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "default2d",
//this shader is present for support for gles/gl3core contexts
//it is single-texture-with-vertex-colours, and doesn't do anything special.
//beware that a few things use this, including apparently fonts and bloom rescaling.
//its really not meant to do anything special.
"varying vec2 tc;\n"
"varying vec4 vc;\n"
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"attribute vec4 v_colour;\n"
"void main ()\n"
"{\n"
"tc = v_texcoord;\n"
"vc = v_colour;\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D s_t0;\n"
"void main ()\n"
"{\n"
"gl_FragColor = texture2D(s_t0, tc) * vc;\n"
"}\n"
"#endif\n"
},
#endif
#ifdef D3D11QUAKE
{QR_DIRECT3D11, 11, "default2d",
"struct a2v\n"
"{\n"
"float4 pos: POSITION;\n"
"float2 tc: TEXCOORD0;\n"
"float4 vcol: COLOR0;\n"
"};\n"
"struct v2f\n"
"{\n"
"float4 pos: SV_POSITION;\n"
"float2 tc: TEXCOORD0;\n"
"float4 vcol: COLOR0;\n"
"};\n"
"#include <ftedefs.h>\n"
"#ifdef VERTEX_SHADER\n"
"v2f main (a2v inp)\n"
"{\n"
"v2f outp;\n"
"outp.pos = mul(m_model, inp.pos);\n"
"outp.pos = mul(m_view, outp.pos);\n"
"outp.pos = mul(m_projection, outp.pos);\n"
"outp.tc = inp.tc;\n"
"outp.vcol = inp.vcol;\n"
"return outp;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"Texture2D shaderTexture;\n"
"SamplerState SampleType;\n"
"float4 main (v2f inp) : SV_TARGET\n"
"{\n"
"return shaderTexture.Sample(SampleType, inp.tc) * inp.vcol;\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "defaultadditivesprite",
"!!permu FOG\n"
//meant to be used for additive stuff. presumably particles and sprites. though actually its only flashblend effects that use this at the time of writing.
//includes fog, apparently.
"#include \"sys/fog.h\"\n"
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"attribute vec4 v_colour;\n"
"varying vec2 tc;\n"
"varying vec4 vc;\n"
"void main ()\n"
"{\n"
"tc = v_texcoord;\n"
"vc = v_colour;\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D s_t0;\n"
"varying vec2 tc;\n"
"varying vec4 vc;\n"
"uniform vec4 e_colourident;\n"
"void main ()\n"
"{\n"
"gl_FragColor = fog4additive(texture2D(s_t0, tc) * vc * e_colourident);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "defaultskin",
"!!permu FULLBRIGHT\n"
"!!permu UPPERLOWER\n"
"!!permu FRAMEBLEND\n"
"!!permu SKELETAL\n"
"!!permu FOG\n"
"!!permu BUMP\n"
"!!cvarf r_glsl_offsetmapping_scale\n"
"!!cvarf gl_specular\n"
//standard shader used for models.
//must support skeletal and 2-way vertex blending or Bad Things Will Happen.
//the vertex shader is responsible for calculating lighting values.
"varying vec2 tc;\n"
"varying vec3 light;\n"
"#if defined(SPECULAR) || defined(OFFSETMAPPING)\n"
"varying vec3 eyevector;\n"
"#endif\n"
"#ifdef VERTEX_SHADER\n"
"#include \"sys/skeletal.h\"\n"
"attribute vec2 v_texcoord;\n"
"uniform vec3 e_light_dir;\n"
"uniform vec3 e_light_mul;\n"
"uniform vec3 e_light_ambient;\n"
"#if defined(SPECULAR) || defined(OFFSETMAPPING)\n"
"uniform vec3 e_eyepos;\n"
"#endif\n"
"void main ()\n"
"{\n"
"#if defined(SPECULAR)||defined(OFFSETMAPPING)\n"
"vec3 n, s, t, w;\n"
"gl_Position = skeletaltransform_wnst(w,n,s,t);\n"
"vec3 eyeminusvertex = e_eyepos - w.xyz;\n"
"eyevector.x = dot(eyeminusvertex, s.xyz);\n"
"eyevector.y = dot(eyeminusvertex, t.xyz);\n"
"eyevector.z = dot(eyeminusvertex, n.xyz);\n"
"#else\n"
"vec3 n;\n"
"gl_Position = skeletaltransform_n(n);\n"
"#endif\n"
"float d = dot(n,e_light_dir);\n"
"if (d < 0.0) //vertex shader. this might get ugly, but I don't really want to make it per vertex.\n"
"d = 0.0; //this avoids the dark side going below the ambient level.\n"
"light = e_light_ambient + (dot(n,e_light_dir)*e_light_mul);\n"
"tc = v_texcoord;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"#include \"sys/fog.h\"\n"
"uniform sampler2D s_t0;\n"
"#ifdef LOWER\n"
"uniform sampler2D s_t1;\n"
"uniform vec3 e_lowercolour;\n"
"#endif\n"
"#ifdef UPPER\n"
"uniform sampler2D s_t2;\n"
"uniform vec3 e_uppercolour;\n"
"#endif\n"
"#ifdef FULLBRIGHT\n"
"uniform sampler2D s_t3;\n"
"#endif\n"
"#if defined(BUMP)\n"
"uniform sampler2D s_t4;\n"
"#endif\n"
"#if defined(SPECULAR)\n"
"uniform sampler2D s_t5;\n"
"uniform float cvar_gl_specular;\n"
"#endif\n"
"#ifdef OFFSETMAPPING\n"
"#include \"sys/offsetmapping.h\"\n"
"#endif\n"
"uniform vec4 e_colourident;\n"
"void main ()\n"
"{\n"
"vec4 col, sp;\n"
"#ifdef OFFSETMAPPING\n"
"vec2 tcoffsetmap = offsetmap(s_t4, tc, eyevector);\n"
"#define tc tcoffsetmap\n"
"#endif\n"
"col = texture2D(s_t0, tc);\n"
"#ifdef UPPER\n"
"vec4 uc = texture2D(s_t2, tc);\n"
"col.rgb += uc.rgb*e_uppercolour*uc.a;\n"
"#endif\n"
"#ifdef LOWER\n"
"vec4 lc = texture2D(s_t1, tc);\n"
"col.rgb += lc.rgb*e_lowercolour*lc.a;\n"
"#endif\n"
"col.rgb *= light;\n"
"#if defined(BUMP) && defined(SPECULAR)\n"
"vec3 bumps = normalize(vec3(texture2D(s_t4, tc)) - 0.5);\n"
"vec4 specs = texture2D(s_t5, tc);\n"
"vec3 halfdir = normalize(normalize(eyevector) + vec3(0.0, 0.0, 1.0));\n"
"float spec = pow(max(dot(halfdir, bumps), 0.0), 32.0 * specs.a);\n"
"col.rgb += cvar_gl_specular * spec * specs.rgb;\n"
"#endif\n"
"#ifdef FULLBRIGHT\n"
"vec4 fb = texture2D(s_t3, tc);\n"
// col.rgb = mix(col.rgb, fb.rgb, fb.a);
"col.rgb += fb.rgb * fb.a;\n"
"#endif\n"
"gl_FragColor = fog4(col * e_colourident);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef D3D11QUAKE
{QR_DIRECT3D11, 11, "defaultskin",
"struct a2v\n"
"{\n"
"float4 pos: POSITION;\n"
"float4 tc: TEXCOORD0;\n"
"float3 normal: NORMAL;\n"
"};\n"
"struct v2f\n"
"{\n"
"float4 pos: SV_POSITION;\n"
"float2 tc: TEXCOORD0;\n"
"float3 light: TEXCOORD1;\n"
"};\n"
"#include <ftedefs.h>\n"
"#ifdef VERTEX_SHADER\n"
//attribute vec2 v_texcoord;
//uniform vec3 e_light_dir;
//uniform vec3 e_light_mul;
//uniform vec3 e_light_ambient;
"v2f main (a2v inp)\n"
"{\n"
"v2f outp;\n"
"outp.pos = mul(m_model, inp.pos);\n"
"outp.pos = mul(m_view, outp.pos);\n"
"outp.pos = mul(m_projection, outp.pos);\n"
"outp.light = e_light_ambient + (dot(inp.normal,e_light_dir)*e_light_mul);\n"
"outp.tc = inp.tc.xy;\n"
"return outp;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"Texture2D shaderTexture[4]; //diffuse, lower, upper, fullbright\n"
"SamplerState SampleType;\n"
//uniform vec4 e_colourident;
"float4 main (v2f inp) : SV_TARGET\n"
"{\n"
"float4 col;\n"
"col = shaderTexture[0].Sample(SampleType, inp.tc);\n"
"#ifdef MASK\n"
"#ifndef MASKOP\n"
"#define MASKOP >= //drawn if (alpha OP ref) is true.\n"
"#endif\n"
//support for alpha masking
"if (!(col.a MASKOP MASK))\n"
"discard;\n"
"#endif\n"
"#ifdef UPPER\n"
"float4 uc = shaderTexture[2].Sample(SampleType, inp.tc);\n"
"col.rgb = mix(col.rgb, uc.rgb*e_uppercolour, uc.a);\n"
"#endif\n"
"#ifdef LOWER\n"
"float4 lc = shaderTexture[1].Sample(SampleType, inp.tc);\n"
"col.rgb = mix(col.rgb, lc.rgb*e_lowercolour, lc.a);\n"
"#endif\n"
"col.rgb *= inp.light;\n"
"#ifdef FULLBRIGHT\n"
"float4 fb = shaderTexture[3].Sample(SampleType, inp.tc);\n"
"col.rgb = mix(col.rgb, fb.rgb, fb.a);\n"
"#endif\n"
"return col;\n"
// return fog4(col * e_colourident);
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "defaultsky",
//regular sky shader for scrolling q1 skies
//the sky surfaces are thrown through this as-is.
"#ifdef VERTEX_SHADER\n"
"varying vec3 pos;\n"
"void main ()\n"
"{\n"
"pos = v_position.xyz;\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform float e_time;\n"
"uniform vec3 e_eyepos;\n"
"varying vec3 pos;\n"
"uniform sampler2D s_t0;\n"
"uniform sampler2D s_t1;\n"
"void main ()\n"
"{\n"
"vec2 tccoord;\n"
"vec3 dir = pos - e_eyepos;\n"
"dir.z *= 3.0;\n"
"dir.xy /= 0.5*length(dir);\n"
"tccoord = (dir.xy + e_time*0.03125);\n"
"vec3 solid = vec3(texture2D(s_t0, tccoord));\n"
"tccoord = (dir.xy + e_time*0.0625);\n"
"vec4 clouds = texture2D(s_t1, tccoord);\n"
"gl_FragColor.rgb = (solid.rgb*(1.0-clouds.a)) + (clouds.a*clouds.rgb);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef D3D9QUAKE
{QR_DIRECT3D9, 9, "defaultsky",
"struct a2v\n"
"{\n"
"float4 pos: POSITION;\n"
"};\n"
"struct v2f\n"
"{\n"
"#ifndef FRAGMENT_SHADER\n"
"float4 pos: POSITION;\n"
"#endif\n"
"float3 vpos: TEXCOORD0;\n"
"};\n"
"#ifdef VERTEX_SHADER\n"
"float4x4 m_modelviewprojection;\n"
"v2f main (a2v inp)\n"
"{\n"
"v2f outp;\n"
"outp.pos = mul(m_modelviewprojection, inp.pos);\n"
"outp.vpos = inp.pos;\n"
"return outp;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"float e_time;\n"
"float3 e_eyepos;\n"
"float l_lightradius;\n"
"float3 l_lightcolour;\n"
"float3 l_lightposition;\n"
"sampler s_t0; /*diffuse*/\n"
"sampler s_t1; /*normal*/\n"
"sampler s_t2; /*specular*/\n"
"float4 main (v2f inp) : COLOR0\n"
"{\n"
"float2 tccoord;\n"
"float3 dir = inp.vpos - e_eyepos;\n"
"dir.z *= 3.0;\n"
"dir.xy /= 0.5*length(dir);\n"
"tccoord = (dir.xy + e_time*0.03125);\n"
"float4 solid = tex2D(s_t0, tccoord);\n"
"tccoord = (dir.xy + e_time*0.0625);\n"
"float4 clouds = tex2D(s_t1, tccoord);\n"
"return float4((solid.rgb*(1.0-clouds.a)) + (clouds.a*clouds.rgb), 1);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef D3D11QUAKE
{QR_DIRECT3D11, 11, "defaultsky",
//regular sky shader for scrolling q1 skies
//the sky surfaces are thrown through this as-is.
"struct a2v\n"
"{\n"
"float4 pos: POSITION;\n"
"float2 tc: TEXCOORD0;\n"
"};\n"
"struct v2f\n"
"{\n"
"float4 pos: SV_POSITION;\n"
"float2 tc: TEXCOORD0;\n"
"float3 mpos: TEXCOORD1;\n"
"};\n"
"#include <ftedefs.h>\n"
"#ifdef VERTEX_SHADER\n"
"v2f main (a2v inp)\n"
"{\n"
"v2f outp;\n"
"outp.pos = mul(m_model, inp.pos);\n"
"outp.mpos = outp.pos.xyz;\n"
"outp.pos = mul(m_view, outp.pos);\n"
"outp.pos = mul(m_projection, outp.pos);\n"
"outp.tc = inp.tc;\n"
"return outp;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"Texture2D shaderTexture[2];\n"
"SamplerState SampleType;\n"
"float4 main (v2f inp) : SV_TARGET\n"
"{\n"
"float2 tccoord;\n"
"float3 dir = inp.mpos - v_eyepos;\n"
"dir.z *= 3.0;\n"
"dir.xy /= 0.5*length(dir);\n"
"tccoord = (dir.xy + e_time*0.03125);\n"
"float4 solid = shaderTexture[0].Sample(SampleType, tccoord);\n"
"tccoord = (dir.xy + e_time*0.0625);\n"
"float4 clouds = shaderTexture[1].Sample(SampleType, tccoord);\n"
"return (solid*(1.0-clouds.a)) + (clouds.a*clouds);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "defaultfill",
"#ifdef VERTEX_SHADER\n"
"attribute vec4 v_colour;\n"
"varying vec4 vc;\n"
"void main ()\n"
"{\n"
"vc = v_colour;\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"varying vec4 vc;\n"
"void main ()\n"
"{\n"
"gl_FragColor = vc;\n"
"}\n"
"#endif\n"
},
#endif
#ifdef D3D11QUAKE
{QR_DIRECT3D11, 11, "defaultfill",
"struct a2v\n"
"{\n"
"float4 pos: POSITION;\n"
"float4 vcol: COLOR0;\n"
"};\n"
"struct v2f\n"
"{\n"
"float4 pos: SV_POSITION;\n"
"float4 vcol: COLOR0;\n"
"};\n"
"#include <ftedefs.h>\n"
"#ifdef VERTEX_SHADER\n"
"v2f main (a2v inp)\n"
"{\n"
"v2f outp;\n"
"outp.pos = mul(m_projection, inp.pos);\n"
"outp.vcol = inp.vcol;\n"
"return outp;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"float4 main (v2f inp) : SV_TARGET\n"
"{\n"
"return inp.vcol;\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "defaultsprite",
"!!permu FOG\n"
//used by both particles and sprites.
//note the fog blending mode is all that differs from defaultadditivesprite
"#include \"sys/fog.h\"\n"
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"attribute vec4 v_colour;\n"
"varying vec2 tc;\n"
"varying vec4 vc;\n"
"void main ()\n"
"{\n"
"tc = v_texcoord;\n"
"vc = v_colour;\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D s_t0;\n"
"varying vec2 tc;\n"
"varying vec4 vc;\n"
"uniform vec4 e_colourident;\n"
"void main ()\n"
"{\n"
"vec4 col = texture2D(s_t0, tc);\n"
"#ifdef MASK\n"
"if (col.a < float(MASK))\n"
"discard;\n"
"#endif\n"
"gl_FragColor = fog4blend(col * vc * e_colourident);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef D3D11QUAKE
{QR_DIRECT3D11, 11, "defaultsprite",
"struct a2v\n"
"{\n"
"float4 pos: POSITION;\n"
"float4 tc: TEXCOORD0;\n"
"float4 vcol: COLOR0;\n"
"};\n"
"struct v2f\n"
"{\n"
"float4 pos: SV_POSITION;\n"
"float2 tc: TEXCOORD0;\n"
"float4 vcol: COLOR0;\n"
"};\n"
"#include <ftedefs.h>\n"
"#ifdef VERTEX_SHADER\n"
"v2f main (a2v inp)\n"
"{\n"
"v2f outp;\n"
"outp.pos = mul(m_model, inp.pos);\n"
"outp.pos = mul(m_view, outp.pos);\n"
"outp.pos = mul(m_projection, outp.pos);\n"
"outp.tc = inp.tc.xy;\n"
"outp.vcol = inp.vcol;\n"
"return outp;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"Texture2D shaderTexture;\n"
"SamplerState SampleType;\n"
"float4 main (v2f inp) : SV_TARGET\n"
"{\n"
"return shaderTexture.Sample(SampleType, inp.tc) * inp.vcol;\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "defaultwall",
"!!permu DELUXE\n"
"!!permu FULLBRIGHT\n"
"!!permu FOG\n"
"!!permu LIGHTSTYLED\n"
"!!permu BUMP\n"
"!!permu SPECULAR\n"
"!!cvarf r_glsl_offsetmapping_scale\n"
"!!cvarf gl_specular\n"
//this is what normally draws all of your walls, even with rtlights disabled
//note that the '286' preset uses drawflat_walls instead.
"#include \"sys/fog.h\"\n"
"#if defined(OFFSETMAPPING) || defined(SPECULAR)\n"
"varying vec3 eyevector;\n"
"#endif\n"
"varying vec2 tc;\n"
"#ifdef LIGHTSTYLED\n"
//we could use an offset, but that would still need to be per-surface which would break batches
//fixme: merge attributes?
"varying vec2 lm, lm2, lm3, lm4;\n"
"#else\n"
"varying vec2 lm;\n"
"#endif\n"
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"attribute vec2 v_lmcoord;\n"
"#ifdef LIGHTSTYLED\n"
"attribute vec2 v_lmcoord2;\n"
"attribute vec2 v_lmcoord3;\n"
"attribute vec2 v_lmcoord4;\n"
"#endif\n"
"#if defined(OFFSETMAPPING) || defined(SPECULAR)\n"
"uniform vec3 e_eyepos;\n"
"attribute vec3 v_normal;\n"
"attribute vec3 v_svector;\n"
"attribute vec3 v_tvector;\n"
"#endif\n"
"void main ()\n"
"{\n"
"#if defined(OFFSETMAPPING) || defined(SPECULAR)\n"
"vec3 eyeminusvertex = e_eyepos - v_position.xyz;\n"
"eyevector.x = dot(eyeminusvertex, v_svector.xyz);\n"
"eyevector.y = dot(eyeminusvertex, v_tvector.xyz);\n"
"eyevector.z = dot(eyeminusvertex, v_normal.xyz);\n"
"#endif\n"
"tc = v_texcoord;\n"
"lm = v_lmcoord;\n"
"#ifdef LIGHTSTYLED\n"
"lm2 = v_lmcoord2;\n"
"lm3 = v_lmcoord3;\n"
"lm4 = v_lmcoord4;\n"
"#endif\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
//samplers
"uniform sampler2D s_t0; //diffuse\n"
"uniform sampler2D s_t1; //lightmap0\n"
"#if defined(BUMP) && (defined(OFFSETMAPPING) || defined(DELUXE) || defined(SPECULAR))\n"
"uniform sampler2D s_t2; //normal.rgb+height.a\n"
"#endif\n"
"#ifdef DELUXE\n"
"uniform sampler2D s_t3; //deluxe0\n"
"#endif\n"
"#ifdef FULLBRIGHT\n"
"uniform sampler2D s_t4; //fullbright\n"
"#endif\n"
"#ifdef SPECULAR\n"
"uniform sampler2D s_t5; //specular\n"
"#endif\n"
"#ifdef LIGHTSTYLED\n"
"uniform sampler2D s_t6; //lightmap1\n"
"uniform sampler2D s_t7; //lightmap2\n"
"uniform sampler2D s_t8; //lightmap3\n"
"uniform sampler2D s_t9; //deluxe1\n"
"uniform sampler2D s_t10; //deluxe2\n"
"uniform sampler2D s_t11; //deluxe3\n"
"#endif\n"
"#ifdef LIGHTSTYLED\n"
"uniform vec4 e_lmscale[4];\n"
"#else\n"
"uniform vec4 e_lmscale;\n"
"#endif\n"
"uniform vec4 e_colourident;\n"
"#ifdef SPECULAR\n"
"uniform float cvar_gl_specular;\n"
"#endif\n"
"#ifdef OFFSETMAPPING\n"
"#include \"sys/offsetmapping.h\"\n"
"#endif\n"
"void main ()\n"
"{\n"
//adjust texture coords for offsetmapping
"#ifdef OFFSETMAPPING\n"
"vec2 tcoffsetmap = offsetmap(s_t2, tc, eyevector);\n"
"#define tc tcoffsetmap\n"
"#endif\n"
//yay, regular texture!
"gl_FragColor = texture2D(s_t0, tc);\n"
"#if defined(BUMP) && (defined(DELUXE) || defined(SPECULAR))\n"
"vec3 norm = normalize(texture2D(s_t2, tc).rgb - 0.5);\n"
"#elif defined(SPECULAR) || defined(DELUXE)\n"
"vec3 norm = vec3(0, 0, 1); //specular lighting expects this to exist.\n"
"#endif\n"
//modulate that by the lightmap(s) including deluxemap(s)
"#ifdef LIGHTSTYLED\n"
"vec3 lightmaps;\n"
"#ifdef DELUXE\n"
"lightmaps = texture2D(s_t1, lm ).rgb * e_lmscale[0].rgb * dot(norm, texture2D(s_t3, lm ).rgb);\n"
"lightmaps += texture2D(s_t6, lm2).rgb * e_lmscale[1].rgb * dot(norm, texture2D(s_t9, lm2).rgb);\n"
"lightmaps += texture2D(s_t7, lm3).rgb * e_lmscale[2].rgb * dot(norm, texture2D(s_t10, lm3).rgb);\n"
"lightmaps += texture2D(s_t8, lm4).rgb * e_lmscale[3].rgb * dot(norm, texture2D(s_t11,lm4).rgb);\n"
"#else\n"
"lightmaps = texture2D(s_t1, lm ).rgb * e_lmscale[0].rgb;\n"
"lightmaps += texture2D(s_t6, lm2).rgb * e_lmscale[1].rgb;\n"
"lightmaps += texture2D(s_t7, lm3).rgb * e_lmscale[2].rgb;\n"
"lightmaps += texture2D(s_t8, lm4).rgb * e_lmscale[3].rgb;\n"
"#endif\n"
"#else\n"
"vec3 lightmaps = (texture2D(s_t1, lm) * e_lmscale).rgb;\n"
//modulate by the bumpmap dot light
"#ifdef DELUXE\n"
"lightmaps *= dot(norm, 2.0*(texture2D(s_t3, lm).rgb-0.5));\n"
"#endif\n"
"#endif\n"
"#ifdef SPECULAR\n"
"vec4 specs = texture2D(s_t5, tc);\n"
"#ifdef DELUXE\n"
//not lightstyled...
"vec3 halfdir = normalize(normalize(eyevector) + 2.0*(texture2D(s_t3, lm).rgb-0.5)); //this norm should be the deluxemap info instead\n"
"#else\n"
"vec3 halfdir = normalize(normalize(eyevector) + vec3(0.0, 0.0, 1.0)); //this norm should be the deluxemap info instead\n"
"#endif\n"
"float spec = pow(max(dot(halfdir, norm), 0.0), 32.0 * specs.a);\n"
"spec *= cvar_gl_specular;\n"
//NOTE: rtlights tend to have a *4 scaler here to over-emphasise the effect because it looks cool.
//As not all maps will have deluxemapping, and the double-cos from the light util makes everything far too dark anyway,
//we default to something that is not garish when the light value is directly infront of every single pixel.
//we can justify this difference due to the rtlight editor etc showing the *4.
"gl_FragColor.rgb += spec * specs.rgb;\n"
"#endif\n"
//now we have our diffuse+specular terms, modulate by lightmap values.
"gl_FragColor.rgb *= lightmaps.rgb;\n"
//add on the fullbright
"#ifdef FULLBRIGHT\n"
"gl_FragColor.rgb += texture2D(s_t4, tc).rgb;\n"
"#endif\n"
//entity modifiers
"gl_FragColor = gl_FragColor * e_colourident;\n"
//and finally hide it all if we're fogged.
"#ifdef FOG\n"
"gl_FragColor = fog4(gl_FragColor);\n"
"#endif\n"
"}\n"
"#endif\n"
},
#endif
#ifdef D3D11QUAKE
{QR_DIRECT3D11, 11, "defaultwall",
"struct a2v\n"
"{\n"
"float4 pos: POSITION;\n"
"float4 tc: TEXCOORD0;\n"
"};\n"
"struct v2f\n"
"{\n"
"float4 pos: SV_POSITION;\n"
"float2 tc: TEXCOORD0;\n"
"float2 lmtc: TEXCOORD1;\n"
"};\n"
"#include <ftedefs.h>\n"
"#ifdef VERTEX_SHADER\n"
"v2f main (a2v inp)\n"
"{\n"
"v2f outp;\n"
"outp.pos = mul(m_model, inp.pos);\n"
"outp.pos = mul(m_view, outp.pos);\n"
"outp.pos = mul(m_projection, outp.pos);\n"
"outp.tc = inp.tc.xy;\n"
"outp.lmtc = inp.tc.zw;\n"
"return outp;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"Texture2D shaderTexture[2];\n"
"SamplerState SampleType[2];\n"
"float4 main (v2f inp) : SV_TARGET\n"
"{\n"
"float4 tex = shaderTexture[0].Sample(SampleType[0], inp.tc);\n"
"float4 lm = shaderTexture[1].Sample(SampleType[1], inp.lmtc);\n"
"#ifdef MASK\n"
"#ifndef MASKOP\n"
"#define MASKOP >= //drawn if (alpha OP ref) is true.\n"
"#endif\n"
//support for alpha masking
"if (!(tex.a MASKOP MASK))\n"
"discard;\n"
"#endif\n"
"return tex * lm.bgra;\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "defaultwarp",
"!!cvarf r_wateralpha\n"
"!!permu FOG\n"
//this is the shader that's responsible for drawing default q1 turbulant water surfaces
//this is expected to be moderately fast.
"#include \"sys/fog.h\"\n"
"varying vec2 tc;\n"
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"void main ()\n"
"{\n"
"tc = v_texcoord.st;\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D s_t0;\n"
"uniform float e_time;\n"
"#ifndef ALPHA\n"
"uniform float cvar_r_wateralpha;\n"
"#define USEALPHA cvar_r_wateralpha\n"
"#else\n"
"#define USEALPHA float(ALPHA)\n"
"#endif\n"
"void main ()\n"
"{\n"
"vec2 ntc;\n"
"ntc.s = tc.s + sin(tc.t+e_time)*0.125;\n"
"ntc.t = tc.t + sin(tc.s+e_time)*0.125;\n"
"vec3 ts = vec3(texture2D(s_t0, ntc));\n"
"gl_FragColor = fog4(vec4(ts, USEALPHA));\n"
"}\n"
"#endif\n"
},
#endif
#ifdef D3D9QUAKE
{QR_DIRECT3D9, 9, "defaultwarp",
"!!cvarf r_wateralpha\n"
"struct a2v {\n"
"float4 pos: POSITION;\n"
"float2 tc: TEXCOORD0;\n"
"};\n"
"struct v2f {\n"
"#ifndef FRAGMENT_SHADER\n"
"float4 pos: POSITION;\n"
"#endif\n"
"float2 tc: TEXCOORD0;\n"
"};\n"
"#ifdef VERTEX_SHADER\n"
"float4x4 m_modelviewprojection;\n"
"v2f main (a2v inp)\n"
"{\n"
"v2f outp;\n"
"outp.pos = mul(m_modelviewprojection, inp.pos);\n"
"outp.tc = inp.tc;\n"
"return outp;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"float cvar_r_wateralpha;\n"
"float e_time;\n"
"sampler s_t0;\n"
"float4 main (v2f inp) : COLOR0\n"
"{\n"
"float2 ntc;\n"
"ntc.x = inp.tc.x + sin(inp.tc.y+e_time)*0.125;\n"
"ntc.y = inp.tc.y + sin(inp.tc.x+e_time)*0.125;\n"
"float3 ts = tex2D(s_t0, ntc).xyz;\n"
"return float4(ts, cvar_r_wateralpha);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef D3D11QUAKE
{QR_DIRECT3D11, 11, "defaultwarp",
"!!cvarf r_wateralpha\n"
"struct a2v\n"
"{\n"
"float4 pos: POSITION;\n"
"float2 tc: TEXCOORD0;\n"
"};\n"
"struct v2f\n"
"{\n"
"float4 pos: SV_POSITION;\n"
"float2 tc: TEXCOORD0;\n"
"};\n"
"#include <ftedefs.h>\n"
"#ifdef VERTEX_SHADER\n"
"v2f main (a2v inp)\n"
"{\n"
"v2f outp;\n"
"outp.pos = mul(m_model, inp.pos);\n"
"outp.pos = mul(m_view, outp.pos);\n"
"outp.pos = mul(m_projection, outp.pos);\n"
"outp.tc = inp.tc;\n"
"return outp;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
// float cvar_r_wateralpha;
// float e_time;
// sampler s_t0;
"Texture2D shaderTexture;\n"
"SamplerState SampleType;\n"
"float4 main (v2f inp) : SV_TARGET\n"
"{\n"
"float2 ntc;\n"
"ntc.x = inp.tc.x + sin(inp.tc.y+e_time)*0.125;\n"
"ntc.y = inp.tc.y + sin(inp.tc.x+e_time)*0.125;\n"
"return shaderTexture.Sample(SampleType, ntc);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "defaultgammacb",
//this shader is applies gamma/contrast/brightness to the source image, and dumps it out.
"varying vec2 tc;\n"
"varying vec4 vc;\n"
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"attribute vec4 v_colour;\n"
"void main ()\n"
"{\n"
"tc = v_texcoord;\n"
"vc = v_colour;\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D s_t0;\n"
"void main ()\n"
"{\n"
"gl_FragColor = pow(texture2D(s_t0, tc) * vc.g, vec4(vc.r)) + vc.b;\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "drawflat_wall",
"!!cvarv r_floorcolor\n"
"!!cvarv r_wallcolor\n"
"!!permu FOG\n"
//this is for the '286' preset walls, and just draws lightmaps coloured based upon surface normals.
"#include \"sys/fog.h\"\n"
"varying vec4 col;\n"
"#ifdef VERTEX_SHADER\n"
"attribute vec3 v_normal;\n"
"attribute vec2 v_lmcoord;\n"
"varying vec2 lm;\n"
"uniform vec3 cvar_r_wallcolor;\n"
"uniform vec3 cvar_r_floorcolor;\n"
"uniform vec4 e_lmscale;\n"
"void main ()\n"
"{\n"
"col = vec4(e_lmscale.rgb/255.0 * ((v_normal.z < 0.73)?cvar_r_wallcolor:cvar_r_floorcolor), e_lmscale.a);\n"
"lm = v_lmcoord;\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D s_t0;\n"
"varying vec2 lm;\n"
"void main ()\n"
"{\n"
"gl_FragColor = fog4(col * texture2D(s_t0, lm));\n"
"}\n"
"#endif\n"
},
#endif
#ifdef D3D11QUAKE
{QR_DIRECT3D11, 11, "drawflat_wall",
"struct a2v\n"
"{\n"
"float4 pos: POSITION;\n"
"float4 tc: TEXCOORD0;\n"
"float3 norm: NORMAL;\n"
"};\n"
"struct v2f\n"
"{\n"
"float4 pos: SV_POSITION;\n"
"float2 tc: TEXCOORD0;\n"
"float2 lmtc: TEXCOORD1;\n"
"float4 col: TEXCOORD2;\n"
"};\n"
"#include <ftedefs.h>\n"
"#ifdef VERTEX_SHADER\n"
"v2f main (a2v inp)\n"
"{\n"
"v2f outp;\n"
"outp.pos = mul(m_model, inp.pos);\n"
"outp.pos = mul(m_view, outp.pos);\n"
"outp.pos = mul(m_projection, outp.pos);\n"
"outp.tc = inp.tc.xy;\n"
"outp.lmtc = inp.tc.zw;\n"
"outp.col = ((inp.norm.z<0.73)?float4(0.5, 0.5, 0.5, 1):float4(0.25, 0.25, 0.5, 1));\n"
"return outp;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"Texture2D shaderTexture;\n"
"SamplerState SampleType;\n"
"float4 main (v2f inp) : SV_TARGET\n"
"{\n"
"return inp.col * shaderTexture.Sample(SampleType, inp.lmtc);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "lpp_depthnorm",
"!!permu BUMP\n"
"!!permu SKELETAL\n"
//light pre-pass rendering (defered lighting)
//this is the initial pass, that draws the surface normals and depth to the initial colour buffer
"varying vec3 norm, tang, bitang;\n"
"#if defined(BUMP)\n"
"varying vec2 tc;\n"
"#endif\n"
"#ifdef VERTEX_SHADER\n"
"#include \"sys/skeletal.h\"\n"
"attribute vec2 v_texcoord;\n"
"void main()\n"
"{\n"
"#if defined(BUMP)\n"
"gl_Position = skeletaltransform_nst(norm, tang, bitang);\n"
"tc = v_texcoord;\n"
"#else\n"
"gl_Position = skeletaltransform_n(norm);\n"
"#endif\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"#if defined(BUMP)\n"
"uniform sampler2D s_t0;\n"
"#endif\n"
"void main()\n"
"{\n"
"vec3 onorm;\n"
"#if defined(BUMP)\n"
"vec3 bm = 2.0*texture2D(s_t0, tc).xyz - 1.0;\n"
"onorm = normalize(bm.x * tang + bm.y * bitang + bm.z * norm);\n"
"#else\n"
"onorm = norm;\n"
"#endif\n"
"gl_FragColor = vec4(onorm.xyz, gl_FragCoord.z / gl_FragCoord.w);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "lpp_light",
//this shader is a light shader. ideally drawn with a quad covering the entire region
//the output is contribution from this light (which will be additively blended)
//you can blame Electro for much of the maths in here.
//fixme: no fog
"varying vec4 tf;\n"
"#ifdef VERTEX_SHADER\n"
"void main()\n"
"{\n"
"tf = ftetransform();\n"
"gl_Position = tf;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D s_t0;\n"
"uniform vec3 l_lightposition;\n"
"uniform mat4 m_invviewprojection;\n"
"uniform vec3 l_lightcolour;\n"
"uniform float l_lightradius;\n"
"vec3 calcLightWorldPos(vec2 screenPos, float depth)\n"
"{\n"
"vec4 pos;\n"
"pos.x = screenPos.x;\n"
"pos.y = screenPos.y;\n"
"pos.z = depth;\n"
"pos.w = 1.0;\n"
"pos = m_invviewprojection * pos;\n"
"return pos.xyz / pos.w;\n"
"}\n"
"void main ()\n"
"{\n"
"vec3 lightColour = l_lightcolour.rgb;\n"
"float lightIntensity = 1.0;\n"
"float lightAttenuation = l_lightradius; // fixme: just use the light radius for now, use better near/far att math separately once working\n"
"float radiusFar = l_lightradius;\n"
"float radiusNear = l_lightradius*0.5;\n"
"vec2 fc;\n"
"fc = tf.xy / tf.w;\n"
"vec4 data = texture2D(s_t0, (1.0 + fc) / 2.0);\n"
"float depth = data.a;\n"
"vec3 norm = data.xyz;\n"
/* calc where the wall that generated this sample came from */
"vec3 worldPos = calcLightWorldPos(fc, depth);\n"
/*calc diffuse lighting term*/
"vec3 lightDir = l_lightposition - worldPos;\n"
"float zdiff = 1.0 - clamp(length(lightDir) / lightAttenuation, 0.0, 1.0);\n"
"float atten = (radiusFar * zdiff) / (radiusFar - radiusNear);\n"
"atten = pow(atten, 2.0);\n"
"lightDir = normalize(lightDir);\n"
"float nDotL = dot(norm, lightDir) * atten;\n"
"float lightDiffuse = max(0.0, nDotL);\n"
"gl_FragColor = vec4(lightDiffuse * (lightColour * lightIntensity), 1.0);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "lpp_wall",
//the final defered lighting pass.
//the lighting values were written to some render target, which is fed into this shader, and now we draw all the wall textures with it.
"varying vec2 tc, lm;\n"
"varying vec4 tf;\n"
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"attribute vec2 v_lmcoord;\n"
"void main ()\n"
"{\n"
"tc = v_texcoord;\n"
"lm = v_lmcoord;\n"
"gl_Position = tf = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D s_t0;\n"
"uniform sampler2D s_t1;\n"
"uniform sampler2D s_t2;\n"
"uniform vec4 e_lmscale;\n"
"void main ()\n"
"{\n"
"vec2 nst;\n"
"nst = tf.xy / tf.w;\n"
"nst = (1.0 + nst) / 2.0;\n"
"vec4 l = texture2D(s_t0, nst)*5.0;\n"
"vec4 c = texture2D(s_t1, tc);\n"
"vec3 lmsamp = texture2D(s_t2, lm).rgb*e_lmscale;\n"
"vec3 diff = l.rgb;\n"
"vec3 chrom = diff / (0.001 + dot(diff, vec3(0.3, 0.59, 0.11)));\n"
"vec3 spec = chrom * l.a;\n"
"gl_FragColor = vec4((diff + lmsamp) * c.xyz, 1.0);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "postproc_fisheye",
"!!cvarf ffov\n"
//fisheye view rendering, for silly fovs that are still playable.
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"varying vec2 texcoord;\n"
"void main()\n"
"{\n"
"texcoord = v_texcoord.xy;\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform samplerCube s_t0;\n"
"varying vec2 texcoord;\n"
"uniform float cvar_ffov;\n"
"void main()\n"
"{\n"
"vec3 tc; \n"
"vec2 d; \n"
"vec2 ang; \n"
"d = texcoord; \n"
"ang.x = sqrt(d.x*d.x+d.y*d.y)*radians(cvar_ffov); \n"
"ang.y = -atan(d.y, d.x); \n"
"tc.x = sin(ang.x) * cos(ang.y); \n"
"tc.y = sin(ang.x) * sin(ang.y); \n"
"tc.z = cos(ang.x); \n"
"gl_FragColor = textureCube(s_t0, tc);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "postproc_panorama",
"!!cvarf ffov\n"
//panoramic view rendering, for promo map shots or whatever.
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"varying vec2 texcoord;\n"
"void main()\n"
"{\n"
"texcoord = v_texcoord.xy;\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform samplerCube s_t0;\n"
"varying vec2 texcoord;\n"
"uniform float cvar_ffov;\n"
"void main()\n"
"{\n"
"vec3 tc; \n"
"float ang; \n"
"ang = texcoord.x*-radians(cvar_ffov); \n"
"tc.x = sin(ang); \n"
"tc.y = -texcoord.y; \n"
"tc.z = cos(ang); \n"
"gl_FragColor = textureCube(s_t0, tc);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "rtlight",
"!!permu BUMP\n"
"!!permu FRAMEBLEND\n"
"!!permu SKELETAL\n"
"!!permu UPPERLOWER\n"
"!!permu FOG\n"
"!!cvarf r_glsl_offsetmapping_scale\n"
"!!cvardf r_glsl_pcf\n"
//this is the main shader responsible for realtime dlights.
//texture units:
//s0=diffuse, s1=normal, s2=specular, s3=shadowmap
//custom modifiers:
//PCF(shadowmap)
//CUBEPROJ(projected cubemap)
//SPOT(projected circle
//CUBESHADOW
"#ifndef r_glsl_pcf\n"
"#error r_glsl_pcf wasn't defined\n"
"#endif\n"
"#if r_glsl_pcf < 1\n"
"#undef r_glsl_pcf\n"
"#define r_glsl_pcf 9\n"
"#endif\n"
"#if 0 && defined(GL_ARB_texture_gather) && defined(PCF) \n"
"#extension GL_ARB_texture_gather : enable\n"
"#endif\n"
"#ifdef UPPERLOWER\n"
"#define UPPER\n"
"#define LOWER\n"
"#endif\n"
"varying vec2 tcbase;\n"
"varying vec3 lightvector;\n"
"#if defined(SPECULAR) || defined(OFFSETMAPPING)\n"
"varying vec3 eyevector;\n"
"#endif\n"
"#if defined(PCF) || defined(CUBE) || defined(SPOT)\n"
"varying vec4 vtexprojcoord;\n"
"uniform mat4 l_cubematrix;\n"
"#endif\n"
"#ifdef VERTEX_SHADER\n"
"#include \"sys/skeletal.h\"\n"
"uniform vec3 l_lightposition;\n"
"attribute vec2 v_texcoord;\n"
"#if defined(SPECULAR) || defined(OFFSETMAPPING)\n"
"uniform vec3 e_eyepos;\n"
"#endif\n"
"void main ()\n"
"{\n"
"vec3 n, s, t, w;\n"
"gl_Position = skeletaltransform_wnst(w,n,s,t);\n"
"tcbase = v_texcoord; //pass the texture coords straight through\n"
"vec3 lightminusvertex = l_lightposition - w.xyz;\n"
"lightvector.x = dot(lightminusvertex, s.xyz);\n"
"lightvector.y = dot(lightminusvertex, t.xyz);\n"
"lightvector.z = dot(lightminusvertex, n.xyz);\n"
"#if defined(SPECULAR)||defined(OFFSETMAPPING)\n"
"vec3 eyeminusvertex = e_eyepos - w.xyz;\n"
"eyevector.x = dot(eyeminusvertex, s.xyz);\n"
"eyevector.y = dot(eyeminusvertex, t.xyz);\n"
"eyevector.z = dot(eyeminusvertex, n.xyz);\n"
"#endif\n"
"#if defined(PCF) || defined(SPOT) || defined(CUBE)\n"
//for texture projections/shadowmapping on dlights
"vtexprojcoord = (l_cubematrix*vec4(w.xyz, 1.0));\n"
"#endif\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"#include \"sys/fog.h\"\n"
"uniform sampler2D s_t0; //diffuse\n"
"#if defined(BUMP) || defined(SPECULAR) || defined(OFFSETMAPPING)\n"
"uniform sampler2D s_t1; //normalmap\n"
"#endif\n"
"#ifdef SPECULAR\n"
"uniform sampler2D s_t2; //specular\n"
"#endif\n"
"#ifdef CUBE\n"
"uniform samplerCube s_t3; //projected cubemap\n"
"#endif\n"
"#ifdef PCF\n"
"#ifdef CUBESHADOW\n"
"uniform samplerCubeShadow s_t4; //shadowmap\n"
"#else\n"
"#if 0//def GL_ARB_texture_gather\n"
"uniform sampler2D s_t4;\n"
"#else\n"
"uniform sampler2DShadow s_t4;\n"
"#endif\n"
"#endif\n"
"#endif\n"
"#ifdef LOWER\n"
"uniform sampler2D s_t5; //pants colours\n"
"uniform vec3 e_lowercolour;\n"
"#endif\n"
"#ifdef UPPER\n"
"uniform sampler2D s_t6; //shirt colours\n"
"uniform vec3 e_uppercolour;\n"
"#endif\n"
"uniform float l_lightradius;\n"
"uniform vec3 l_lightcolour;\n"
"uniform vec3 l_lightcolourscale;\n"
"#ifdef PCF\n"
"uniform vec4 l_shadowmapproj; //light projection matrix info\n"
"uniform vec2 l_shadowmapscale; //xy are the texture scale, z is 1, w is the scale.\n"
"vec3 ShadowmapCoord(void)\n"
"{\n"
"#ifdef SPOT\n"
//bias it. don't bother figuring out which side or anything, its not needed
//l_projmatrix contains the light's projection matrix so no other magic needed
"vtexprojcoord.z -= 0.015;\n"
"return (vtexprojcoord.xyz/vtexprojcoord.w + vec3(1.0, 1.0, 1.0)) * vec3(0.5, 0.5, 0.5);\n"
//#elif defined(CUBESHADOW)
// vec3 shadowcoord = vshadowcoord.xyz / vshadowcoord.w;
// #define dosamp(x,y) shadowCube(s_t4, shadowcoord + vec2(x,y)*texscale.xy).r
"#else\n"
//figure out which axis to use
//texture is arranged thusly:
//forward left up
//back right down
"vec3 dir = abs(vtexprojcoord.xyz);\n"
//assume z is the major axis (ie: forward from the light)
"vec3 t = vtexprojcoord.xyz;\n"
"float ma = dir.z;\n"
"vec3 axis = vec3(0.5/3.0, 0.5/2.0, 0.5);\n"
"if (dir.x > ma)\n"
"{\n"
"ma = dir.x;\n"
"t = vtexprojcoord.zyx;\n"
"axis.x = 0.5;\n"
"}\n"
"if (dir.y > ma)\n"
"{\n"
"ma = dir.y;\n"
"t = vtexprojcoord.xzy;\n"
"axis.x = 2.5/3.0;\n"
"}\n"
//if the axis is negative, flip it.
"if (t.z > 0.0)\n"
"{\n"
"axis.y = 1.5/2.0;\n"
"t.z = -t.z;\n"
"}\n"
//we also need to pass the result through the light's projection matrix too
//the 'matrix' we need only contains 5 actual values. and one of them is a -1. So we might as well just use a vec4.
//note: the projection matrix also includes scalers to pinch the image inwards to avoid sampling over borders, as well as to cope with non-square source image
//the resulting z is prescaled to result in a value between -0.5 and 0.5.
//also make sure we're in the right quadrant type thing
"return axis + ((l_shadowmapproj.xyz*t.xyz + vec3(0.0, 0.0, l_shadowmapproj.w)) / -t.z);\n"
"#endif\n"
"}\n"
"float ShadowmapFilter(void)\n"
"{\n"
"vec3 shadowcoord = ShadowmapCoord();\n"
"#if 0//def GL_ARB_texture_gather\n"
"vec2 ipart, fpart;\n"
"#define dosamp(x,y) textureGatherOffset(s_t4, ipart.xy, vec2(x,y)))\n"
"vec4 tl = step(shadowcoord.z, dosamp(-1.0, -1.0));\n"
"vec4 bl = step(shadowcoord.z, dosamp(-1.0, 1.0));\n"
"vec4 tr = step(shadowcoord.z, dosamp(1.0, -1.0));\n"
"vec4 br = step(shadowcoord.z, dosamp(1.0, 1.0));\n"
//we now have 4*4 results, woo
//we can just average them for 1/16th precision, but that's still limited graduations
//the middle four pixels are 'full strength', but we interpolate the sides to effectively give 3*3
"vec4 col = vec4(tl.ba, tr.ba) + vec4(bl.rg, br.rg) + //middle two rows are full strength\n"
"mix(vec4(tl.rg, tr.rg), vec4(bl.ba, br.ba), fpart.y); //top+bottom rows\n"
"return dot(mix(col.rgb, col.agb, fpart.x), vec3(1.0/9.0)); //blend r+a, gb are mixed because its pretty much free and gives a nicer dot instruction instead of lots of adds.\n"
"#else\n"
"#define dosamp(x,y) shadow2D(s_t4, shadowcoord.xyz + (vec3(x,y,0.0)*l_shadowmapscale.xyx)).r\n"
"float s = 0.0;\n"
"#if r_glsl_pcf >= 1 && r_glsl_pcf < 5\n"
"s += dosamp(0.0, 0.0);\n"
"return s;\n"
"#elif r_glsl_pcf >= 5 && r_glsl_pcf < 9\n"
"s += dosamp(-1.0, 0.0);\n"
"s += dosamp(0.0, -1.0);\n"
"s += dosamp(0.0, 0.0);\n"
"s += dosamp(0.0, 1.0);\n"
"s += dosamp(1.0, 0.0);\n"
"return s/5.0;\n"
"#else\n"
"s += dosamp(-1.0, -1.0);\n"
"s += dosamp(-1.0, 0.0);\n"
"s += dosamp(-1.0, 1.0);\n"
"s += dosamp(0.0, -1.0);\n"
"s += dosamp(0.0, 0.0);\n"
"s += dosamp(0.0, 1.0);\n"
"s += dosamp(1.0, -1.0);\n"
"s += dosamp(1.0, 0.0);\n"
"s += dosamp(1.0, 1.0);\n"
"return s/9.0;\n"
"#endif\n"
"#endif\n"
"}\n"
"#endif\n"
"#ifdef OFFSETMAPPING\n"
"#include \"sys/offsetmapping.h\"\n"
"#endif\n"
"void main ()\n"
"{\n"
//read raw texture samples (offsetmapping munges the tex coords first)
"#ifdef OFFSETMAPPING\n"
"vec2 tcoffsetmap = offsetmap(s_t1, tcbase, eyevector);\n"
"#define tcbase tcoffsetmap\n"
"#endif\n"
"vec3 bases = vec3(texture2D(s_t0, tcbase));\n"
"#ifdef UPPER\n"
"vec4 uc = texture2D(s_t6, tcbase);\n"
"bases.rgb += uc.rgb*e_uppercolour*uc.a;\n"
"#endif\n"
"#ifdef LOWER\n"
"vec4 lc = texture2D(s_t5, tcbase);\n"
"bases.rgb += lc.rgb*e_lowercolour*lc.a;\n"
"#endif\n"
"#if defined(BUMP) || defined(SPECULAR)\n"
"vec3 bumps = normalize(vec3(texture2D(s_t1, tcbase)) - 0.5);\n"
"#endif\n"
"#ifdef SPECULAR\n"
"vec4 specs = texture2D(s_t2, tcbase);\n"
"#endif\n"
"vec3 nl = normalize(lightvector);\n"
"float colorscale = max(1.0 - (dot(lightvector, lightvector)/(l_lightradius*l_lightradius)), 0.0);\n"
"vec3 diff;\n"
"#ifdef BUMP\n"
"diff = bases * (l_lightcolourscale.x + l_lightcolourscale.y * max(dot(bumps, nl), 0.0));\n"
"#else\n"
//we still do bumpmapping even without bumps to ensure colours are always sane. light.exe does it too.
"diff = bases * (l_lightcolourscale.x + l_lightcolourscale.y * max(dot(vec3(0.0, 0.0, 1.0), nl), 0.0));\n"
"#endif\n"
"#ifdef SPECULAR\n"
"vec3 halfdir = normalize(normalize(eyevector) + nl);\n"
"float spec = pow(max(dot(halfdir, bumps), 0.0), 32.0 * specs.a);\n"
"diff += l_lightcolourscale.z * spec * specs.rgb;\n"
"#endif\n"
"#ifdef CUBE\n"
/*filter the colour by the cubemap projection*/
"diff *= textureCube(s_t3, vtexprojcoord.xyz).rgb;\n"
"#endif\n"
"#if defined(SPOT)\n"
/*filter the colour by the spotlight. discard anything behind the light so we don't get a mirror image*/
"if (vtexprojcoord.w < 0.0) discard;\n"
"vec2 spot = ((vtexprojcoord.st)/vtexprojcoord.w);colorscale*=1.0-(dot(spot,spot));\n"
"#endif\n"
"#ifdef PCF\n"
/*filter the light by the shadowmap. logically a boolean, but we allow fractions for softer shadows*/
//diff.rgb = (vtexprojcoord.xyz/vtexprojcoord.w) * 0.5 + 0.5;
"colorscale *= ShadowmapFilter();\n"
// diff = ShadowmapCoord();
"#endif\n"
"#if defined(PROJECTION)\n"
/*2d projection, not used*/
// diff *= texture2d(s_t3, shadowcoord);
"#endif\n"
"gl_FragColor.rgb = fog3additive(diff*colorscale*l_lightcolour);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef D3D9QUAKE
{QR_DIRECT3D9, 9, "rtlight",
"!!permu BUMP\n"
"!!permu SPECULAR\n"
"!!permu OFFSETMAPPING\n"
"!!permu SKELETAL\n"
"!!permu FOG\n"
// texture units:
// s0=diffuse, s1=normal, s2=specular, s3=shadowmap
// custom modifiers:
// PCF(shadowmap)
// CUBE(projected cubemap)
"struct a2v\n"
"{\n"
"float4 pos: POSITION;\n"
"float3 tc: TEXCOORD0;\n"
"float3 n: NORMAL0;\n"
"float3 s: TANGENT0;\n"
"float3 t: BINORMAL0;\n"
"};\n"
"struct v2f\n"
"{\n"
"#ifndef FRAGMENT_SHADER\n"
"float4 pos: POSITION;\n"
"#endif\n"
"float3 tc: TEXCOORD0;\n"
"float3 lpos: TEXCOORD1;\n"
"};\n"
"#ifdef VERTEX_SHADER\n"
"float4x4 m_modelviewprojection;\n"
"float3 l_lightposition;\n"
"v2f main (a2v inp)\n"
"{\n"
"v2f outp;\n"
"outp.pos = mul(m_modelviewprojection, inp.pos);\n"
"outp.tc = inp.tc;\n"
"float3 lightminusvertex = l_lightposition - inp.pos.xyz;\n"
"outp.lpos.x = dot(lightminusvertex, inp.s.xyz);\n"
"outp.lpos.y = dot(lightminusvertex, inp.t.xyz);\n"
"outp.lpos.z = dot(lightminusvertex, inp.n.xyz);\n"
"return outp;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"sampler s_t0;\n"
"sampler s_t1;\n"
"float l_lightradius;\n"
"float3 l_lightcolour;\n"
"float4 main (v2f inp) : COLOR0\n"
"{\n"
"float3 col = l_lightcolour;\n"
"col *= max(1.0 - dot(inp.lpos, inp.lpos)/(l_lightradius*l_lightradius), 0.0);\n"
"float3 diff = tex2D(s_t0, inp.tc);\n"
"return float4(diff * col, 1);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef D3D11QUAKE
{QR_DIRECT3D11, 11, "rtlight",
"!!permu BUMP\n"
"!!permu FRAMEBLEND\n"
"!!permu SKELETAL\n"
"!!permu UPPERLOWER\n"
"!!permu FOG\n"
"!!cvarf r_glsl_offsetmapping_scale\n"
"!!cvardf r_glsl_pcf\n"
//this is the main shader responsible for realtime dlights.
//texture units:
//s0=diffuse, s1=normal, s2=specular, s3=shadowmap
//custom modifiers:
//PCF(shadowmap)
//CUBEPROJ(projected cubemap)
//SPOT(projected circle
//CUBESHADOW
"#undef CUBE //engine cannot load cubemaps properly with d3d yet.\n"
"#ifndef r_glsl_pcf\n"
"#error r_glsl_pcf wasn't defined\n"
"#endif\n"
"#if r_glsl_pcf < 1\n"
"#undef r_glsl_pcf\n"
"#define r_glsl_pcf 9\n"
"#endif\n"
"#ifdef UPPERLOWER\n"
"#define UPPER\n"
"#define LOWER\n"
"#endif\n"
"struct a2v\n"
"{\n"
"float4 pos: POSITION;\n"
"float4 tc: TEXCOORD0;\n"
"float3 n: NORMAL;\n"
"float3 s: TANGENT;\n"
"float3 t: BINORMAL;\n"
"};\n"
"struct v2f\n"
"{\n"
"float4 pos: SV_POSITION;\n"
"float2 tc: TEXCOORD0;\n"
"float3 lightvector: TEXCOORD1;\n"
"float3 eyevector: TEXCOORD2;\n"
"float3 vtexprojcoord: TEXCOORD3;\n"
"};\n"
"#include <ftedefs.h>\n"
"#ifdef VERTEX_SHADER\n"
"v2f main (a2v inp)\n"
"{\n"
"v2f outp;\n"
"float4 wpos;\n"
"wpos = mul(m_model, inp.pos);\n"
"outp.pos = mul(m_view, wpos);\n"
"outp.pos = mul(m_projection, outp.pos);\n"
"outp.tc = inp.tc.xy;\n"
"float3 lightminusvertex = l_lightposition - wpos.xyz;\n"
"outp.lightvector.x = -dot(lightminusvertex, inp.s.xyz);\n"
"outp.lightvector.y = dot(lightminusvertex, inp.t.xyz);\n"
"outp.lightvector.z = dot(lightminusvertex, inp.n.xyz);\n"
"float3 eyeminusvertex = e_eyepos - wpos.xyz;\n"
"outp.eyevector.x = -dot(eyeminusvertex, inp.s.xyz);\n"
"outp.eyevector.y = dot(eyeminusvertex, inp.t.xyz);\n"
"outp.eyevector.z = dot(eyeminusvertex, inp.n.xyz);\n"
"outp.vtexprojcoord = mul(l_cubematrix, wpos).xyz;\n"
"return outp;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"Texture2D tx_base : register(t0);\n"
"Texture2D tx_bump : register(t1);\n"
"Texture2D tx_spec : register(t2);\n"
"TextureCube tx_cube : register(t3);\n"
"Texture2D tx_smap : register(t4);\n"
"Texture2D tx_lower : register(t5);\n"
"Texture2D tx_upper : register(t6);\n"
"SamplerState ss_base : register(s0);\n"
"SamplerState ss_bump : register(s1);\n"
"SamplerState ss_spec : register(s2);\n"
"SamplerState ss_cube : register(s3);\n"
"SamplerComparisonState ss_smap : register(s4);\n"
"SamplerState ss_lower : register(s5);\n"
"SamplerState ss_upper : register(s6);\n"
"#ifdef PCF\n"
"float3 ShadowmapCoord(float3 vtexprojcoord)\n"
"{\n"
"#ifdef SPOT\n"
//bias it. don't bother figuring out which side or anything, its not needed
//l_projmatrix contains the light's projection matrix so no other magic needed
"vtexprojcoord.z -= 0.015;\n"
"return (vtexprojcoord.xyz + float3(1.0, 1.0, 1.0)) * float3(0.5, 0.5, 0.5);\n"
//#elif defined(CUBESHADOW)
// vec3 shadowcoord = vshadowcoord.xyz / vshadowcoord.w;
// #define dosamp(x,y) shadowCube(s_t4, shadowcoord + vec2(x,y)*texscale.xy).r
"#else\n"
//figure out which axis to use
//texture is arranged thusly:
//forward left up
//back right down
"float3 dir = abs(vtexprojcoord.xyz);\n"
//assume z is the major axis (ie: forward from the light)
"float3 t = vtexprojcoord.xyz;\n"
"float ma = dir.z;\n"
"float3 axis = float3(0.5/3.0, 0.5/2.0, 0.5);\n"
"if (dir.x > ma)\n"
"{\n"
"ma = dir.x;\n"
"t = vtexprojcoord.zyx;\n"
"axis.x = 0.5;\n"
"}\n"
"if (dir.y > ma)\n"
"{\n"
"ma = dir.y;\n"
"t = vtexprojcoord.xzy;\n"
"axis.x = 2.5/3.0;\n"
"}\n"
//if the axis is negative, flip it.
"if (t.z > 0.0)\n"
"{\n"
"axis.y = 1.5/2.0;\n"
"t.z = -t.z;\n"
"}\n"
//we also need to pass the result through the light's projection matrix too
//the 'matrix' we need only contains 5 actual values. and one of them is a -1. So we might as well just use a vec4.
//note: the projection matrix also includes scalers to pinch the image inwards to avoid sampling over borders, as well as to cope with non-square source image
//the resulting z is prescaled to result in a value between -0.5 and 0.5.
//also make sure we're in the right quadrant type thing
"return axis + ((l_shadowmapproj.xyz*t.xyz + float3(0.0, 0.0, l_shadowmapproj.w)) / -t.z);\n"
"#endif\n"
"}\n"
"float ShadowmapFilter(float3 vtexprojcoord)\n"
"{\n"
"float3 shadowcoord = ShadowmapCoord(vtexprojcoord);\n"
// #define dosamp(x,y) shadow2D(s_t4, shadowcoord.xyz + (vec3(x,y,0.0)*l_shadowmapscale.xyx)).r
// #define dosamp(x,y) (tx_smap.Sample(ss_smap, shadowcoord.xy + (float2(x,y)*l_shadowmapscale.xy)).r < shadowcoord.z)
"#define dosamp(x,y) (tx_smap.SampleCmpLevelZero(ss_smap, shadowcoord.xy+(float2(x,y)*l_shadowmapscale.xy), shadowcoord.z))\n"
"float s = 0.0;\n"
"#if r_glsl_pcf >= 1 && r_glsl_pcf < 5\n"
"s += dosamp(0.0, 0.0);\n"
"return s;\n"
"#elif r_glsl_pcf >= 5 && r_glsl_pcf < 9\n"
"s += dosamp(-1.0, 0.0);\n"
"s += dosamp(0.0, -1.0);\n"
"s += dosamp(0.0, 0.0);\n"
"s += dosamp(0.0, 1.0);\n"
"s += dosamp(1.0, 0.0);\n"
"return s/5.0;\n"
"#else\n"
"s += dosamp(-1.0, -1.0);\n"
"s += dosamp(-1.0, 0.0);\n"
"s += dosamp(-1.0, 1.0);\n"
"s += dosamp(0.0, -1.0);\n"
"s += dosamp(0.0, 0.0);\n"
"s += dosamp(0.0, 1.0);\n"
"s += dosamp(1.0, -1.0);\n"
"s += dosamp(1.0, 0.0);\n"
"s += dosamp(1.0, 1.0);\n"
"return s/9.0;\n"
"#endif\n"
"}\n"
"#endif\n"
"float4 main (v2f inp) : SV_TARGET\n"
"{\n"
"float2 tc = inp.tc; //TODO: offsetmapping.\n"
"float4 base = tx_base.Sample(ss_base, tc);\n"
"#ifdef BUMP\n"
"float4 bump = tx_bump.Sample(ss_bump, tc);\n"
"bump.rgb = normalize(bump.rgb - 0.5);\n"
"#else\n"
"float4 bump = float4(0, 0, 1, 0);\n"
"#endif\n"
"float4 spec = tx_spec.Sample(ss_spec, tc);\n"
"#ifdef CUBE\n"
"float4 cubemap = tx_cube.Sample(ss_cube, inp.vtexprojcoord);\n"
"#endif\n"
"#ifdef LOWER\n"
"float4 lower = tx_lower.Sample(ss_lower, tc);\n"
"base += lower;\n"
"#endif\n"
"#ifdef UPPER\n"
"float4 upper = tx_upper.Sample(ss_upper, tc);\n"
"base += upper;\n"
"#endif\n"
"float lightscale = max(1.0 - (dot(inp.lightvector,inp.lightvector)/(l_lightradius*l_lightradius)), 0.0);\n"
"float3 nl = normalize(inp.lightvector);\n"
"float bumpscale = max(dot(bump.xyz, nl), 0.0);\n"
"float3 halfdir = normalize(normalize(inp.eyevector) + nl);\n"
"float specscale = pow(max(dot(halfdir, bump.rgb), 0.0), 32.0 * spec.a);\n"
"float4 result;\n"
"result.a = base.a;\n"
"result.rgb = base.rgb * (l_lightcolourscale.x + l_lightcolourscale.y * bumpscale); //amient light + diffuse\n"
"result.rgb += spec.rgb * l_lightcolourscale.z * specscale; //specular\n"
"result.rgb *= lightscale * l_colour; //fade light by distance and light colour.\n"
"#ifdef CUBE\n"
"result.rgb *= cubemap.rgb; //fade by cubemap\n"
"#endif\n"
"#ifdef PCF\n"
"result.rgb *= ShadowmapFilter(inp.vtexprojcoord);\n"
"#endif\n"
//TODO: fog
"return result;\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "underwaterwarp",
"!!cvarf r_waterwarp\n"
//this is a post processing shader that is drawn fullscreen whenever the view is underwater.
//its generally expected to warp the view a little.
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"varying vec2 v_stc;\n"
"varying vec2 v_warp;\n"
"varying vec2 v_edge;\n"
"uniform float e_time;\n"
"void main ()\n"
"{\n"
"gl_Position = ftetransform();\n"
"v_stc = vec2(v_texcoord.x, 1.0-v_texcoord.y);\n"
"v_warp.s = e_time * 0.25 + v_texcoord.s;\n"
"v_warp.t = e_time * 0.25 + v_texcoord.t;\n"
"v_edge = v_texcoord.xy;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"varying vec2 v_stc;\n"
"varying vec2 v_warp;\n"
"varying vec2 v_edge;\n"
"uniform sampler2D s_t0;/*$currentrender*/\n"
"uniform sampler2D s_t1;/*warp image*/\n"
"uniform sampler2D s_t2;/*edge image*/\n"
"uniform vec4 e_rendertexturescale;\n"
"uniform float cvar_r_waterwarp;\n"
"void main ()\n"
"{\n"
"vec2 amp = (0.010 / 0.625) * cvar_r_waterwarp * texture2D(s_t2, v_edge).rg;\n"
"vec3 offset = (texture2D(s_t1, v_warp).rgb - 0.5) * 2.0;\n"
"vec2 temp = v_stc + offset.xy * amp;\n"
"gl_FragColor = texture2D(s_t0, temp*e_rendertexturescale.st);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "menutint",
"!!cvari r_menutint_inverse\n"
"!!cvarv r_menutint\n"
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"varying vec2 texcoord;\n"
"uniform vec4 e_rendertexturescale;\n"
"void main(void)\n"
"{\n"
"texcoord.x = v_texcoord.x*e_rendertexturescale.x;\n"
"texcoord.y = (1.0-v_texcoord.y)*e_rendertexturescale.y;\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"varying vec2 texcoord;\n"
"uniform vec3 cvar_r_menutint;\n"
"uniform sampler2D s_t0;\n"
"uniform int cvar_r_menutint_inverse;\n"
"const vec3 lumfactors = vec3(0.299, 0.587, 0.114);\n"
"const vec3 invertvec = vec3(1.0, 1.0, 1.0);\n"
"void main(void)\n"
"{\n"
"vec3 texcolor = texture2D(s_t0, texcoord).rgb;\n"
"float luminance = dot(lumfactors, texcolor);\n"
"texcolor = vec3(luminance, luminance, luminance);\n"
"texcolor *= cvar_r_menutint;\n"
"texcolor = (cvar_r_menutint_inverse > 0) ? (invertvec - texcolor) : texcolor;\n"
"gl_FragColor = vec4(texcolor, 1.0);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "terrain",
"!!permu FOG\n"
"#include \"sys/fog.h\"\n"
"varying vec2 tc;\n"
"varying vec2 lm;\n"
"varying vec4 vc;\n"
"#ifdef RTLIGHT\n"
"varying vec3 lightvector;\n"
// #if defined(SPECULAR) || defined(OFFSETMAPPING)
// varying vec3 eyevector;
// #endif
"#if defined(PCF) || defined(CUBE) || defined(SPOT)\n"
"varying vec4 vtexprojcoord;\n"
"#endif\n"
"#endif\n"
"#ifdef VERTEX_SHADER\n"
"#ifdef RTLIGHT\n"
"uniform vec3 l_lightposition;\n"
// #if defined(SPECULAR) || defined(OFFSETMAPPING)
// uniform vec3 e_eyepos;
// #endif
"#if defined(PCF) || defined(CUBE) || defined(SPOT)\n"
"uniform mat4 l_cubematrix;\n"
"#endif\n"
"attribute vec3 v_normal;\n"
"attribute vec3 v_svector;\n"
"attribute vec3 v_tvector;\n"
"#endif\n"
"attribute vec2 v_texcoord;\n"
"attribute vec2 v_lmcoord;\n"
"attribute vec4 v_colour;\n"
"void main (void)\n"
"{\n"
"tc = v_texcoord.st;\n"
"lm = v_lmcoord.st;\n"
"vc = v_colour;\n"
"gl_Position = ftetransform();\n"
"#ifdef RTLIGHT\n"
//light position is in model space, which is handy.
"vec3 lightminusvertex = l_lightposition - v_position.xyz;\n"
//no bumpmapping, so we can just use distance without regard for actual surface direction. we still do scalecos stuff. you might notice it on steep slopes.
"lightvector = lightminusvertex;\n"
// lightvector.x = dot(lightminusvertex, v_svector.xyz);
// lightvector.y = dot(lightminusvertex, v_tvector.xyz);
// lightvector.z = dot(lightminusvertex, v_normal.xyz);
// #if defined(SPECULAR)||defined(OFFSETMAPPING)
// vec3 eyeminusvertex = e_eyepos - v_position.xyz;
// eyevector.x = dot(eyeminusvertex, v_svector.xyz);
// eyevector.y = dot(eyeminusvertex, v_tvector.xyz);
// eyevector.z = dot(eyeminusvertex, v_normal.xyz);
// #endif
"#if defined(PCF) || defined(SPOT) || defined(CUBE)\n"
//for texture projections/shadowmapping on dlights
"vtexprojcoord = (l_cubematrix*vec4(v_position.xyz, 1.0));\n"
"#endif\n"
"#endif\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
//four texture passes
"uniform sampler2D s_t0;\n"
"uniform sampler2D s_t1;\n"
"uniform sampler2D s_t2;\n"
"uniform sampler2D s_t3;\n"
//mix values
"uniform sampler2D s_t4;\n"
"#ifdef PCF\n"
"uniform sampler2DShadow s_t5;\n"
"#include \"sys/pcf.h\"\n"
"#endif\n"
"#ifdef CUBE\n"
"uniform samplerCube s_t6;\n"
"#endif\n"
//light levels
"uniform vec4 e_lmscale;\n"
"#ifdef RTLIGHT\n"
"uniform float l_lightradius;\n"
"uniform vec3 l_lightcolour;\n"
"uniform vec3 l_lightcolourscale;\n"
"#endif\n"
"void main (void)\n"
"{\n"
"vec4 r;\n"
"vec4 m = texture2D(s_t4, lm);\n"
"r = texture2D(s_t0, tc)*m.r;\n"
"r += texture2D(s_t1, tc)*m.g;\n"
"r += texture2D(s_t2, tc)*m.b;\n"
"r += texture2D(s_t3, tc)*(1.0 - (m.r + m.g + m.b));\n"
//vertex colours provide a scaler that applies even through rtlights.
"r *= vc;\n"
"#ifdef RTLIGHT\n"
"vec3 nl = normalize(lightvector);\n"
"float colorscale = max(1.0 - (dot(lightvector, lightvector)/(l_lightradius*l_lightradius)), 0.0);\n"
"vec3 diff;\n"
// #ifdef BUMP
// colorscale *= (l_lightcolourscale.x + l_lightcolourscale.y * max(dot(bumps, nl), 0.0));
// #else
"colorscale *= (l_lightcolourscale.x + l_lightcolourscale.y * max(dot(vec3(0.0, 0.0, 1.0), nl), 0.0));\n"
// #endif
// #ifdef SPECULAR
// vec3 halfdir = normalize(normalize(eyevector) + nl);
// float spec = pow(max(dot(halfdir, bumps), 0.0), 32.0 * specs.a);
// diff += l_lightcolourscale.z * spec * specs.rgb;
// #endif
"#if defined(SPOT)\n"
"if (vtexprojcoord.w < 0.0) discard;\n"
"vec2 spot = ((vtexprojcoord.st)/vtexprojcoord.w);\n"
"colorscale *= 1.0-(dot(spot,spot));\n"
"#endif\n"
"#ifdef PCF\n"
"colorscale *= ShadowmapFilter(s_t5);\n"
"#endif\n"
"r.rgb *= colorscale * l_lightcolour;\n"
"#ifdef CUBE\n"
"r.rgb *= textureCube(s_t6, vtexprojcoord.xyz).rgb;\n"
"#endif\n"
"gl_FragColor = fog4additive(r);\n"
"#else\n"
//lightmap is greyscale in m.a. probably we should just scale the texture mix, but precision errors when editing make me paranoid.
"r *= e_lmscale*vec4(m.aaa,1.0);\n"
"gl_FragColor = fog4(r);\n"
"#endif\n"
"}\n"
"#endif\n"
},
#endif
#ifdef D3D11QUAKE
{QR_DIRECT3D11, 11, "terrain",
"struct a2v\n"
"{\n"
"float4 pos: POSITION;\n"
"float4 tc: TEXCOORD0;\n"
"float4 vcol: COLOR0;\n"
"};\n"
"struct v2f\n"
"{\n"
"float4 pos: SV_POSITION;\n"
"float2 tc: TEXCOORD0;\n"
"float2 lmtc: TEXCOORD1;\n"
"float4 vcol: COLOR0;\n"
"float3 vtexprojcoord: TEXCOORD2;\n"
"float3 vtexprojcoord: TEXCOORD2;\n"
"};\n"
"#include <ftedefs.h>\n"
"#ifdef VERTEX_SHADER\n"
"v2f main (a2v inp)\n"
"{\n"
"v2f outp;\n"
"outp.pos = mul(m_model, inp.pos);\n"
"outp.pos = mul(m_view, outp.pos);\n"
"outp.pos = mul(m_projection, outp.pos);\n"
"outp.tc = inp.tc.xy;\n"
"outp.lmtc = inp.tc.zw;\n"
"outp.vcol = inp.vcol;\n"
"return outp;\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"Texture2D shaderTexture[7];\n"
"SamplerState SampleType[7];\n"
"float4 main (v2f inp) : SV_TARGET\n"
"{\n"
"float4 result;\n"
"float4 base = shaderTexture[0].Sample(SampleType[0], inp.tc);\n"
"#ifdef BUMP\n"
"float4 bump = shaderTexture[1].Sample(SampleType[1], inp.tc);\n"
"#else\n"
"float4 bump = float4(0, 0, 1, 0);\n"
"#endif\n"
"float4 spec = shaderTexture[2].Sample(SampleType[2], inp.tc);\n"
"#ifdef CUBE\n"
"float4 cubemap = shaderTexture[3].Sample(SampleType[3], inp.vtexprojcoord);\n"
"#endif\n"
//shadowmap 2d
"#ifdef LOWER\n"
"float4 lower = shaderTexture[5].Sample(SampleType[5], inp.tc);\n"
"base += lower;\n"
"#endif\n"
"#ifdef UPPER\n"
"float4 upper = shaderTexture[6].Sample(SampleType[6], inp.tc);\n"
"base += upper;\n"
"#endif\n"
"float lightscale = max(1.0 - (dot(inp.lightvector,inp.lightvector)/(l_lightradius*l_lightradius)), 0.0);\n"
"float3 nl = normalize(inp.lightvector);\n"
"float bumpscale = max(dot(bump.xyz, nl), 0.0);\n"
"float3 halfdir = normalize(normalize(eyevector) + nl);\n"
"float specscale = pow(max(dot(halfdir, bumps), 0.0), 32.0 * spec.a);\n"
"result.a = base.a;\n"
"result.rgb = base.rgb * (l_lightcolourscale.x + l_lightcolourscale.y * bumpscale); //amient light + diffuse\n"
"result.rgb += spec.rgb * l_lightcolourscale.z * specscale; //specular\n"
"result.rgb *= lightscale; //fade light by distance\n"
"#ifdef CUBE\n"
"result.rgb *= cubemap.rgb; //fade by cubemap\n"
"#endif\n"
"return result;\n"
"}\n"
"#endif\n"
},
#endif