static int r_frame = 0; ///< used only by R_GetCurrentTexture
+qboolean r_loadnormalmap;
+qboolean r_loadgloss;
+qboolean r_loadfog;
+
//
// screen size info
//
cvar_t r_equalize_entities_by = {CVAR_SAVE, "r_equalize_entities_by", "0.7", "light equalizing: exponent of dynamics compression (0 = no compression, 1 = full compression)"};
cvar_t r_equalize_entities_to = {CVAR_SAVE, "r_equalize_entities_to", "0.8", "light equalizing: target light level"};
-cvar_t r_animcache = {CVAR_SAVE, "r_animcache", "1", "cache animation frames to save CPU usage, primarily optimizes shadows and reflections"};
-
cvar_t r_depthfirst = {CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
cvar_t r_useinfinitefarclip = {CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
cvar_t r_farclip_base = {0, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
cvar_t gl_fogend = {0, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
cvar_t gl_skyclip = {0, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
-cvar_t r_textureunits = {0, "r_textureunits", "32", "number of hardware texture units reported by driver (note: setting this to 1 turns off gl_combine)"};
+cvar_t r_textureunits = {0, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
+static cvar_t gl_combine = {CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
+static cvar_t r_glsl = {CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
-cvar_t r_glsl = {CVAR_SAVE, "r_glsl", "1", "enables use of OpenGL 2.0 pixel shaders for lighting"};
cvar_t r_glsl_deluxemapping = {CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
cvar_t r_glsl_postprocess_uservec2 = {CVAR_SAVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
cvar_t r_glsl_postprocess_uservec3 = {CVAR_SAVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
cvar_t r_glsl_postprocess_uservec4 = {CVAR_SAVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
-cvar_t r_glsl_usegeneric = {CVAR_SAVE, "r_glsl_usegeneric", "1", "use shaders for rendering simple geometry (rather than conventional fixed-function rendering for this purpose)"};
cvar_t r_water = {CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
cvar_t r_water_clippingplanebias = {CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
cvar_t r_track_sprites_scaleh = {CVAR_SAVE, "r_track_sprites_scaleh", "1", "height scaling of tracked sprites"};
cvar_t r_glsl_saturation = {CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
+cvar_t r_framedatasize = {CVAR_SAVE, "r_framedatasize", "1", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
+
extern cvar_t v_glslgamma;
extern qboolean v_flipped_state;
}
}
}
- r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, NULL);
+ r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_MIPMAP | TEXF_PERSISTENT, NULL);
}
static void R_BuildWhiteCube(void)
"\n"
"// enable various extensions depending on permutation:\n"
"\n"
-"#ifdef USESHADOWMAPRECT\n"
-"# extension GL_ARB_texture_rectangle : enable\n"
-"#endif\n"
-"\n"
-"#ifdef USESHADOWMAP2D\n"
-"# ifdef GL_EXT_gpu_shader4\n"
-"# extension GL_EXT_gpu_shader4 : enable\n"
-"# endif\n"
-"# ifdef GL_ARB_texture_gather\n"
-"# extension GL_ARB_texture_gather : enable\n"
-"# else\n"
-"# ifdef GL_AMD_texture_texture4\n"
-"# extension GL_AMD_texture_texture4 : enable\n"
-"# endif\n"
-"# endif\n"
-"#endif\n"
-"\n"
-"#ifdef USESHADOWMAPCUBE\n"
-"# extension GL_EXT_gpu_shader4 : enable\n"
-"#endif\n"
-"\n"
-"#ifdef USESHADOWSAMPLER\n"
-"# extension GL_ARB_shadow : enable\n"
-"#endif\n"
-"\n"
-"// common definitions between vertex shader and fragment shader:\n"
-"\n"
-"//#ifdef __GLSL_CG_DATA_TYPES\n"
-"//# define myhalf half\n"
-"//# define myhalf2 half2\n"
-"//# define myhalf3half3\n"
-"//# define myhalf4 half4\n"
-"//#else\n"
-"# define myhalf float\n"
-"# define myhalf2 vec2\n"
-"# define myhalf3 vec3\n"
-"# define myhalf4 vec4\n"
-"//#endif\n"
-"\n"
-"#ifdef USEFOGINSIDE\n"
-"# define USEFOG\n"
-"#else\n"
-"# ifdef USEFOGOUTSIDE\n"
-"# define USEFOG\n"
-"# endif\n"
-"#endif\n"
-"\n"
"#ifdef MODE_DEPTH_OR_SHADOW\n"
-"\n"
-"# ifdef VERTEX_SHADER\n"
+"#ifdef VERTEX_SHADER\n"
"void main(void)\n"
"{\n"
" gl_Position = ftransform();\n"
"}\n"
-"# endif\n"
-"\n"
-"#else\n"
+"#endif\n"
+"#else // !MODE_DEPTH_ORSHADOW\n"
"#ifdef MODE_SHOWDEPTH\n"
-"# ifdef VERTEX_SHADER\n"
+"#ifdef VERTEX_SHADER\n"
"void main(void)\n"
"{\n"
" gl_Position = ftransform();\n"
" gl_FrontColor = vec4(gl_Position.z, gl_Position.z, gl_Position.z, 1.0);\n"
"}\n"
-"# endif\n"
-"# ifdef FRAGMENT_SHADER\n"
+"#endif\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
"void main(void)\n"
"{\n"
" gl_FragColor = gl_Color;\n"
"}\n"
-"# endif\n"
-"\n"
+"#endif\n"
"#else // !MODE_SHOWDEPTH\n"
-"\n"
"#ifdef MODE_POSTPROCESS\n"
-"# ifdef VERTEX_SHADER\n"
+"#ifdef VERTEX_SHADER\n"
"void main(void)\n"
"{\n"
-" gl_FrontColor = gl_Color;\n"
" gl_Position = ftransform();\n"
" gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
"#ifdef USEBLOOM\n"
" gl_TexCoord[1] = gl_TextureMatrix[1] * gl_MultiTexCoord1;\n"
"#endif\n"
"}\n"
-"# endif\n"
-"# ifdef FRAGMENT_SHADER\n"
+"#endif\n"
"\n"
+"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D Texture_First;\n"
"#ifdef USEBLOOM\n"
"uniform sampler2D Texture_Second;\n"
"\n"
"#ifdef USESATURATION\n"
" //apply saturation BEFORE gamma ramps, so v_glslgamma value does not matter\n"
-" myhalf y = dot(gl_FragColor.rgb, vec3(0.299, 0.587, 0.114));\n"
+" float y = dot(gl_FragColor.rgb, vec3(0.299, 0.587, 0.114));\n"
" //gl_FragColor = vec3(y) + (gl_FragColor.rgb - vec3(y)) * Saturation;\n"
" gl_FragColor.rgb = mix(vec3(y), gl_FragColor.rgb, Saturation);\n"
"#endif\n"
" gl_FragColor.b = texture2D(Texture_GammaRamps, vec2(gl_FragColor.b, 0)).b;\n"
"#endif\n"
"}\n"
-"# endif\n"
-"\n"
-"\n"
-"#else\n"
+"#endif\n"
+"#else // !MODE_POSTPROCESS\n"
"#ifdef MODE_GENERIC\n"
-"# ifdef VERTEX_SHADER\n"
+"#ifdef VERTEX_SHADER\n"
"void main(void)\n"
"{\n"
" gl_FrontColor = gl_Color;\n"
-"# ifdef USEDIFFUSE\n"
+"#ifdef USEDIFFUSE\n"
" gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
-"# endif\n"
-"# ifdef USESPECULAR\n"
+"#endif\n"
+"#ifdef USESPECULAR\n"
" gl_TexCoord[1] = gl_TextureMatrix[1] * gl_MultiTexCoord1;\n"
-"# endif\n"
+"#endif\n"
" gl_Position = ftransform();\n"
"}\n"
-"# endif\n"
-"# ifdef FRAGMENT_SHADER\n"
+"#endif\n"
"\n"
-"# ifdef USEDIFFUSE\n"
+"#ifdef FRAGMENT_SHADER\n"
+"#ifdef USEDIFFUSE\n"
"uniform sampler2D Texture_First;\n"
-"# endif\n"
-"# ifdef USESPECULAR\n"
+"#endif\n"
+"#ifdef USESPECULAR\n"
"uniform sampler2D Texture_Second;\n"
-"# endif\n"
+"#endif\n"
"\n"
"void main(void)\n"
"{\n"
" gl_FragColor = gl_Color;\n"
-"# ifdef USEDIFFUSE\n"
+"#ifdef USEDIFFUSE\n"
" gl_FragColor *= texture2D(Texture_First, gl_TexCoord[0].xy);\n"
-"# endif\n"
+"#endif\n"
"\n"
-"# ifdef USESPECULAR\n"
+"#ifdef USESPECULAR\n"
" vec4 tex2 = texture2D(Texture_Second, gl_TexCoord[1].xy);\n"
-"# endif\n"
-"# ifdef USECOLORMAPPING\n"
+"#endif\n"
+"#ifdef USECOLORMAPPING\n"
" gl_FragColor *= tex2;\n"
-"# endif\n"
-"# ifdef USEGLOW\n"
+"#endif\n"
+"#ifdef USEGLOW\n"
" gl_FragColor += tex2;\n"
-"# endif\n"
-"# ifdef USEVERTEXTEXTUREBLEND\n"
+"#endif\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
" gl_FragColor = mix(gl_FragColor, tex2, tex2.a);\n"
-"# endif\n"
+"#endif\n"
"}\n"
-"# endif\n"
-"\n"
+"#endif\n"
"#else // !MODE_GENERIC\n"
"#ifdef MODE_BLOOMBLUR\n"
-"# ifdef VERTEX_SHADER\n"
+"#ifdef VERTEX_SHADER\n"
"void main(void)\n"
"{\n"
" gl_FrontColor = gl_Color;\n"
" gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
" gl_Position = ftransform();\n"
"}\n"
-"# endif\n"
-"# ifdef FRAGMENT_SHADER\n"
+"#endif\n"
"\n"
+"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D Texture_First;\n"
"uniform vec4 BloomBlur_Parameters;\n"
"\n"
" }\n"
" gl_FragColor = vec4(color * BloomBlur_Parameters.z + vec3(BloomBlur_Parameters.w), 1);\n"
"}\n"
+"#endif\n"
+"#else // !MODE_BLOOMBLUR\n"
+"#ifdef MODE_REFRACTION\n"
+"varying vec2 TexCoord;\n"
+"varying vec4 ModelViewProjectionPosition;\n"
+"#ifdef VERTEX_SHADER\n"
+"\n"
+"void main(void)\n"
+"{\n"
+" TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
+" gl_Position = ftransform();\n"
+" ModelViewProjectionPosition = gl_Position;\n"
+"}\n"
+"#endif\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"uniform sampler2D Texture_Normal;\n"
+"uniform sampler2D Texture_Refraction;\n"
+"uniform sampler2D Texture_Reflection;\n"
+"\n"
+"uniform vec4 DistortScaleRefractReflect;\n"
+"uniform vec4 ScreenScaleRefractReflect;\n"
+"uniform vec4 ScreenCenterRefractReflect;\n"
+"uniform vec4 RefractColor;\n"
+"uniform vec4 ReflectColor;\n"
+"uniform float ReflectFactor;\n"
+"uniform float ReflectOffset;\n"
+"\n"
+"void main(void)\n"
+"{\n"
+" vec2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n"
+" //vec2 ScreenTexCoord = (ModelViewProjectionPosition.xy + normalize(vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5)).xy * DistortScaleRefractReflect.xy * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
+" vec2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
+" vec2 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5))).xy * DistortScaleRefractReflect.xy;\n"
+" // FIXME temporary hack to detect the case that the reflection\n"
+" // gets blackened at edges due to leaving the area that contains actual\n"
+" // content.\n"
+" // Remove this 'ack once we have a better way to stop this thing from\n"
+" // 'appening.\n"
+" float f = min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.01, 0.01)).rgb) / 0.05);\n"
+" f *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.01, -0.01)).rgb) / 0.05);\n"
+" f *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
+" f *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
+" ScreenTexCoord = mix(SafeScreenTexCoord, ScreenTexCoord, f);\n"
+" gl_FragColor = texture2D(Texture_Refraction, ScreenTexCoord) * RefractColor;\n"
+"}\n"
+"#endif\n"
+"#else // !MODE_REFRACTION\n"
+"#ifdef MODE_WATER\n"
+"varying vec2 TexCoord;\n"
+"varying vec3 EyeVector;\n"
+"varying vec4 ModelViewProjectionPosition;\n"
+"#ifdef VERTEX_SHADER\n"
+"uniform vec3 EyePosition;\n"
+"\n"
+"void main(void)\n"
+"{\n"
+" TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
+" vec3 EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
+" EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
+" EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
+" EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
+" gl_Position = ftransform();\n"
+" ModelViewProjectionPosition = gl_Position;\n"
+"}\n"
+"#endif\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"uniform sampler2D Texture_Normal;\n"
+"uniform sampler2D Texture_Refraction;\n"
+"uniform sampler2D Texture_Reflection;\n"
+"\n"
+"uniform vec4 DistortScaleRefractReflect;\n"
+"uniform vec4 ScreenScaleRefractReflect;\n"
+"uniform vec4 ScreenCenterRefractReflect;\n"
+"uniform vec4 RefractColor;\n"
+"uniform vec4 ReflectColor;\n"
+"uniform float ReflectFactor;\n"
+"uniform float ReflectOffset;\n"
+"\n"
+"void main(void)\n"
+"{\n"
+" vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
+" //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
+" vec4 SafeScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
+" vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5))).xyxy * DistortScaleRefractReflect;\n"
+" // FIXME temporary hack to detect the case that the reflection\n"
+" // gets blackened at edges due to leaving the area that contains actual\n"
+" // content.\n"
+" // Remove this 'ack once we have a better way to stop this thing from\n"
+" // 'appening.\n"
+" float f = min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.01, 0.01)).rgb) / 0.05);\n"
+" f *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.01, -0.01)).rgb) / 0.05);\n"
+" f *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
+" f *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
+" ScreenTexCoord.xy = mix(SafeScreenTexCoord.xy, ScreenTexCoord.xy, f);\n"
+" f = min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.01, 0.01)).rgb) / 0.05);\n"
+" f *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.01, -0.01)).rgb) / 0.05);\n"
+" f *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
+" f *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
+" ScreenTexCoord.zw = mix(SafeScreenTexCoord.zw, ScreenTexCoord.zw, f);\n"
+" float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0) * ReflectFactor + ReflectOffset;\n"
+" gl_FragColor = mix(texture2D(Texture_Refraction, ScreenTexCoord.xy) * RefractColor, texture2D(Texture_Reflection, ScreenTexCoord.zw) * ReflectColor, Fresnel);\n"
+"}\n"
+"#endif\n"
+"#else // !MODE_WATER\n"
+"\n"
+"#if defined(USESHADOWMAPRECT) || defined(MODE_DEFERREDLIGHTSOURCE) || defined(USEDEFERREDLIGHTMAP)\n"
+"# extension GL_ARB_texture_rectangle : enable\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAP2D\n"
+"# ifdef GL_EXT_gpu_shader4\n"
+"# extension GL_EXT_gpu_shader4 : enable\n"
"# endif\n"
+"# ifdef GL_ARB_texture_gather\n"
+"# extension GL_ARB_texture_gather : enable\n"
+"# else\n"
+"# ifdef GL_AMD_texture_texture4\n"
+"# extension GL_AMD_texture_texture4 : enable\n"
+"# endif\n"
+"# endif\n"
+"#endif\n"
"\n"
-"#else // !MODE_BLOOMBLUR\n"
+"#ifdef USESHADOWMAPCUBE\n"
+"# extension GL_EXT_gpu_shader4 : enable\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWSAMPLER\n"
+"# extension GL_ARB_shadow : enable\n"
+"#endif\n"
+"\n"
+"// common definitions between vertex shader and fragment shader:\n"
+"\n"
+"//#ifdef __GLSL_CG_DATA_TYPES\n"
+"//# define myhalf half\n"
+"//# define myhalf2 half2\n"
+"//# define myhalf3half3\n"
+"//# define myhalf4 half4\n"
+"//#else\n"
+"# define myhalf float\n"
+"# define myhalf2 vec2\n"
+"# define myhalf3 vec3\n"
+"# define myhalf4 vec4\n"
+"//#endif\n"
+"\n"
+"#if defined(USEFOGINSIDE) || defined(USEFOGOUTSIDE)\n"
+"# define USEFOG\n"
+"#endif\n"
"\n"
"varying vec2 TexCoord;\n"
"#ifdef USEVERTEXTEXTUREBLEND\n"
"varying vec2 TexCoord2;\n"
"#endif\n"
+"#if defined(MODE_LIGHTMAP) || defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
+"#define USELIGHTMAP\n"
"varying vec2 TexCoordLightmap;\n"
+"#endif\n"
"\n"
"#ifdef MODE_LIGHTSOURCE\n"
"varying vec3 CubeVector;\n"
"#ifdef MODE_LIGHTSOURCE\n"
"varying vec3 LightVector;\n"
"#endif\n"
-"#ifdef MODE_LIGHTDIRECTION\n"
+"#if defined(MODE_LIGHTDIRECTION) && defined(USEDIFFUSE)\n"
"varying vec3 LightVector;\n"
"#endif\n"
"\n"
+"#if defined(USEOFFSETMAPPING) || defined(USEFOG) || defined(USESPECULAR)\n"
+"#define USEEYEVECTOR\n"
"varying vec3 EyeVector;\n"
+"#endif\n"
"#ifdef USEFOG\n"
"varying vec3 EyeVectorModelSpace;\n"
"varying float FogPlaneVertexDist;\n"
"varying vec3 VectorT; // direction of T texcoord (sometimes crudely called binormal)\n"
"varying vec3 VectorR; // direction of R texcoord (surface normal)\n"
"\n"
-"#ifdef MODE_WATER\n"
-"varying vec4 ModelViewProjectionPosition;\n"
-"#endif\n"
-"#ifdef MODE_REFRACTION\n"
-"varying vec4 ModelViewProjectionPosition;\n"
-"#endif\n"
"#ifdef USEREFLECTION\n"
"varying vec4 ModelViewProjectionPosition;\n"
"#endif\n"
+"#ifdef MODE_DEFERREDLIGHTSOURCE\n"
+"varying vec4 ModelViewPosition;\n"
+"#endif\n"
+"\n"
+"uniform vec3 LightPosition;\n"
+"uniform vec3 EyePosition;\n"
+"uniform vec3 LightDir;\n"
+"uniform vec4 FogPlane;\n"
"\n"
"\n"
"\n"
"// vertex shader specific:\n"
"#ifdef VERTEX_SHADER\n"
"\n"
-"uniform vec3 LightPosition;\n"
-"uniform vec3 EyePosition;\n"
-"uniform vec3 LightDir;\n"
-"uniform vec4 FogPlane;\n"
+"// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3), this would require sending a 4 component texcoord1 with W as 1 or -1 according to which side the texcoord2 should be on\n"
+"\n"
+"#ifdef MODE_DEFERREDGEOMETRY\n"
+"void main(void)\n"
+"{\n"
+" TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+" gl_FrontColor = gl_Color;\n"
+" TexCoord2 = vec2(gl_TextureMatrix[1] * gl_MultiTexCoord0);\n"
+"#endif\n"
"\n"
-"// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3), this would require sending a 4 component texcoord1 with W as 1 or -1 according to which side the texcoord2 should be on\n"
+" // transform unnormalized eye direction into tangent space\n"
+"#ifdef USEFOG\n"
+" EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
+" FogPlaneVertexDist = dot(FogPlane, gl_Vertex);\n"
+"#endif\n"
+"#ifdef USEOFFSETMAPPING\n"
+"#ifndef USEFOG\n"
+" vec3 EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
+"#endif\n"
+" EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
+" EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
+" EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
+"#endif\n"
"\n"
+" VectorS = normalize(gl_NormalMatrix * gl_MultiTexCoord1.xyz).xyz;\n"
+" VectorT = normalize(gl_NormalMatrix * gl_MultiTexCoord2.xyz).xyz;\n"
+" VectorR = normalize(gl_NormalMatrix * gl_MultiTexCoord3.xyz).xyz;\n"
+" gl_Position = ftransform();\n"
+"}\n"
+"#else // !MODE_DEFERREDGEOMETRY\n"
+"#ifdef MODE_DEFERREDLIGHTSOURCE\n"
+"void main(void)\n"
+"{\n"
+" ModelViewPosition = gl_ModelViewMatrix * gl_Vertex;\n"
+" gl_Position = ftransform();\n"
+"}\n"
+"#else // !MODE_DEFERREDLIGHTSOURCE\n"
"void main(void)\n"
"{\n"
+"#if defined(MODE_VERTEXCOLOR) || defined(USEVERTEXTEXTUREBLEND)\n"
" gl_FrontColor = gl_Color;\n"
+"#endif\n"
" // copy the surface texcoord\n"
" TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
"#ifdef USEVERTEXTEXTUREBLEND\n"
" TexCoord2 = vec2(gl_TextureMatrix[1] * gl_MultiTexCoord0);\n"
"#endif\n"
-"#ifndef MODE_LIGHTSOURCE\n"
-"# ifndef MODE_LIGHTDIRECTION\n"
+"#ifdef USELIGHTMAP\n"
" TexCoordLightmap = vec2(gl_MultiTexCoord4);\n"
-"# endif\n"
"#endif\n"
"\n"
"#ifdef MODE_LIGHTSOURCE\n"
" // (-1 to +1 across the light box)\n"
" CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
"\n"
+"# ifdef USEDIFFUSE\n"
" // transform unnormalized light direction into tangent space\n"
" // (we use unnormalized to ensure that it interpolates correctly and then\n"
" // normalize it per pixel)\n"
" LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
" LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
" LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
+"# endif\n"
"#endif\n"
"\n"
-"#ifdef MODE_LIGHTDIRECTION\n"
+"#if defined(MODE_LIGHTDIRECTION) && defined(USEDIFFUSE)\n"
" LightVector.x = dot(LightDir, gl_MultiTexCoord1.xyz);\n"
" LightVector.y = dot(LightDir, gl_MultiTexCoord2.xyz);\n"
" LightVector.z = dot(LightDir, gl_MultiTexCoord3.xyz);\n"
"#endif\n"
"\n"
" // transform unnormalized eye direction into tangent space\n"
+"#ifdef USEEYEVECTOR\n"
"#ifndef USEFOG\n"
" vec3 EyeVectorModelSpace;\n"
"#endif\n"
" EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
" EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
" EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
+"#endif\n"
"\n"
"#ifdef USEFOG\n"
" FogPlaneVertexDist = dot(FogPlane, gl_Vertex);\n"
" VectorR = gl_MultiTexCoord3.xyz;\n"
"#endif\n"
"\n"
-"//#if defined(MODE_WATER) || defined(MODE_REFRACTION) || defined(USEREFLECTION)\n"
+"//#if defined(USEREFLECTION)\n"
"// ModelViewProjectionPosition = gl_Vertex * gl_ModelViewProjectionMatrix;\n"
"// //ModelViewProjectionPosition_svector = (gl_Vertex + vec4(gl_MultiTexCoord1.xyz, 0)) * gl_ModelViewProjectionMatrix - ModelViewProjectionPosition;\n"
"// //ModelViewProjectionPosition_tvector = (gl_Vertex + vec4(gl_MultiTexCoord2.xyz, 0)) * gl_ModelViewProjectionMatrix - ModelViewProjectionPosition;\n"
" // rendering\n"
" gl_Position = ftransform();\n"
"\n"
-"#ifdef MODE_WATER\n"
-" ModelViewProjectionPosition = gl_Position;\n"
-"#endif\n"
-"#ifdef MODE_REFRACTION\n"
-" ModelViewProjectionPosition = gl_Position;\n"
-"#endif\n"
"#ifdef USEREFLECTION\n"
" ModelViewProjectionPosition = gl_Position;\n"
"#endif\n"
"}\n"
+"#endif // !MODE_DEFERREDLIGHTSOURCE\n"
+"#endif // !MODE_DEFERREDGEOMETRY\n"
"\n"
"#endif // VERTEX_SHADER\n"
"\n"
"// fragment shader specific:\n"
"#ifdef FRAGMENT_SHADER\n"
"\n"
-"// 13 textures, we can only use up to 16 on DX9-class hardware\n"
"uniform sampler2D Texture_Normal;\n"
"uniform sampler2D Texture_Color;\n"
+"#if defined(USESPECULAR) || defined(USEDEFERREDLIGHTMAP)\n"
"uniform sampler2D Texture_Gloss;\n"
+"#endif\n"
+"#ifdef USEGLOW\n"
"uniform sampler2D Texture_Glow;\n"
+"#endif\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
"uniform sampler2D Texture_SecondaryNormal;\n"
"uniform sampler2D Texture_SecondaryColor;\n"
+"#if defined(USESPECULAR) || defined(USEDEFERREDLIGHTMAP)\n"
"uniform sampler2D Texture_SecondaryGloss;\n"
+"#endif\n"
+"#ifdef USEGLOW\n"
"uniform sampler2D Texture_SecondaryGlow;\n"
+"#endif\n"
+"#endif\n"
+"#ifdef USECOLORMAPPING\n"
"uniform sampler2D Texture_Pants;\n"
"uniform sampler2D Texture_Shirt;\n"
+"#endif\n"
+"#ifdef USEFOG\n"
"uniform sampler2D Texture_FogMask;\n"
+"#endif\n"
+"#ifdef USELIGHTMAP\n"
"uniform sampler2D Texture_Lightmap;\n"
+"#endif\n"
+"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
"uniform sampler2D Texture_Deluxemap;\n"
-"uniform sampler2D Texture_Refraction;\n"
-"uniform sampler2D Texture_Reflection;\n"
-"uniform sampler2D Texture_Attenuation;\n"
-"uniform samplerCube Texture_Cube;\n"
-"\n"
-"#define showshadowmap 0\n"
-"\n"
-"#ifdef USESHADOWMAPRECT\n"
-"# ifdef USESHADOWSAMPLER\n"
-"uniform sampler2DRectShadow Texture_ShadowMapRect;\n"
-"# else\n"
-"uniform sampler2DRect Texture_ShadowMapRect;\n"
-"# endif\n"
"#endif\n"
-"\n"
-"#ifdef USESHADOWMAP2D\n"
-"# ifdef USESHADOWSAMPLER\n"
-"uniform sampler2DShadow Texture_ShadowMap2D;\n"
-"# else\n"
-"uniform sampler2D Texture_ShadowMap2D;\n"
-"# endif\n"
+"#ifdef USEREFLECTION\n"
+"uniform sampler2D Texture_Reflection;\n"
"#endif\n"
"\n"
-"#ifdef USESHADOWMAPVSDCT\n"
-"uniform samplerCube Texture_CubeProjection;\n"
+"#ifdef MODE_DEFERREDLIGHTSOURCE\n"
+"uniform sampler2DRect Texture_ScreenDepth;\n"
+"uniform sampler2DRect Texture_ScreenNormalMap;\n"
"#endif\n"
-"\n"
-"#ifdef USESHADOWMAPCUBE\n"
-"# ifdef USESHADOWSAMPLER\n"
-"uniform samplerCubeShadow Texture_ShadowMapCube;\n"
-"# else\n"
-"uniform samplerCube Texture_ShadowMapCube;\n"
-"# endif\n"
+"#ifdef USEDEFERREDLIGHTMAP\n"
+"uniform sampler2DRect Texture_ScreenDiffuse;\n"
+"uniform sampler2DRect Texture_ScreenSpecular;\n"
"#endif\n"
"\n"
"uniform myhalf3 LightColor;\n"
"uniform myhalf4 TintColor;\n"
"\n"
"\n"
-"//#ifdef MODE_WATER\n"
+"#ifdef USEREFLECTION\n"
"uniform vec4 DistortScaleRefractReflect;\n"
"uniform vec4 ScreenScaleRefractReflect;\n"
"uniform vec4 ScreenCenterRefractReflect;\n"
-"uniform myhalf4 RefractColor;\n"
"uniform myhalf4 ReflectColor;\n"
-"uniform myhalf ReflectFactor;\n"
-"uniform myhalf ReflectOffset;\n"
-"//#else\n"
-"//# ifdef MODE_REFRACTION\n"
-"//uniform vec4 DistortScaleRefractReflect;\n"
-"//uniform vec4 ScreenScaleRefractReflect;\n"
-"//uniform vec4 ScreenCenterRefractReflect;\n"
-"//uniform myhalf4 RefractColor;\n"
-"//# ifdef USEREFLECTION\n"
-"//uniform myhalf4 ReflectColor;\n"
-"//# endif\n"
-"//# else\n"
-"//# ifdef USEREFLECTION\n"
-"//uniform vec4 DistortScaleRefractReflect;\n"
-"//uniform vec4 ScreenScaleRefractReflect;\n"
-"//uniform vec4 ScreenCenterRefractReflect;\n"
-"//uniform myhalf4 ReflectColor;\n"
-"//# endif\n"
-"//# endif\n"
-"//#endif\n"
+"#endif\n"
"\n"
+"#ifdef USEGLOW\n"
"uniform myhalf3 GlowColor;\n"
+"#endif\n"
"uniform myhalf SceneBrightness;\n"
"\n"
-"uniform float OffsetMapping_Scale;\n"
-"uniform float OffsetMapping_Bias;\n"
-"uniform float FogRangeRecip;\n"
-"uniform float FogPlaneViewDist;\n"
-"uniform float FogHeightFade;\n"
-"\n"
"uniform myhalf AmbientScale;\n"
"uniform myhalf DiffuseScale;\n"
+"#ifdef USESPECULAR\n"
"uniform myhalf SpecularScale;\n"
"uniform myhalf SpecularPower;\n"
+"#endif\n"
+"\n"
+"\n"
+"\n"
+"#ifdef USEFOG\n"
+"uniform float FogRangeRecip;\n"
+"uniform float FogPlaneViewDist;\n"
+"uniform float FogHeightFade;\n"
+"myhalf FogVertex(void)\n"
+"{\n"
+" float fogfrac;\n"
+"#ifdef USEFOGOUTSIDE\n"
+" fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0, min(0.0, FogPlaneVertexDist) * FogHeightFade);\n"
+"#else\n"
+" fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist)) * min(1.0, (min(0.0, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);\n"
+"#endif\n"
+" return myhalf(texture2D(Texture_FogMask, myhalf2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0)));\n"
+"}\n"
+"#endif\n"
"\n"
"#ifdef USEOFFSETMAPPING\n"
+"uniform float OffsetMapping_Scale;\n"
+"uniform float OffsetMapping_Bias;\n"
"vec2 OffsetMapping(vec2 TexCoord)\n"
"{\n"
"#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n"
"}\n"
"#endif // USEOFFSETMAPPING\n"
"\n"
+"#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE)\n"
+"uniform sampler2D Texture_Attenuation;\n"
+"uniform samplerCube Texture_Cube;\n"
+"\n"
+"#define showshadowmap 0\n"
+"\n"
+"#ifdef USESHADOWMAPRECT\n"
+"# ifdef USESHADOWSAMPLER\n"
+"uniform sampler2DRectShadow Texture_ShadowMapRect;\n"
+"# else\n"
+"uniform sampler2DRect Texture_ShadowMapRect;\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAP2D\n"
+"# ifdef USESHADOWSAMPLER\n"
+"uniform sampler2DShadow Texture_ShadowMap2D;\n"
+"# else\n"
+"uniform sampler2D Texture_ShadowMap2D;\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAPVSDCT\n"
+"uniform samplerCube Texture_CubeProjection;\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAPCUBE\n"
+"# ifdef USESHADOWSAMPLER\n"
+"uniform samplerCubeShadow Texture_ShadowMapCube;\n"
+"# else\n"
+"uniform samplerCube Texture_ShadowMapCube;\n"
+"# endif\n"
+"#endif\n"
+"\n"
"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D) || defined(USESHADOWMAPCUBE)\n"
"uniform vec2 ShadowMap_TextureScale;\n"
"uniform vec4 ShadowMap_Parameters;\n"
"}\n"
"# endif\n"
"#endif\n"
+"#endif // !defined(MODE_LIGHTSOURCE) && !defined(MODE_DEFERREDLIGHTSOURCE)\n"
"\n"
-"#ifdef MODE_WATER\n"
-"\n"
-"// water pass\n"
+"#ifdef MODE_DEFERREDGEOMETRY\n"
"void main(void)\n"
"{\n"
"#ifdef USEOFFSETMAPPING\n"
"#define TexCoord TexCoordOffset\n"
"#endif\n"
"\n"
-" vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
-" //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
-" vec4 SafeScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
-" vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5))).xyxy * DistortScaleRefractReflect;\n"
-" // FIXME temporary hack to detect the case that the reflection\n"
-" // gets blackened at edges due to leaving the area that contains actual\n"
-" // content.\n"
-" // Remove this 'ack once we have a better way to stop this thing from\n"
-" // 'appening.\n"
-" float f = min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.01, 0.01)).rgb) / 0.05);\n"
-" f *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.01, -0.01)).rgb) / 0.05);\n"
-" f *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
-" f *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
-" ScreenTexCoord.xy = mix(SafeScreenTexCoord.xy, ScreenTexCoord.xy, f);\n"
-" f = min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.01, 0.01)).rgb) / 0.05);\n"
-" f *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.01, -0.01)).rgb) / 0.05);\n"
-" f *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
-" f *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
-" ScreenTexCoord.zw = mix(SafeScreenTexCoord.zw, ScreenTexCoord.zw, f);\n"
-" float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0) * ReflectFactor + ReflectOffset;\n"
-" gl_FragColor = mix(texture2D(Texture_Refraction, ScreenTexCoord.xy) * RefractColor, texture2D(Texture_Reflection, ScreenTexCoord.zw) * ReflectColor, Fresnel);\n"
-"}\n"
+" // get diffuse alpha in case we're using alpha masking\n"
+" float alpha = float(texture2D(Texture_Color, TexCoord).a);\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+" float terrainblend = clamp(float(gl_Color.a) * alpha * 2.0 - 0.5, float(0.0), float(1.0));\n"
+" //float terrainblend = min(float(gl_Color.a) * alpha * 2.0, float(1.0));\n"
+" //float terrainblend = float(gl_Color.a) * alpha > 0.5;\n"
+" alpha = 1.0;\n"
+"#endif\n"
"\n"
-"#else // !MODE_WATER\n"
-"#ifdef MODE_REFRACTION\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+" vec3 surfacenormal = normalize(mix(vec3(texture2D(Texture_SecondaryNormal, TexCoord2)), vec3(texture2D(Texture_Normal, TexCoord)), terrainblend) - vec3(0.5, 0.5, 0.5));\n"
+"#else\n"
+" vec3 surfacenormal = normalize(vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5, 0.5, 0.5));\n"
+"#endif\n"
+"\n"
+" // fade the normal in fog so that lights don't have to consider fog\n"
+"#ifdef USEFOG\n"
+" surfacenormal *= FogVertex();\n"
+"#endif\n"
"\n"
-"// refraction pass\n"
+" gl_FragColor = vec4((surfacenormal.x * VectorS + surfacenormal.y * VectorT + surfacenormal.z * VectorR) * 0.5 + vec3(0.5,0.5,0.5), alpha);\n"
+"}\n"
+"#else // !MODE_DEFERREDGEOMETRY\n"
+"#ifdef MODE_DEFERREDLIGHTSOURCE\n"
+"uniform mat4 ViewToLight;\n"
+"// ScreenToDepth = vec2(Far / (Far - Near), Far * Near / (Near - Far));\n"
+"uniform vec2 ScreenToDepth;\n"
+"uniform float DeferredDiffuseRange;\n"
+"uniform float DeferredSpecularRange;\n"
"void main(void)\n"
"{\n"
-"#ifdef USEOFFSETMAPPING\n"
-" // apply offsetmapping\n"
-" vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
-"#define TexCoord TexCoordOffset\n"
+" // calculate viewspace pixel position\n"
+" vec3 position;\n"
+" position.z = ScreenToDepth.y / (texture2DRect(Texture_ScreenDepth, gl_FragCoord.xy).r + ScreenToDepth.x);\n"
+" position.xy = ModelViewPosition.xy * (position.z / ModelViewPosition.z);\n"
+" // decode viewspace pixel normal\n"
+" myhalf4 normalmap = texture2DRect(Texture_ScreenNormalMap, gl_FragCoord.xy);\n"
+" myhalf fade = 1;\n"
+" myhalf3 surfacenormal = normalmap.rgb * 2 - myhalf3(1,1,1);\n"
+"#ifdef USEFOG\n"
+" // extract fogged brightness from length of surfacenormal (because it was written this way)\n"
+" fade *= length(surfacenormal);\n"
+" surfacenormal = normalize(surfacenormal);\n"
+"#endif\n"
+" // surfacenormal = pixel normal in viewspace\n"
+" // LightVector = pixel to light in viewspace\n"
+" // CubeVector = position in lightspace\n"
+" // eyevector = pixel to view in viewspace\n"
+" vec3 CubeVector = vec3(ViewToLight * vec4(position,1));\n"
+" fade *= myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n"
+"#ifdef USEDIFFUSE\n"
+" // get the light normal\n"
+" myhalf3 diffusenormal = myhalf3(normalize(LightPosition - position));\n"
+" // calculate diffuse shading\n"
+" myhalf diffuse = AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
+"# ifdef USESPECULAR\n"
+" // calculate directional shading\n"
+" vec3 eyevector = position * -1.0;\n"
+"# ifdef USEEXACTSPECULARMATH\n"
+" myhalf specular = SpecularScale * pow(myhalf(max(float(dot(reflect(diffusenormal, surfacenormal), normalize(eyevector)))*-1.0, 0.0)), SpecularPower);\n"
+"# else\n"
+" myhalf3 specularnormal = normalize(diffusenormal + myhalf3(normalize(eyevector)));\n"
+" myhalf specular = SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
+"# endif\n"
+"# else\n"
+" myhalf specular = 0;\n"
+"# endif\n"
+"#else\n"
+" myhalf diffuse = 1;\n"
+" myhalf specular = 0;\n"
"#endif\n"
"\n"
-" vec2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n"
-" //vec2 ScreenTexCoord = (ModelViewProjectionPosition.xy + normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5)).xy * DistortScaleRefractReflect.xy * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
-" vec2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
-" vec2 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5))).xy * DistortScaleRefractReflect.xy;\n"
-" // FIXME temporary hack to detect the case that the reflection\n"
-" // gets blackened at edges due to leaving the area that contains actual\n"
-" // content.\n"
-" // Remove this 'ack once we have a better way to stop this thing from\n"
-" // 'appening.\n"
-" float f = min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.01, 0.01)).rgb) / 0.05);\n"
-" f *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.01, -0.01)).rgb) / 0.05);\n"
-" f *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, 0.01)).rgb) / 0.05);\n"
-" f *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, -0.01)).rgb) / 0.05);\n"
-" ScreenTexCoord = mix(SafeScreenTexCoord, ScreenTexCoord, f);\n"
-" gl_FragColor = texture2D(Texture_Refraction, ScreenTexCoord) * RefractColor;\n"
-"}\n"
+"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAPCUBE) || defined(USESHADOWMAP2D)\n"
+" fade *= ShadowMapCompare(CubeVector);\n"
+"#endif\n"
"\n"
-"#else // !MODE_REFRACTION\n"
+" diffuse *= DeferredDiffuseRange;\n"
+" specular *= DeferredSpecularRange;\n"
+"\n"
+" myhalf3 lightcolor = TintColor.rgb * fade;\n"
+"# ifdef USECUBEFILTER\n"
+" lightcolor *= myhalf3(textureCube(Texture_Cube, CubeVector));\n"
+"# endif\n"
+"\n"
+" gl_FragData[0] = vec4(lightcolor * diffuse, 1.0);\n"
+" gl_FragData[1] = vec4(lightcolor * specular, 1.0);\n"
+"}\n"
+"#else // !MODE_DEFERREDLIGHTSOURCE\n"
+"#ifdef USEDEFERREDLIGHTMAP\n"
+"uniform float DeferredDiffuseRange;\n"
+"uniform float DeferredSpecularRange;\n"
+"#endif\n"
"void main(void)\n"
"{\n"
"#ifdef USEOFFSETMAPPING\n"
" //color = mix(myhalf4(1, 0, 0, 1), color, terrainblend);\n"
"#endif\n"
"\n"
+" // get the surface normal\n"
"#ifdef USEDIFFUSE\n"
-" // get the surface normal and the gloss color\n"
"# ifdef USEVERTEXTEXTUREBLEND\n"
" myhalf3 surfacenormal = normalize(mix(myhalf3(texture2D(Texture_SecondaryNormal, TexCoord2)), myhalf3(texture2D(Texture_Normal, TexCoord)), terrainblend) - myhalf3(0.5, 0.5, 0.5));\n"
-"# ifdef USESPECULAR\n"
-" myhalf3 glosscolor = mix(myhalf3(texture2D(Texture_SecondaryGloss, TexCoord2)), myhalf3(texture2D(Texture_Gloss, TexCoord)), terrainblend);\n"
-"# endif\n"
"# else\n"
" myhalf3 surfacenormal = normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5, 0.5, 0.5));\n"
-"# ifdef USESPECULAR\n"
+"# endif\n"
+"#endif\n"
+"\n"
+" // get the gloss color\n"
+"#if defined(USESPECULAR) || defined(USEDEFERREDLIGHTMAP)\n"
+"# ifdef USEVERTEXTEXTUREBLEND\n"
+" myhalf3 glosscolor = mix(myhalf3(texture2D(Texture_SecondaryGloss, TexCoord2)), myhalf3(texture2D(Texture_Gloss, TexCoord)), terrainblend);\n"
+"# else\n"
" myhalf3 glosscolor = myhalf3(texture2D(Texture_Gloss, TexCoord));\n"
-"# endif\n"
"# endif\n"
"#endif\n"
"\n"
+"#ifdef USEDEFERREDLIGHTMAP\n"
+" myhalf3 deferredcolor = color.rgb * myhalf3(texture2DRect(Texture_ScreenDiffuse, gl_FragCoord.xy)) * DeferredDiffuseRange + glosscolor.rgb * myhalf3(texture2DRect(Texture_ScreenSpecular, gl_FragCoord.xy)) * DeferredSpecularRange;\n"
+"#endif\n"
+"\n"
"\n"
"\n"
"#ifdef MODE_LIGHTSOURCE\n"
"\n"
"\n"
"\n"
+"\n"
+"\n"
+"\n"
+"\n"
" color *= TintColor;\n"
"\n"
"#ifdef USEGLOW\n"
"\n"
" // apply fog after Contrastboost/SceneBrightness because its color is already modified appropriately\n"
"#ifdef USEFOG\n"
-" float fogfrac;\n"
-"#ifdef USEFOGOUTSIDE\n"
-" fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0, min(0.0, FogPlaneVertexDist) * FogHeightFade);\n"
-"#else\n"
-" fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist)) * min(1.0, (min(0.0, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);\n"
+" color.rgb = mix(FogColor, color.rgb, FogVertex());\n"
"#endif\n"
-"// float FogHeightFade1 = -0.5/1024.0;\n"
-"// if (FogPlaneViewDist >= 0.0)\n"
-"// fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0, min(0.0, FogPlaneVertexDist) * FogHeightFade1);\n"
-"// else\n"
-"// fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist)) * min(1.0, (min(0.0, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade1);\n"
-"//# ifdef USEFOGABOVE\n"
-"// if (FogPlaneViewDist >= 0.0)\n"
-"// fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist);\n"
-"// else\n"
-"// fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist));\n"
-"// fogfrac *= min(1.0, (min(0.0, FogPlaneVertexDist) + min(0.0, FogPlaneViewDist))*FogHeightFade1);\n"
-"// fogfrac *= min(1.0, (max(0.0, fade*FogPlaneVertexDist) + max(0.0, fade*FogPlaneViewDist)));\n"
-"// fogfrac *= min(1.0, (max(0.0, FogHeightFade1*FogPlaneVertexDist) + max(0.0, FogHeightFade1*FogPlaneViewDist)));\n"
-"// fogfrac *= min(1.0, (min(0.0, FogPlaneVertexDist) + min(0.0, FogPlaneViewDist))*FogHeightFade1);\n"
-"\n"
-" //fogfrac *= min(1.0, max(0.0, (max(-2048, min(0, FogPlaneVertexDist)) + max(-2048, min(0, FogPlaneViewDist)))/-2048.0));\n"
-" //float fade = -0.5/128.0;\n"
-" //fogfrac *= max(0.0, min(1.0, fade*FogPlaneVertexDist)) + max(0.0, min(1.0, fade*FogPlaneViewDist));\n"
-" //fogfrac *= max(0.0, min(1.0, FogHeightFade1*FogPlaneVertexDist)) + max(0.0, min(1.0, FogHeightFade1*FogPlaneViewDist));\n"
-" //fogfrac *= min(1.0, max(0.0, FogHeightFade1*FogPlaneVertexDist)) + min(1.0, max(0.0, FogHeightFade1*FogPlaneViewDist));\n"
-" //fogfrac *= min(1.0, max(0.0, FogHeightFade1*FogPlaneVertexDist) + max(0.0, FogHeightFade1*FogPlaneViewDist));\n"
-" //fogfrac *= min(1.0, min(1.0, max(0.0, FogHeightFade1*FogPlaneVertexDist)) + min(1.0, max(0.0, FogHeightFade1*FogPlaneViewDist)));\n"
-" //fogfrac *= min(1.0, max(0.0, FogHeightFade1*FogPlaneVertexDist) + max(0.0, FogHeightFade1*FogPlaneViewDist));\n"
-" //fogfrac *= min(1.0, (min(0.0, FogPlaneVertexDist) + min(0.0, FogPlaneViewDist)) * FogHeightFade1);\n"
-" //fogfrac *= min(1.0, (min(0.0, FogPlaneVertexDist) + min(0.0, FogPlaneViewDist)) * FogHeightFade1);\n"
-"//# endif\n"
-" color.rgb = mix(FogColor, color.rgb, myhalf(texture2D(Texture_FogMask, myhalf2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0))));\n"
+"\n"
+"#ifdef USEDEFERREDLIGHTMAP\n"
+" color.rgb += deferredcolor;\n"
"#endif\n"
"\n"
" // reflection must come last because it already contains exactly the correct fog (the reflection render preserves camera distance from the plane, it only flips the side) and ContrastBoost/SceneBrightness\n"
"\n"
" gl_FragColor = vec4(color);\n"
"\n"
+"#ifdef MODE_LIGHTSOURCE\n"
"#if showshadowmap\n"
"# ifdef USESHADOWMAPRECT\n"
"# ifdef USESHADOWSAMPLER\n"
"# endif\n"
"# endif\n"
"#endif\n"
+"#endif // !MODE_LIGHTSOURCE\n"
"}\n"
-"#endif // !MODE_REFRACTION\n"
-"#endif // !MODE_WATER\n"
+"#endif // !MODE_DEFERREDLIGHTSOURCE\n"
+"#endif // !MODE_DEFERREDGEOMETRY\n"
"\n"
"#endif // FRAGMENT_SHADER\n"
"\n"
+"#endif // !MODE_WATER\n"
+"#endif // !MODE_REFRACTION\n"
"#endif // !MODE_BLOOMBLUR\n"
"#endif // !MODE_GENERIC\n"
"#endif // !MODE_POSTPROCESS\n"
SHADERPERMUTATION_SHADOWMAPPCF2 = 1<<21, ///< (lightsource) use higher quality percentage closer filtering on shadowmap test results
SHADERPERMUTATION_SHADOWSAMPLER = 1<<22, ///< (lightsource) use hardware shadowmap test
SHADERPERMUTATION_SHADOWMAPVSDCT = 1<<23, ///< (lightsource) use virtual shadow depth cube texture for shadowmap indexing
- SHADERPERMUTATION_LIMIT = 1<<24, ///< size of permutations array
- SHADERPERMUTATION_COUNT = 24 ///< size of shaderpermutationinfo array
+ SHADERPERMUTATION_DEFERREDLIGHTMAP = 1<<24, ///< (lightmap) read Texture_ScreenDiffuse/Specular textures and add them on top of lightmapping
+ SHADERPERMUTATION_LIMIT = 1<<25, ///< size of permutations array
+ SHADERPERMUTATION_COUNT = 25 ///< size of shaderpermutationinfo array
}
shaderpermutation_t;
{"#define USESHADOWMAPPCF 2\n", " shadowmappcf2"},
{"#define USESHADOWSAMPLER\n", " shadowsampler"},
{"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"},
+ {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
};
/// this enum is multiplied by SHADERPERMUTATION_MODEBASE
SHADERMODE_REFRACTION, ///< refract background (the material is rendered normally after this pass)
SHADERMODE_WATER, ///< refract background and reflection (the material is rendered normally after this pass)
SHADERMODE_SHOWDEPTH, ///< (debugging) renders depth as color
+ SHADERMODE_DEFERREDGEOMETRY, ///< (deferred) render material properties to screenspace geometry buffers
+ SHADERMODE_DEFERREDLIGHTSOURCE, ///< (deferred) use directional pixel shading from light source (rtlight) on screenspace geometry buffers
SHADERMODE_COUNT
}
shadermode_t;
{"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_REFRACTION\n", " refraction"},
{"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_WATER\n", " water"},
{"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_SHOWDEPTH\n", " showdepth"},
+ {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
+ {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
};
struct r_glsl_permutation_s;
int loc_Texture_ShadowMapCube;
int loc_Texture_ShadowMap2D;
int loc_Texture_CubeProjection;
+ int loc_Texture_ScreenDepth;
+ int loc_Texture_ScreenNormalMap;
+ int loc_Texture_ScreenDiffuse;
+ int loc_Texture_ScreenSpecular;
int loc_FogColor;
int loc_LightPosition;
int loc_EyePosition;
int loc_Saturation;
int loc_ShadowMap_TextureScale;
int loc_ShadowMap_Parameters;
+ int loc_ScreenToDepth;
+ int loc_ViewToLight;
+ int loc_DeferredDiffuseRange;
+ int loc_DeferredSpecularRange;
}
r_glsl_permutation_t;
if (shaderstring)
{
if (printfromdisknotice)
- Con_DPrint("from disk... ");
+ Con_DPrintf("from disk %s... ", filename);
return shaderstring;
}
else if (!strcmp(filename, "glsl/default.glsl"))
p->loc_Texture_ShadowMapRect = qglGetUniformLocationARB(p->program, "Texture_ShadowMapRect");
p->loc_Texture_ShadowMapCube = qglGetUniformLocationARB(p->program, "Texture_ShadowMapCube");
p->loc_Texture_ShadowMap2D = qglGetUniformLocationARB(p->program, "Texture_ShadowMap2D");
- p->loc_Texture_CubeProjection = qglGetUniformLocationARB(p->program, "Texture_CubeProjection");
+ p->loc_Texture_CubeProjection = qglGetUniformLocationARB(p->program, "Texture_CubeProjection");
+ p->loc_Texture_ScreenDepth = qglGetUniformLocationARB(p->program, "Texture_ScreenDepth");
+ p->loc_Texture_ScreenNormalMap = qglGetUniformLocationARB(p->program, "Texture_ScreenNormalMap");
+ p->loc_Texture_ScreenDiffuse = qglGetUniformLocationARB(p->program, "Texture_ScreenDiffuse");
+ p->loc_Texture_ScreenSpecular = qglGetUniformLocationARB(p->program, "Texture_ScreenSpecular");
p->loc_FogColor = qglGetUniformLocationARB(p->program, "FogColor");
p->loc_LightPosition = qglGetUniformLocationARB(p->program, "LightPosition");
p->loc_EyePosition = qglGetUniformLocationARB(p->program, "EyePosition");
p->loc_Saturation = qglGetUniformLocationARB(p->program, "Saturation");
p->loc_ShadowMap_TextureScale = qglGetUniformLocationARB(p->program, "ShadowMap_TextureScale");
p->loc_ShadowMap_Parameters = qglGetUniformLocationARB(p->program, "ShadowMap_Parameters");
+ p->loc_ScreenToDepth = qglGetUniformLocationARB(p->program, "ScreenToDepth");
+ p->loc_ViewToLight = qglGetUniformLocationARB(p->program, "ViewToLight");
+ p->loc_DeferredDiffuseRange = qglGetUniformLocationARB(p->program, "DeferredDiffuseRange");
+ p->loc_DeferredSpecularRange = qglGetUniformLocationARB(p->program, "DeferredSpecularRange");
// initialize the samplers to refer to the texture units we use
if (p->loc_Texture_First >= 0) qglUniform1iARB(p->loc_Texture_First , GL20TU_FIRST);
if (p->loc_Texture_Second >= 0) qglUniform1iARB(p->loc_Texture_Second , GL20TU_SECOND);
if (p->loc_Texture_ShadowMapCube >= 0) qglUniform1iARB(p->loc_Texture_ShadowMapCube , GL20TU_SHADOWMAPCUBE);
if (p->loc_Texture_ShadowMap2D >= 0) qglUniform1iARB(p->loc_Texture_ShadowMap2D , GL20TU_SHADOWMAP2D);
if (p->loc_Texture_CubeProjection >= 0) qglUniform1iARB(p->loc_Texture_CubeProjection , GL20TU_CUBEPROJECTION);
+ if (p->loc_Texture_ScreenDepth >= 0) qglUniform1iARB(p->loc_Texture_ScreenDepth , GL20TU_SCREENDEPTH);
+ if (p->loc_Texture_ScreenNormalMap >= 0) qglUniform1iARB(p->loc_Texture_ScreenNormalMap, GL20TU_SCREENNORMALMAP);
+ if (p->loc_Texture_ScreenDiffuse >= 0) qglUniform1iARB(p->loc_Texture_ScreenDiffuse , GL20TU_SCREENDIFFUSE);
+ if (p->loc_Texture_ScreenSpecular >= 0) qglUniform1iARB(p->loc_Texture_ScreenSpecular , GL20TU_SCREENSPECULAR);
CHECKGLERROR
if (developer.integer)
- Con_Printf("GLSL shader %s compiled.\n", permutationname);
+ Con_Printf("^5GLSL shader %s compiled.\n", permutationname);
}
else
- Con_Printf("GLSL shader %s failed! some features may not work properly.\n", permutationname);
+ Con_Printf("^1GLSL shader %s failed! some features may not work properly.\n", permutationname);
// free the strings
if (vertexstring)
}
if (i >= SHADERPERMUTATION_COUNT)
{
- Con_Printf("OpenGL 2.0 shaders disabled - unable to find a working shader permutation fallback on this driver (set r_glsl 1 if you want to try again)\n");
- Cvar_SetValueQuick(&r_glsl, 0);
- R_GLSL_Restart_f(); // unload shaders
- return; // no bit left to clear
+ //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].vertexfilename, shadermodeinfo[mode].pretext);
+ r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
+ qglUseProgramObjectARB(0);CHECKGLERROR
+ return; // no bit left to clear, entire mode is broken
}
}
}
void R_SetupGenericShader(qboolean usetexture)
{
- if (gl_support_fragment_shader)
- {
- if (r_glsl.integer && r_glsl_usegeneric.integer)
- R_SetupShader_SetPermutation(SHADERMODE_GENERIC, usetexture ? SHADERPERMUTATION_DIFFUSE : 0);
- else if (r_glsl_permutation)
- {
- r_glsl_permutation = NULL;
- qglUseProgramObjectARB(0);CHECKGLERROR
- }
- }
-}
-
-void R_SetupGenericTwoTextureShader(int texturemode)
-{
- if (gl_support_fragment_shader)
+ switch(vid.renderpath)
{
- if (r_glsl.integer && r_glsl_usegeneric.integer)
- R_SetupShader_SetPermutation(SHADERMODE_GENERIC, SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | (r_shadow_glossexact.integer ? SHADERPERMUTATION_EXACTSPECULARMATH : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
- else if (r_glsl_permutation)
- {
- r_glsl_permutation = NULL;
- qglUseProgramObjectARB(0);CHECKGLERROR
- }
+ case RENDERPATH_GL20:
+ R_SetupShader_SetPermutation(SHADERMODE_GENERIC, usetexture ? SHADERPERMUTATION_DIFFUSE : 0);
+ break;
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL11:
+ break;
}
- if (!r_glsl_permutation)
+}
+
+void R_SetupGenericTwoTextureShader(int texturemode)
+{
+ switch (vid.renderpath)
{
- if (texturemode == GL_DECAL && gl_combine.integer)
- texturemode = GL_INTERPOLATE_ARB;
- R_Mesh_TexCombine(1, texturemode, texturemode, 1, 1);
+ case RENDERPATH_GL20:
+ R_SetupShader_SetPermutation(SHADERMODE_GENERIC, SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | (r_shadow_glossexact.integer ? SHADERPERMUTATION_EXACTSPECULARMATH : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
+ break;
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL11:
+ R_Mesh_TexCombine(1, GL_DECAL, GL_DECAL, 1, 1);
+ break;
}
}
void R_SetupDepthOrShadowShader(void)
{
- if (gl_support_fragment_shader)
+ switch (vid.renderpath)
{
- if (r_glsl.integer && r_glsl_usegeneric.integer)
- R_SetupShader_SetPermutation(SHADERMODE_DEPTH_OR_SHADOW, 0);
- else if (r_glsl_permutation)
- {
- r_glsl_permutation = NULL;
- qglUseProgramObjectARB(0);CHECKGLERROR
- }
+ case RENDERPATH_GL20:
+ R_SetupShader_SetPermutation(SHADERMODE_DEPTH_OR_SHADOW, 0);
+ break;
+ case RENDERPATH_GL13:
+ break;
+ case RENDERPATH_GL11:
+ break;
}
}
void R_SetupShowDepthShader(void)
{
- if (gl_support_fragment_shader)
+ switch (vid.renderpath)
{
- if (r_glsl.integer && r_glsl_usegeneric.integer)
- R_SetupShader_SetPermutation(SHADERMODE_SHOWDEPTH, 0);
- else if (r_glsl_permutation)
- {
- r_glsl_permutation = NULL;
- qglUseProgramObjectARB(0);CHECKGLERROR
- }
+ case RENDERPATH_GL20:
+ R_SetupShader_SetPermutation(SHADERMODE_SHOWDEPTH, 0);
+ break;
+ case RENDERPATH_GL13:
+ break;
+ case RENDERPATH_GL11:
+ break;
}
}
+extern qboolean r_shadow_usingdeferredprepass;
+extern cvar_t r_shadow_deferred_8bitrange;
extern rtexture_t *r_shadow_attenuationgradienttexture;
extern rtexture_t *r_shadow_attenuation2dtexture;
extern rtexture_t *r_shadow_attenuation3dtexture;
else
mode = SHADERMODE_REFRACTION;
}
+ else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
+ {
+ // normalmap (deferred prepass), may use alpha test on diffuse
+ mode = SHADERMODE_DEFERREDGEOMETRY;
+ if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
+ permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
+ if (r_refdef.fogenabled)
+ permutation |= r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE;
+ if (r_glsl_offsetmapping.integer)
+ {
+ permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+ if (r_glsl_offsetmapping_reliefmapping.integer)
+ permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+ }
+ }
else if (rsurfacepass == RSURFPASS_RTLIGHT)
{
// light source
- mode = SHADERMODE_LIGHTSOURCE;
+ mode = r_shadow_usingdeferredprepass ? SHADERMODE_DEFERREDLIGHTSOURCE : SHADERMODE_LIGHTSOURCE;
if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
permutation |= SHADERPERMUTATION_COLORMAPPING;
if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
permutation |= SHADERPERMUTATION_REFLECTION;
+ if (r_shadow_usingdeferredprepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
+ permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
}
else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
{
permutation |= SHADERPERMUTATION_COLORMAPPING;
if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
permutation |= SHADERPERMUTATION_REFLECTION;
+ if (r_shadow_usingdeferredprepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
+ permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
}
else
{
permutation |= SHADERPERMUTATION_COLORMAPPING;
if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
permutation |= SHADERPERMUTATION_REFLECTION;
+ if (r_shadow_usingdeferredprepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
+ permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
}
if(permutation & SHADERPERMUTATION_SPECULAR)
if(r_shadow_glossexact.integer)
permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
R_SetupShader_SetPermutation(mode, permutation);
- if (mode == SHADERMODE_LIGHTSOURCE)
+ if (mode == SHADERMODE_DEFERREDLIGHTSOURCE)
+ {
+ // this is the location of the light in view space
+ vec3_t viewlightorigin;
+ // this transforms from view space (camera) to light space (cubemap)
+ matrix4x4_t viewtolight;
+ matrix4x4_t lighttoview;
+ float viewtolight16f[16];
+ Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rsurface.rtlight->shadoworigin, viewlightorigin);
+ Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rsurface.rtlight->matrix_lighttoworld);
+ Matrix4x4_Invert_Simple(&viewtolight, &lighttoview);
+ Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
+ if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightPosition, viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
+ if (r_glsl_permutation->loc_ViewToLight >= 0) qglUniformMatrix4fvARB(r_glsl_permutation->loc_ViewToLight, 1, false, viewtolight16f);
+ if (permutation & SHADERPERMUTATION_DIFFUSE)
+ {
+ if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2], rsurface.texture->lightmapcolor[3]);
+ if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, ambientscale);
+ if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, diffusescale);
+ if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, specularscale);
+ }
+ else
+ {
+ // ambient only is simpler
+ if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, lightcolorbase[0] * ambientscale, lightcolorbase[1] * ambientscale, lightcolorbase[2] * ambientscale, rsurface.texture->lightmapcolor[3]);
+ if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, 1);
+ if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, 0);
+ if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, 0);
+ }
+ // additive passes are only darkened by fog, not tinted
+ if (r_glsl_permutation->loc_FogColor >= 0)
+ qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
+ if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform2fARB(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
+ if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4fARB(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+ if (r_glsl_permutation->loc_DeferredDiffuseRange >= 0) qglUniform1fARB(r_glsl_permutation->loc_DeferredDiffuseRange, 1.0f / r_shadow_deferred_8bitrange.value);
+ if (r_glsl_permutation->loc_DeferredSpecularRange >= 0) qglUniform1fARB(r_glsl_permutation->loc_DeferredSpecularRange, 1.0f / r_shadow_deferred_8bitrange.value);
+ }
+ else if (mode == SHADERMODE_LIGHTSOURCE)
{
if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
if (permutation & SHADERPERMUTATION_DIFFUSE)
if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4fvARB(r_glsl_permutation->loc_ReflectColor, 1, rsurface.texture->reflectcolor4f);
if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin);
if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectOffset, rsurface.texture->reflectmin);
+ if (r_glsl_permutation->loc_DeferredDiffuseRange >= 0) qglUniform1fARB(r_glsl_permutation->loc_DeferredDiffuseRange, r_shadow_deferred_8bitrange.value * r_refdef.view.colorscale);
+ if (r_glsl_permutation->loc_DeferredSpecularRange >= 0) qglUniform1fARB(r_glsl_permutation->loc_DeferredSpecularRange, r_shadow_deferred_8bitrange.value * r_refdef.view.colorscale * specularscale);
}
if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_refdef.view.colorscale);
if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower);
}
if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value);
+ if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2fARB(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
CHECKGLERROR
}
skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
}
-skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int textureflags, qboolean complain, qboolean *has_alpha)
+skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain)
{
- // FIXME: it should be possible to disable loading various layers using
- // cvars, to prevent wasted loading time and memory usage if the user does
- // not want them
- qboolean loadnormalmap = true;
- qboolean loadgloss = true;
- qboolean loadpantsandshirt = true;
- qboolean loadglow = true;
int j;
unsigned char *pixels;
unsigned char *bumppixels;
int basepixels_height;
skinframe_t *skinframe;
- if (has_alpha)
- *has_alpha = false;
-
if (cls.state == ca_dedicated)
return NULL;
skinframe->gloss = NULL;
skinframe->glow = NULL;
skinframe->fog = NULL;
+ skinframe->hasalpha = false;
basepixels_width = image_width;
basepixels_height = image_height;
if (textureflags & TEXF_ALPHA)
{
for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
+ {
if (basepixels[j] < 255)
+ {
+ skinframe->hasalpha = true;
break;
- if (j < basepixels_width * basepixels_height * 4)
+ }
+ }
+ if (r_loadfog && skinframe->hasalpha)
{
// has transparent pixels
- if (has_alpha)
- *has_alpha = true;
pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
for (j = 0;j < image_width * image_height * 4;j += 4)
{
//Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
// _norm is the name used by tenebrae and has been adopted as standard
- if (loadnormalmap)
+ if (r_loadnormalmap)
{
if ((pixels = loadimagepixelsbgra(va("%s_norm", skinframe->basename), false, false)) != NULL)
{
// _luma is supported for tenebrae compatibility
// (I think it's a very stupid name, but oh well)
// _glow is the preferred name
- if (loadglow && ((pixels = loadimagepixelsbgra(va("%s_glow", skinframe->basename), false, false)) != NULL || (pixels = loadimagepixelsbgra(va("%s_luma", skinframe->basename), false, false)) != NULL)) {skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%s_glow", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_glow.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
- if (loadgloss && (pixels = loadimagepixelsbgra(va("%s_gloss", skinframe->basename), false, false)) != NULL) {skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%s_gloss", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_gloss.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
- if (loadpantsandshirt && (pixels = loadimagepixelsbgra(va("%s_pants", skinframe->basename), false, false)) != NULL) {skinframe->pants = R_LoadTexture2D (r_main_texturepool, va("%s_pants", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
- if (loadpantsandshirt && (pixels = loadimagepixelsbgra(va("%s_shirt", skinframe->basename), false, false)) != NULL) {skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va("%s_shirt", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
+ if ((pixels = loadimagepixelsbgra(va("%s_glow", skinframe->basename), false, false)) || (pixels = loadimagepixelsbgra(va("%s_luma", skinframe->basename), false, false))) {skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%s_glow", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_glow.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
+ if (r_loadgloss && (pixels = loadimagepixelsbgra(va("%s_gloss", skinframe->basename), false, false))) {skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%s_gloss", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_gloss.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
+ if ((pixels = loadimagepixelsbgra(va("%s_pants", skinframe->basename), false, false))) {skinframe->pants = R_LoadTexture2D (r_main_texturepool, va("%s_pants", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
+ if ((pixels = loadimagepixelsbgra(va("%s_shirt", skinframe->basename), false, false))) {skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va("%s_shirt", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
if (basepixels)
Mem_Free(basepixels);
return skinframe;
}
-skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain)
-{
- return R_SkinFrame_LoadExternal_CheckAlpha(name, textureflags, complain, NULL);
-}
-
-static rtexture_t *R_SkinFrame_TextureForSkinLayer(const unsigned char *in, int width, int height, const char *name, const unsigned int *palette, int textureflags, qboolean force)
-{
- int i;
- if (!force)
- {
- for (i = 0;i < width*height;i++)
- if (((unsigned char *)&palette[in[i]])[3] > 0)
- break;
- if (i == width*height)
- return NULL;
- }
- return R_LoadTexture2D (r_main_texturepool, name, width, height, in, TEXTYPE_PALETTE, textureflags, palette);
-}
-
// this is only used by .spr32 sprites, HL .spr files, HL .bsp files
skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height)
{
skinframe->gloss = NULL;
skinframe->glow = NULL;
skinframe->fog = NULL;
+ skinframe->hasalpha = false;
// if no data was provided, then clearly the caller wanted to get a blank skinframe
if (!skindata)
if (developer_loading.integer)
Con_Printf("loading 32bit skin \"%s\"\n", name);
- if (r_shadow_bumpscale_basetexture.value > 0)
+ if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
{
temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
temp2 = temp1 + width * height * 4;
if (textureflags & TEXF_ALPHA)
{
for (i = 3;i < width * height * 4;i += 4)
+ {
if (skindata[i] < 255)
+ {
+ skinframe->hasalpha = true;
break;
- if (i < width * height * 4)
+ }
+ }
+ if (r_loadfog && skinframe->hasalpha)
{
unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
memcpy(fogpixels, skindata, width * height * 4);
skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
{
int i;
- unsigned char *temp1, *temp2;
- unsigned int *palette;
+ int featuresmask;
skinframe_t *skinframe;
if (cls.state == ca_dedicated)
if (skinframe && skinframe->base)
return skinframe;
- palette = (loadglowtexture ? palette_bgra_nofullbrights : ((skinframe->textureflags & TEXF_ALPHA) ? palette_bgra_transparent : palette_bgra_complete));
-
skinframe->stain = NULL;
skinframe->merged = NULL;
skinframe->base = r_texture_notexture;
skinframe->gloss = NULL;
skinframe->glow = NULL;
skinframe->fog = NULL;
+ skinframe->hasalpha = false;
// if no data was provided, then clearly the caller wanted to get a blank skinframe
if (!skindata)
if (developer_loading.integer)
Con_Printf("loading quake skin \"%s\"\n", name);
- if (r_shadow_bumpscale_basetexture.value > 0)
+ // we actually don't upload anything until the first use, because mdl skins frequently go unused, and are almost never used in both modes (colormapped and non-colormapped)
+ skinframe->qpixels = Mem_Alloc(r_main_mempool, width*height);
+ memcpy(skinframe->qpixels, skindata, width*height);
+ skinframe->qwidth = width;
+ skinframe->qheight = height;
+
+ featuresmask = 0;
+ for (i = 0;i < width * height;i++)
+ featuresmask |= palette_featureflags[skindata[i]];
+
+ skinframe->hasalpha = false;
+ skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
+ skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
+ skinframe->qgeneratemerged = true;
+ skinframe->qgeneratebase = skinframe->qhascolormapping;
+ skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
+
+ R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
+ //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
+
+ return skinframe;
+}
+
+static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
+{
+ int width;
+ int height;
+ unsigned char *skindata;
+
+ if (!skinframe->qpixels)
+ return;
+
+ if (!skinframe->qhascolormapping)
+ colormapped = false;
+
+ if (colormapped)
+ {
+ if (!skinframe->qgeneratebase)
+ return;
+ }
+ else
+ {
+ if (!skinframe->qgeneratemerged)
+ return;
+ }
+
+ width = skinframe->qwidth;
+ height = skinframe->qheight;
+ skindata = skinframe->qpixels;
+
+ if (skinframe->qgeneratenmap)
{
+ unsigned char *temp1, *temp2;
+ skinframe->qgeneratenmap = false;
temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
temp2 = temp1 + width * height * 4;
// use either a custom palette or the quake palette
skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, skinframe->textureflags | TEXF_ALPHA, NULL);
Mem_Free(temp1);
}
- // use either a custom palette, or the quake palette
- skinframe->base = skinframe->merged = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_merged", skinframe->basename), palette, skinframe->textureflags, true); // all
- if (loadglowtexture)
- skinframe->glow = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_glow", skinframe->basename), palette_bgra_onlyfullbrights, skinframe->textureflags, false); // glow
- if (loadpantsandshirt)
+
+ if (skinframe->qgenerateglow)
+ {
+ skinframe->qgenerateglow = false;
+ skinframe->glow = R_LoadTexture2D(r_main_texturepool, va("%s_glow", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, skinframe->textureflags, palette_bgra_onlyfullbrights); // glow
+ }
+
+ if (colormapped)
{
- skinframe->pants = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_pants", skinframe->basename), palette_bgra_pantsaswhite, skinframe->textureflags, false); // pants
- skinframe->shirt = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_shirt", skinframe->basename), palette_bgra_shirtaswhite, skinframe->textureflags, false); // shirt
+ skinframe->qgeneratebase = false;
+ skinframe->base = R_LoadTexture2D(r_main_texturepool, va("%s_nospecial", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, skinframe->textureflags, skinframe->glow ? palette_bgra_nocolormapnofullbrights : palette_bgra_nocolormap);
+ skinframe->pants = R_LoadTexture2D(r_main_texturepool, va("%s_pants", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, skinframe->textureflags, palette_bgra_pantsaswhite);
+ skinframe->shirt = R_LoadTexture2D(r_main_texturepool, va("%s_shirt", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, skinframe->textureflags, palette_bgra_shirtaswhite);
}
- if (skinframe->pants || skinframe->shirt)
- skinframe->base = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_nospecial", skinframe->basename), loadglowtexture ? palette_bgra_nocolormapnofullbrights : palette_bgra_nocolormap, skinframe->textureflags, false); // no special colors
- if (textureflags & TEXF_ALPHA)
+ else
{
- for (i = 0;i < width * height;i++)
- if (((unsigned char *)palette_bgra_alpha)[skindata[i]*4+3] < 255)
- break;
- if (i < width * height)
- skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), palette_bgra_alpha, skinframe->textureflags, true); // fog mask
+ skinframe->qgeneratemerged = false;
+ skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, skinframe->textureflags, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete);
}
- R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
- //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
-
- return skinframe;
+ if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
+ {
+ Mem_Free(skinframe->qpixels);
+ skinframe->qpixels = NULL;
+ }
}
skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette)
skinframe->gloss = NULL;
skinframe->glow = NULL;
skinframe->fog = NULL;
+ skinframe->hasalpha = false;
// if no data was provided, then clearly the caller wanted to get a blank skinframe
if (!skindata)
if (developer_loading.integer)
Con_Printf("loading embedded 8bit image \"%s\"\n", name);
- skinframe->base = skinframe->merged = R_SkinFrame_TextureForSkinLayer(skindata, width, height, skinframe->basename, palette, skinframe->textureflags, true);
+ skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, skinframe->textureflags, palette);
if (textureflags & TEXF_ALPHA)
{
for (i = 0;i < width * height;i++)
- if (((unsigned char *)alphapalette)[skindata[i]*4+3] < 255)
+ {
+ if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
+ {
+ skinframe->hasalpha = true;
break;
- if (i < width * height)
- skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), alphapalette, skinframe->textureflags, true); // fog mask
+ }
+ }
+ if (r_loadfog && skinframe->hasalpha)
+ skinframe->fog = R_LoadTexture2D(r_main_texturepool, va("%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, skinframe->textureflags, alphapalette);
}
R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
skinframe->gloss = NULL;
skinframe->glow = NULL;
skinframe->fog = NULL;
+ skinframe->hasalpha = false;
skinframe->avgcolor[0] = rand() / RAND_MAX;
skinframe->avgcolor[1] = rand() / RAND_MAX;
{
int numentities = r_refdef.scene.numentities;
int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
- int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1
+ int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
if (r_refdef.viewcache.maxentities < numentities)
if (r_refdef.viewcache.world_numclusters != numclusters)
{
r_refdef.viewcache.world_numclusters = numclusters;
+ r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
if (r_refdef.viewcache.world_pvsbits)
Mem_Free(r_refdef.viewcache.world_pvsbits);
r_refdef.viewcache.world_pvsbits = Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
}
}
+extern rtexture_t *loadingscreentexture;
void gl_main_start(void)
{
+ loadingscreentexture = NULL;
+ r_texture_blanknormalmap = NULL;
+ r_texture_white = NULL;
+ r_texture_grey128 = NULL;
+ r_texture_black = NULL;
+ r_texture_whitecube = NULL;
+ r_texture_normalizationcube = NULL;
+ r_texture_fogattenuation = NULL;
+ r_texture_gammaramps = NULL;
+
+ switch(vid.renderpath)
+ {
+ case RENDERPATH_GL20:
+ Cvar_SetValueQuick(&r_textureunits, vid.texunits);
+ Cvar_SetValueQuick(&gl_combine, 1);
+ Cvar_SetValueQuick(&r_glsl, 1);
+ r_loadnormalmap = true;
+ r_loadgloss = true;
+ r_loadfog = false;
+ break;
+ case RENDERPATH_GL13:
+ Cvar_SetValueQuick(&r_textureunits, vid.texunits);
+ Cvar_SetValueQuick(&gl_combine, 1);
+ Cvar_SetValueQuick(&r_glsl, 0);
+ r_loadnormalmap = false;
+ r_loadgloss = false;
+ r_loadfog = true;
+ break;
+ case RENDERPATH_GL11:
+ Cvar_SetValueQuick(&r_textureunits, vid.texunits);
+ Cvar_SetValueQuick(&gl_combine, 0);
+ Cvar_SetValueQuick(&r_glsl, 0);
+ r_loadnormalmap = false;
+ r_loadgloss = false;
+ r_loadfog = true;
+ break;
+ }
+
+ R_AnimCache_Free();
+ R_FrameData_Reset();
+
r_numqueries = 0;
r_maxqueries = 0;
memset(r_queries, 0, sizeof(r_queries));
r_main_texturepool = R_AllocTexturePool();
R_BuildBlankTextures();
R_BuildNoTexture();
- if (gl_texturecubemap)
+ if (vid.support.arb_texture_cube_map)
{
R_BuildWhiteCube();
R_BuildNormalizationCube();
r_refdef.fogmasktable_density = 0;
}
-extern rtexture_t *loadingscreentexture;
void gl_main_shutdown(void)
{
+ R_AnimCache_Free();
+ R_FrameData_Reset();
+
R_Main_FreeViewCache();
if (r_maxqueries)
CL_ParseEntityLump(cl.worldmodel->brush.entities);
}
R_Main_FreeViewCache();
+
+ R_FrameData_Reset();
}
void GL_Main_Init(void)
Cvar_RegisterVariable(&r_equalize_entities_minambient);
Cvar_RegisterVariable(&r_equalize_entities_by);
Cvar_RegisterVariable(&r_equalize_entities_to);
- Cvar_RegisterVariable(&r_animcache);
Cvar_RegisterVariable(&r_depthfirst);
Cvar_RegisterVariable(&r_useinfinitefarclip);
Cvar_RegisterVariable(&r_farclip_base);
Cvar_RegisterVariable(&r_fog_exp2);
Cvar_RegisterVariable(&r_drawfog);
Cvar_RegisterVariable(&r_textureunits);
+ Cvar_RegisterVariable(&gl_combine);
Cvar_RegisterVariable(&r_glsl);
Cvar_RegisterVariable(&r_glsl_deluxemapping);
Cvar_RegisterVariable(&r_glsl_offsetmapping);
Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
- Cvar_RegisterVariable(&r_glsl_usegeneric);
Cvar_RegisterVariable(&r_water);
Cvar_RegisterVariable(&r_water_resolutionmultiplier);
Cvar_RegisterVariable(&r_water_clippingplanebias);
Cvar_RegisterVariable(&r_test);
Cvar_RegisterVariable(&r_batchmode);
Cvar_RegisterVariable(&r_glsl_saturation);
+ Cvar_RegisterVariable(&r_framedatasize);
if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
Cvar_SetValue("r_fullbrights", 0);
R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
//==================================================================================
-// LordHavoc: animcache written by Echon, refactored and reformatted by me
-
-/**
- * Animation cache helps save re-animating a player mesh if it's re-rendered again in a given frame
- * (reflections, lighting, etc). All animation cache becomes invalid on the next frame and is flushed
- * (well, over-wrote). The memory for each cache is kept around to save on allocation thrashing.
- */
+// LordHavoc: this stores temporary data used within the same frame
-typedef struct r_animcache_entity_s
-{
- float *vertex3f;
- float *normal3f;
- float *svector3f;
- float *tvector3f;
- int maxvertices;
- qboolean wantnormals;
- qboolean wanttangents;
-}
-r_animcache_entity_t;
+qboolean r_framedata_failed;
+static size_t r_framedata_size;
+static size_t r_framedata_current;
+static void *r_framedata_base;
-typedef struct r_animcache_s
+void R_FrameData_Reset(void)
{
- r_animcache_entity_t entity[MAX_EDICTS];
- int maxindex;
- int currentindex;
+ if (r_framedata_base);
+ Mem_Free(r_framedata_base);
+ r_framedata_base = NULL;
+ r_framedata_size = 0;
+ r_framedata_current = 0;
+ r_framedata_failed = false;
}
-r_animcache_t;
-static r_animcache_t r_animcachestate;
-
-void R_AnimCache_Free(void)
+void R_FrameData_NewFrame(void)
{
- int idx;
- for (idx=0 ; idx<r_animcachestate.maxindex ; idx++)
+ size_t wantedsize;
+ if (r_framedata_failed)
+ Cvar_SetValueQuick(&r_framedatasize, r_framedatasize.value + 1.0f);
+ wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
+ wantedsize = bound(65536, wantedsize, 128*1024*1024);
+ if (r_framedata_size != wantedsize)
{
- r_animcachestate.entity[idx].maxvertices = 0;
- Mem_Free(r_animcachestate.entity[idx].vertex3f);
- r_animcachestate.entity[idx].vertex3f = NULL;
- r_animcachestate.entity[idx].normal3f = NULL;
- r_animcachestate.entity[idx].svector3f = NULL;
- r_animcachestate.entity[idx].tvector3f = NULL;
+ r_framedata_size = wantedsize;
+ if (r_framedata_base);
+ Mem_Free(r_framedata_base);
+ r_framedata_base = Mem_Alloc(r_main_mempool, r_framedata_size);
}
- r_animcachestate.currentindex = 0;
- r_animcachestate.maxindex = 0;
+ r_framedata_current = 0;
+ r_framedata_failed = false;
}
-void R_AnimCache_ResizeEntityCache(const int cacheIdx, const int numvertices)
+void *R_FrameData_Alloc(size_t size)
{
- int arraySize;
- float *base;
- r_animcache_entity_t *cache = &r_animcachestate.entity[cacheIdx];
-
- if (cache->maxvertices >= numvertices)
- return;
+ void *data;
- // Release existing memory
- if (cache->vertex3f)
- Mem_Free(cache->vertex3f);
+ // align to 16 byte boundary
+ size = (size + 15) & ~15;
+ data = (void *)((unsigned char*)r_framedata_base + r_framedata_current);
+ r_framedata_current += size;
- // Pad by 1024 verts
- cache->maxvertices = (numvertices + 1023) & ~1023;
- arraySize = cache->maxvertices * 3;
+ // check overflow
+ if (r_framedata_current > r_framedata_size)
+ r_framedata_failed = true;
- // Allocate, even if we don't need this memory in this instance it will get ignored and potentially used later
- base = (float *)Mem_Alloc(r_main_mempool, arraySize * sizeof(float) * 4);
- r_animcachestate.entity[cacheIdx].vertex3f = base;
- r_animcachestate.entity[cacheIdx].normal3f = base + arraySize;
- r_animcachestate.entity[cacheIdx].svector3f = base + arraySize*2;
- r_animcachestate.entity[cacheIdx].tvector3f = base + arraySize*3;
+ // return NULL on everything after a failure
+ if (r_framedata_failed)
+ return NULL;
-// Con_Printf("allocated cache for %i (%f KB)\n", cacheIdx, (arraySize*sizeof(float)*4)/1024.0f);
+ return data;
}
-void R_AnimCache_NewFrame(void)
+void *R_FrameData_Store(size_t size, void *data)
{
- int i;
+ void *d = R_FrameData_Alloc(size);
+ if (d)
+ memcpy(d, data, size);
+ return d;
+}
+
+//==================================================================================
+
+// LordHavoc: animcache originally written by Echon, rewritten since then
+
+/**
+ * Animation cache prevents re-generating mesh data for an animated model
+ * multiple times in one frame for lighting, shadowing, reflections, etc.
+ */
- if (r_animcache.integer && r_drawentities.integer)
- r_animcachestate.maxindex = sizeof(r_animcachestate.entity) / sizeof(r_animcachestate.entity[0]);
- else if (r_animcachestate.maxindex)
- R_AnimCache_Free();
+void R_AnimCache_Free(void)
+{
+}
- r_animcachestate.currentindex = 0;
+void R_AnimCache_ClearCache(void)
+{
+ int i;
+ entity_render_t *ent;
for (i = 0;i < r_refdef.scene.numentities;i++)
- r_refdef.scene.entities[i]->animcacheindex = -1;
+ {
+ ent = r_refdef.scene.entities[i];
+ ent->animcache_vertex3f = NULL;
+ ent->animcache_normal3f = NULL;
+ ent->animcache_svector3f = NULL;
+ ent->animcache_tvector3f = NULL;
+ }
}
qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
{
dp_model_t *model = ent->model;
- r_animcache_entity_t *c;
+ int numvertices;
// see if it's already cached this frame
- if (ent->animcacheindex >= 0)
+ if (ent->animcache_vertex3f)
{
// add normals/tangents if needed
- c = r_animcachestate.entity + ent->animcacheindex;
- if (c->wantnormals)
- wantnormals = false;
- if (c->wanttangents)
- wanttangents = false;
if (wantnormals || wanttangents)
- model->AnimateVertices(model, ent->frameblend, NULL, wantnormals ? c->normal3f : NULL, wanttangents ? c->svector3f : NULL, wanttangents ? c->tvector3f : NULL);
+ {
+ if (ent->animcache_normal3f)
+ wantnormals = false;
+ if (ent->animcache_svector3f)
+ wanttangents = false;
+ if (wantnormals || wanttangents)
+ {
+ numvertices = model->surfmesh.num_vertices;
+ if (wantnormals)
+ ent->animcache_normal3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+ if (wanttangents)
+ {
+ ent->animcache_svector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+ ent->animcache_tvector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+ }
+ if (!r_framedata_failed)
+ model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
+ }
+ }
}
else
{
// see if this ent is worth caching
- if (r_animcachestate.maxindex <= r_animcachestate.currentindex)
+ if (!model || !model->Draw || !model->surfmesh.isanimated || !model->AnimateVertices || (ent->frameblend[0].lerp == 1 && ent->frameblend[0].subframe == 0 && !ent->skeleton))
return false;
- if (!model || !model->Draw || !model->surfmesh.isanimated || !model->AnimateVertices || (ent->frameblend[0].lerp == 1 && ent->frameblend[0].subframe == 0))
- return false;
- // assign it a cache entry and make sure the arrays are big enough
- R_AnimCache_ResizeEntityCache(r_animcachestate.currentindex, model->surfmesh.num_vertices);
- ent->animcacheindex = r_animcachestate.currentindex++;
- c = r_animcachestate.entity + ent->animcacheindex;
- c->wantnormals = wantnormals;
- c->wanttangents = wanttangents;
- model->AnimateVertices(model, ent->frameblend, c->vertex3f, wantnormals ? c->normal3f : NULL, wanttangents ? c->svector3f : NULL, wanttangents ? c->tvector3f : NULL);
+ // get some memory for this entity and generate mesh data
+ numvertices = model->surfmesh.num_vertices;
+ ent->animcache_vertex3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+ if (wantnormals)
+ ent->animcache_normal3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+ if (wanttangents)
+ {
+ ent->animcache_svector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+ ent->animcache_tvector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices);
+ }
+ if (!r_framedata_failed)
+ model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
}
- return true;
+ return !r_framedata_failed;
}
void R_AnimCache_CacheVisibleEntities(void)
{
int i;
- qboolean wantnormals;
- qboolean wanttangents;
-
- if (!r_animcachestate.maxindex)
- return;
+ qboolean wantnormals = !r_showsurfaces.integer;
+ qboolean wanttangents = !r_showsurfaces.integer;
- wantnormals = !r_showsurfaces.integer;
- wanttangents = !r_showsurfaces.integer && (r_glsl.integer || r_refdef.scene.rtworld || r_refdef.scene.rtdlight);
+ switch(vid.renderpath)
+ {
+ case RENDERPATH_GL20:
+ break;
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL11:
+ wanttangents = false;
+ break;
+ }
- // TODO: thread this?
+ // TODO: thread this
+ // NOTE: R_PrepareRTLights() also caches entities
for (i = 0;i < r_refdef.scene.numentities;i++)
- {
- if (!r_refdef.viewcache.entityvisible[i])
- continue;
- R_AnimCache_GetEntity(r_refdef.scene.entities[i], wantnormals, wanttangents);
- }
+ if (r_refdef.viewcache.entityvisible[i])
+ R_AnimCache_GetEntity(r_refdef.scene.entities[i], wantnormals, wanttangents);
+
+ if (r_shadows.integer)
+ for (i = 0;i < r_refdef.scene.numentities;i++)
+ if (!r_refdef.viewcache.entityvisible[i])
+ R_AnimCache_GetEntity(r_refdef.scene.entities[i], false, false);
}
//==================================================================================
vec3_t start;
vec3_t end;
dp_model_t *model = r_refdef.scene.worldmodel;
-
+
if (!model || !model->brush.TraceLineOfSight)
return true;
int samples;
entity_render_t *ent;
- if (!r_drawentities.integer)
- return;
-
renderimask = r_refdef.envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : ((chase_active.integer || r_waterstate.renderingscene) ? RENDER_VIEWMODEL : RENDER_EXTERIORMODEL);
if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
{
int i, sky;
entity_render_t *ent;
- if (!r_drawentities.integer)
- return false;
-
sky = false;
for (i = 0;i < r_refdef.scene.numentities;i++)
{
int i;
entity_render_t *ent;
- if (!r_drawentities.integer)
- return;
-
for (i = 0;i < r_refdef.scene.numentities;i++)
{
if (!r_refdef.viewcache.entityvisible[i])
int i;
entity_render_t *ent;
- if (!r_drawentities.integer)
- return;
-
for (i = 0;i < r_refdef.scene.numentities;i++)
{
if (!r_refdef.viewcache.entityvisible[i])
int i;
entity_render_t *ent;
- if (!r_drawentities.integer)
- return;
-
for (i = 0;i < r_refdef.scene.numentities;i++)
{
if (!r_refdef.viewcache.entityvisible[i])
int i;
entity_render_t *ent;
- if (!r_drawentities.integer)
- return;
-
for (i = 0;i < r_refdef.scene.numentities;i++)
{
if (!r_refdef.viewcache.entityvisible[i])
}
}
-static void R_DrawModelDecals_Entity(entity_render_t *ent);
-static void R_DrawModelDecals(void)
-{
- int i;
- entity_render_t *ent;
-
- R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
-
- if (!r_drawentities.integer || r_showsurfaces.integer)
- return;
-
- for (i = 0;i < r_refdef.scene.numentities;i++)
- {
- if (!r_refdef.viewcache.entityvisible[i])
- continue;
- ent = r_refdef.scene.entities[i];
- r_refdef.stats.entities++;
- if (ent->decalsystem.numdecals)
- R_DrawModelDecals_Entity(ent);
- }
-}
-
static void R_View_SetFrustum(void)
{
int i;
if (!r_refdef.view.useperspective)
R_Viewport_InitOrtho(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, -r_refdef.view.ortho_x, -r_refdef.view.ortho_y, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
- else if (gl_stencil && r_useinfinitefarclip.integer)
+ else if (vid.stencil && r_useinfinitefarclip.integer)
R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
else
R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
int waterwidth, waterheight, texturewidth, textureheight;
r_waterstate_waterplane_t *p;
+ if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
+ return;
+
+ switch(vid.renderpath)
+ {
+ case RENDERPATH_GL20:
+ break;
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL11:
+ return;
+ }
+
// set waterwidth and waterheight to the water resolution that will be
// used (often less than the screen resolution for faster rendering)
waterwidth = (int)bound(1, vid.width * r_water_resolutionmultiplier.value, vid.width);
// calculate desired texture sizes
// can't use water if the card does not support the texture size
- if (!r_water.integer || !r_glsl.integer || !gl_support_fragment_shader || waterwidth > gl_max_texture_size || waterheight > gl_max_texture_size || r_showsurfaces.integer)
+ if (!r_water.integer || r_showsurfaces.integer)
texturewidth = textureheight = waterwidth = waterheight = 0;
- else if (gl_support_arb_texture_non_power_of_two)
+ else if (vid.support.arb_texture_non_power_of_two)
{
texturewidth = waterwidth;
textureheight = waterheight;
{
int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
+ switch(vid.renderpath)
+ {
+ case RENDERPATH_GL20:
+ break;
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL11:
+ return;
+ }
+
// set bloomwidth and bloomheight to the bloom resolution that will be
// used (often less than the screen resolution for faster rendering)
r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, vid.height);
r_bloomstate.bloomheight = r_bloomstate.bloomwidth * vid.height / vid.width;
r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, vid.height);
- r_bloomstate.bloomwidth = bound(1, r_bloomstate.bloomwidth, gl_max_texture_size);
- r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, gl_max_texture_size);
+ r_bloomstate.bloomwidth = bound(1, r_bloomstate.bloomwidth, (int)vid.maxtexturesize_2d);
+ r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, (int)vid.maxtexturesize_2d);
// calculate desired texture sizes
- if (gl_support_arb_texture_non_power_of_two)
+ if (vid.support.arb_texture_non_power_of_two)
{
screentexturewidth = r_refdef.view.width;
screentextureheight = r_refdef.view.height;
for (bloomtextureheight = 1;bloomtextureheight < r_bloomstate.bloomheight;bloomtextureheight *= 2);
}
- if ((r_hdr.integer || r_bloom.integer || (!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))) && ((r_bloom_resolution.integer < 4 || r_bloom_blur.value < 1 || r_bloom_blur.value >= 512) || r_refdef.view.width > gl_max_texture_size || r_refdef.view.height > gl_max_texture_size))
+ if ((r_hdr.integer || r_bloom.integer || (!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))) && ((r_bloom_resolution.integer < 4 || r_bloom_blur.value < 1 || r_bloom_blur.value >= 512) || r_refdef.view.width > (int)vid.maxtexturesize_2d || r_refdef.view.height > (int)vid.maxtexturesize_2d))
{
Cvar_SetValueQuick(&r_hdr, 0);
Cvar_SetValueQuick(&r_bloom, 0);
Cvar_SetValueQuick(&r_damageblur, 0);
}
- if (!(r_glsl.integer && (r_glsl_postprocess.integer || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial))) && !r_bloom.integer && !r_hdr.integer && (R_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0)))
+ if (!(r_glsl_postprocess.integer || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial)) && !r_bloom.integer && !r_hdr.integer && (R_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0)))
screentexturewidth = screentextureheight = 0;
if (!r_hdr.integer && !r_bloom.integer)
bloomtexturewidth = bloomtextureheight = 0;
// apply subtract last
// (just like it would be in a GLSL shader)
- if (r_bloom_colorsubtract.value > 0 && gl_support_ext_blend_subtract)
+ if (r_bloom_colorsubtract.value > 0 && vid.support.ext_blend_subtract)
{
GL_BlendFunc(GL_ONE, GL_ZERO);
R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
static void R_BlendView(void)
{
- if (r_bloomstate.texture_screen)
+ unsigned int permutation;
+
+ switch (vid.renderpath)
{
- // make sure the buffer is available
- if (r_bloom_blur.value < 1) { Cvar_SetValueQuick(&r_bloom_blur, 1); }
+ case RENDERPATH_GL20:
+ permutation =
+ (r_bloomstate.texture_bloom ? SHADERPERMUTATION_BLOOM : 0)
+ | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
+ | ((v_glslgamma.value && !vid_gammatables_trivial) ? SHADERPERMUTATION_GAMMARAMPS : 0)
+ | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
+ | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
- R_ResetViewRendering2D();
- R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
- R_Mesh_ColorPointer(NULL, 0, 0);
- R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
- GL_ActiveTexture(0);CHECKGLERROR
-
- if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))
- {
- // declare variables
- float speed;
- static float avgspeed;
-
- speed = VectorLength(cl.movement_velocity);
-
- cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_vcoeff.value), 1);
- avgspeed = avgspeed * (1 - cl.motionbluralpha) + speed * cl.motionbluralpha;
-
- speed = (avgspeed - r_motionblur_vmin.value) / max(1, r_motionblur_vmax.value - r_motionblur_vmin.value);
- speed = bound(0, speed, 1);
- speed = speed * (1 - r_motionblur_bmin.value) + r_motionblur_bmin.value;
-
- // calculate values into a standard alpha
- cl.motionbluralpha = 1 - exp(-
- (
- (r_motionblur.value * speed / 80)
- +
- (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
- )
- /
- max(0.0001, cl.time - cl.oldtime) // fps independent
- );
-
- cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
- cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
- // apply the blur
- if (cl.motionbluralpha > 0)
- {
- R_SetupGenericShader(true);
- GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- GL_Color(1, 1, 1, cl.motionbluralpha);
- R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
- R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
- R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
- r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
- }
- }
+ if (r_bloomstate.texture_screen)
+ {
+ // make sure the buffer is available
+ if (r_bloom_blur.value < 1) { Cvar_SetValueQuick(&r_bloom_blur, 1); }
- // copy view into the screen texture
- qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);CHECKGLERROR
- r_refdef.stats.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
- }
+ R_ResetViewRendering2D();
+ R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
+ R_Mesh_ColorPointer(NULL, 0, 0);
+ R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
+ GL_ActiveTexture(0);CHECKGLERROR
+
+ if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))
+ {
+ // declare variables
+ float speed;
+ static float avgspeed;
+
+ speed = VectorLength(cl.movement_velocity);
+
+ cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_vcoeff.value), 1);
+ avgspeed = avgspeed * (1 - cl.motionbluralpha) + speed * cl.motionbluralpha;
+
+ speed = (avgspeed - r_motionblur_vmin.value) / max(1, r_motionblur_vmax.value - r_motionblur_vmin.value);
+ speed = bound(0, speed, 1);
+ speed = speed * (1 - r_motionblur_bmin.value) + r_motionblur_bmin.value;
+
+ // calculate values into a standard alpha
+ cl.motionbluralpha = 1 - exp(-
+ (
+ (r_motionblur.value * speed / 80)
+ +
+ (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
+ )
+ /
+ max(0.0001, cl.time - cl.oldtime) // fps independent
+ );
+
+ cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
+ cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
+ // apply the blur
+ if (cl.motionbluralpha > 0)
+ {
+ R_SetupGenericShader(true);
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GL_Color(1, 1, 1, cl.motionbluralpha);
+ R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
+ R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
+ R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
+ r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
+ }
+ }
- if (r_glsl.integer && gl_support_fragment_shader && (r_bloomstate.texture_screen || r_bloomstate.texture_bloom))
- {
- unsigned int permutation =
- (r_bloomstate.texture_bloom ? SHADERPERMUTATION_BLOOM : 0)
- | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
- | ((v_glslgamma.value && !vid_gammatables_trivial) ? SHADERPERMUTATION_GAMMARAMPS : 0)
- | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
- | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
+ // copy view into the screen texture
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);CHECKGLERROR
+ r_refdef.stats.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
+ }
+ else if (!r_bloomstate.texture_bloom)
+ break; // no screen processing, no bloom, skip it
if (r_bloomstate.texture_bloom && !r_bloomstate.hdr)
{
qglUniform1fARB(r_glsl_permutation->loc_Saturation, r_glsl_saturation.value);
R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
- return;
- }
-
-
-
- if (r_bloomstate.texture_bloom && r_bloomstate.hdr)
- {
- // render high dynamic range bloom effect
- // the bloom texture was made earlier this render, so we just need to
- // blend it onto the screen...
- R_ResetViewRendering2D();
- R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
- R_Mesh_ColorPointer(NULL, 0, 0);
- R_SetupGenericShader(true);
- GL_Color(1, 1, 1, 1);
- GL_BlendFunc(GL_ONE, GL_ONE);
- R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
- R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
- R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
- r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
- }
- else if (r_bloomstate.texture_bloom)
- {
- // render simple bloom effect
- // copy the screen and shrink it and darken it for the bloom process
- R_Bloom_CopyBloomTexture(r_bloom_colorscale.value);
- // make the bloom texture
- R_Bloom_MakeTexture();
- // put the original screen image back in place and blend the bloom
- // texture on it
- R_ResetViewRendering2D();
- R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
- R_Mesh_ColorPointer(NULL, 0, 0);
- GL_Color(1, 1, 1, 1);
- GL_BlendFunc(GL_ONE, GL_ZERO);
- // do both in one pass if possible
- R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
- R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
- if (r_textureunits.integer >= 2 && gl_combine.integer)
- {
- R_SetupGenericTwoTextureShader(GL_ADD);
- R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_screen));
- R_Mesh_TexCoordPointer(1, 2, r_bloomstate.screentexcoord2f, 0, 0);
- }
- else
+ break;
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL11:
+ if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
{
- R_SetupGenericShader(true);
+ // apply a color tint to the whole view
+ R_ResetViewRendering2D();
+ R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
+ R_Mesh_ColorPointer(NULL, 0, 0);
+ R_SetupGenericShader(false);
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
- r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
- // now blend on the bloom texture
- GL_BlendFunc(GL_ONE, GL_ONE);
- R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
- R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
}
- R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
- r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
- }
- if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
- {
- // apply a color tint to the whole view
- R_ResetViewRendering2D();
- R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
- R_Mesh_ColorPointer(NULL, 0, 0);
- R_SetupGenericShader(false);
- GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
- R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
+ break;
}
}
r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
- r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
+ r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
r_refdef.scene.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer && r_dynamic.integer;
- r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && gl_stencil;
+ r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
r_refdef.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
if (r_showsurfaces.integer)
{
else
r_refdef.fogenabled = false;
- if(r_glsl.integer && v_glslgamma.integer && !vid_gammatables_trivial)
+ switch(vid.renderpath)
{
- if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
+ case RENDERPATH_GL20:
+ if(v_glslgamma.integer && !vid_gammatables_trivial)
{
- // build GLSL gamma texture
+ if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
+ {
+ // build GLSL gamma texture
#define RAMPWIDTH 256
- unsigned short ramp[RAMPWIDTH * 3];
- unsigned char rampbgr[RAMPWIDTH][4];
- int i;
+ unsigned short ramp[RAMPWIDTH * 3];
+ unsigned char rampbgr[RAMPWIDTH][4];
+ int i;
- r_texture_gammaramps_serial = vid_gammatables_serial;
+ r_texture_gammaramps_serial = vid_gammatables_serial;
- VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
- for(i = 0; i < RAMPWIDTH; ++i)
- {
- rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
- rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
- rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
- rampbgr[i][3] = 0;
- }
- if (r_texture_gammaramps)
- {
- R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, RAMPWIDTH, 1);
- }
- else
- {
- r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, NULL);
+ VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
+ for(i = 0; i < RAMPWIDTH; ++i)
+ {
+ rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
+ rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
+ rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
+ rampbgr[i][3] = 0;
+ }
+ if (r_texture_gammaramps)
+ {
+ R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, RAMPWIDTH, 1);
+ }
+ else
+ {
+ r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, NULL);
+ }
}
}
- }
- else
- {
- // remove GLSL gamma texture
+ else
+ {
+ // remove GLSL gamma texture
+ }
+ break;
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL11:
+ break;
}
}
r_frame++; // used only by R_GetCurrentTexture
rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
- R_AnimCache_NewFrame();
+ if (!r_drawentities.integer)
+ r_refdef.scene.numentities = 0;
+
+ R_AnimCache_ClearCache();
+ R_FrameData_NewFrame();
if (r_refdef.view.isoverlay)
{
r_refdef.view.clear = true;
// this produces a bloom texture to be used in R_BlendView() later
- if (r_hdr.integer)
+ if (r_hdr.integer && r_bloomstate.bloomwidth)
R_HDR_RenderBloomTexture();
r_refdef.view.showdebug = true;
extern cvar_t cl_locs_show;
static void R_DrawLocs(void);
static void R_DrawEntityBBoxes(void);
+static void R_DrawModelDecals(void);
extern cvar_t cl_decals_newsystem;
+extern qboolean r_shadow_usingdeferredprepass;
void R_RenderScene(void)
{
r_refdef.stats.renders++;
R_SetupView(false);
R_Sky();
R_SetupView(true);
+ if (r_timereport_active)
+ R_TimeReport("sky");
}
}
R_AnimCache_CacheVisibleEntities();
+ if (r_timereport_active)
+ R_TimeReport("animation");
+
+ R_Shadow_PrepareLights();
+ if (r_timereport_active)
+ R_TimeReport("preparelights");
+
+ if (r_shadow_usingdeferredprepass)
+ R_Shadow_DrawPrepass();
if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
{
S_ExtraUpdate ();
}
- R_ShadowVolumeLighting(false);
- if (r_timereport_active)
- R_TimeReport("rtlights");
+ if (!r_shadow_usingdeferredprepass)
+ {
+ R_Shadow_DrawLights();
+ if (r_timereport_active)
+ R_TimeReport("rtlights");
+ }
// don't let sound skip if going slow
if (r_refdef.scene.extraupdate)
if (cl.csqc_vidvars.drawworld)
{
- R_DrawCoronas();
+ R_Shadow_DrawCoronas();
if (r_timereport_active)
R_TimeReport("coronas");
}
R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
t->colormapping = VectorLength2(rsurface.colormap_pantscolor) + VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
+ if (t->currentskinframe->qpixels)
+ R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
t->glosstexture = r_texture_black;
t->backgroundbasetexture = t->backgroundnumskinframes ? ((!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base) : r_texture_white;
//if (rsurface.entity == r_refdef.scene.worldentity)
// return;
rsurface.entity = r_refdef.scene.worldentity;
+ rsurface.skeleton = NULL;
rsurface.ent_skinnum = 0;
rsurface.ent_qwskin = -1;
rsurface.ent_shadertime = 0;
//if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
// return;
rsurface.entity = (entity_render_t *)ent;
+ rsurface.skeleton = ent->skeleton;
rsurface.ent_skinnum = ent->skinnum;
rsurface.ent_qwskin = (ent->entitynumber <= cl.maxclients && ent->entitynumber >= 1 && cls.protocol == PROTOCOL_QUAKEWORLD && cl.scores[ent->entitynumber - 1].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl")) ? (ent->entitynumber - 1) : -1;
rsurface.ent_shadertime = ent->shadertime;
}
if (model->surfmesh.isanimated && model->AnimateVertices && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].subframe != 0))
{
- if (R_AnimCache_GetEntity((entity_render_t *)ent, wantnormals, wanttangents))
+ if (ent->animcache_vertex3f && !r_framedata_failed)
{
- rsurface.modelvertex3f = r_animcachestate.entity[ent->animcacheindex].vertex3f;
- rsurface.modelsvector3f = wanttangents ? r_animcachestate.entity[ent->animcacheindex].svector3f : NULL;
- rsurface.modeltvector3f = wanttangents ? r_animcachestate.entity[ent->animcacheindex].tvector3f : NULL;
- rsurface.modelnormal3f = wantnormals ? r_animcachestate.entity[ent->animcacheindex].normal3f : NULL;
+ rsurface.modelvertex3f = ent->animcache_vertex3f;
+ rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
+ rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
+ rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
}
else if (wanttangents)
{
rsurface.modelsvector3f = rsurface.array_modelsvector3f;
rsurface.modeltvector3f = rsurface.array_modeltvector3f;
rsurface.modelnormal3f = rsurface.array_modelnormal3f;
- model->AnimateVertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f);
+ model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f);
}
else if (wantnormals)
{
rsurface.modelsvector3f = NULL;
rsurface.modeltvector3f = NULL;
rsurface.modelnormal3f = rsurface.array_modelnormal3f;
- model->AnimateVertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, NULL, NULL);
+ model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, NULL, NULL);
}
else
{
rsurface.modelsvector3f = NULL;
rsurface.modeltvector3f = NULL;
rsurface.modelnormal3f = NULL;
- model->AnimateVertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, NULL, NULL, NULL);
+ model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.array_modelvertex3f, NULL, NULL, NULL);
}
rsurface.modelvertex3f_bufferobject = 0;
rsurface.modelvertex3f_bufferoffset = 0;
void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, int entflags, double shadertime, float r, float g, float b, float a, int numvertices, const float *vertex3f, const float *texcoord2f, const float *normal3f, const float *svector3f, const float *tvector3f, const float *color4f, int numtriangles, const int *element3i, const unsigned short *element3s, qboolean wantnormals, qboolean wanttangents)
{
rsurface.entity = r_refdef.scene.worldentity;
+ rsurface.skeleton = NULL;
rsurface.ent_skinnum = 0;
rsurface.ent_qwskin = -1;
rsurface.ent_shadertime = shadertime;
GL_Color(1, 1, 1, 1);
}
-static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
+extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
+extern rtexture_t *r_shadow_prepasslightingspeculartexture;
+static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
{
if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION)))
return;
R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
}
- if(rsurface.texture->colormapping)
+ if (rsurface.texture->colormapping)
{
R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
}
R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
+ if (r_shadow_usingdeferredprepass)
+ {
+ R_Mesh_TexBindAll(GL20TU_SCREENDIFFUSE, 0, 0, 0, R_GetTexture(r_shadow_prepasslightingdiffusetexture));
+ R_Mesh_TexBindAll(GL20TU_SCREENSPECULAR, 0, 0, 0, R_GetTexture(r_shadow_prepasslightingspeculartexture));
+ }
if ((rsurface.uselightmaptexture || (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
R_Mesh_ColorPointer(NULL, 0, 0);
else
R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
- if (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
+ if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION)) && !prepass)
{
// render background
GL_BlendFunc(GL_ONE, GL_ZERO);
R_Mesh_TexBind(GL20TU_REFLECTION, R_GetTexture(r_texture_white)); // changed per surface
}
- R_SetupSurfaceShader(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE);
+ R_SetupSurfaceShader(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, prepass ? RSURFPASS_DEFERREDGEOMETRY : RSURFPASS_BASE);
if (!r_glsl_permutation)
return;
R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
- R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
+ if (!prepass)
+ R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
if (r_glsl_permutation->loc_Texture_Refraction >= 0)
{
RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
}
-static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
+static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
{
CHECKGLERROR
RSurf_SetupDepthAndCulling();
- if (r_showsurfaces.integer == 3)
+ if (r_showsurfaces.integer == 3 && !prepass)
+ {
R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth);
- else if (r_glsl.integer && gl_support_fragment_shader)
- R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth);
- else if (gl_combine.integer && r_textureunits.integer >= 2)
+ return;
+ }
+ switch (vid.renderpath)
+ {
+ case RENDERPATH_GL20:
+ R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
+ break;
+ case RENDERPATH_GL13:
R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist, writedepth);
- else
+ break;
+ case RENDERPATH_GL11:
R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist, writedepth);
+ break;
+ }
CHECKGLERROR
}
-static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
+static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
{
CHECKGLERROR
RSurf_SetupDepthAndCulling();
- if (r_showsurfaces.integer == 3)
+ if (r_showsurfaces.integer == 3 && !prepass)
+ {
R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth);
- else if (r_glsl.integer && gl_support_fragment_shader)
- R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth);
- else if (gl_combine.integer && r_textureunits.integer >= 2)
+ return;
+ }
+ switch (vid.renderpath)
+ {
+ case RENDERPATH_GL20:
+ R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
+ break;
+ case RENDERPATH_GL13:
R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist, writedepth);
- else
+ break;
+ case RENDERPATH_GL11:
R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist, writedepth);
+ break;
+ }
CHECKGLERROR
}
else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
RSurf_ActiveModelEntity(ent, false, false);
else
- RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
+ {
+ switch (vid.renderpath)
+ {
+ case RENDERPATH_GL20:
+ RSurf_ActiveModelEntity(ent, true, true);
+ break;
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL11:
+ RSurf_ActiveModelEntity(ent, true, false);
+ break;
+ }
+ }
for (i = 0;i < numsurfaces;i = j)
{
}
// render the range of surfaces
if (ent == r_refdef.scene.worldentity)
- R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false);
+ R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
else
- R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false);
+ R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
}
rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
GL_AlphaTest(false);
}
-static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly)
+static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
{
const entity_render_t *queueentity = r_refdef.scene.worldentity;
CHECKGLERROR
RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
}
+ else if (prepass)
+ {
+ if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
+ return;
+ if (!rsurface.texture->currentnumlayers)
+ return;
+ R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
+ }
else if (r_showsurfaces.integer && !r_refdef.view.showdebug)
{
RSurf_SetupDepthAndCulling();
else
{
// the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
- R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST));
+ R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
}
CHECKGLERROR
}
-void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly)
+void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
{
int i, j;
texture_t *texture;
// use skin 1 instead)
texture = surfacelist[i]->texture;
rsurface.texture = R_GetCurrentTexture(texture);
- rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
+ rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL && !depthonly && !prepass;
if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
{
// if this texture is not the kind we want, skip ahead to the next one
for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
;
// render the range of surfaces
- R_ProcessWorldTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly);
+ R_ProcessWorldTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass);
}
}
-static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity)
+static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity, qboolean prepass)
{
CHECKGLERROR
if (depthonly)
RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
}
+ else if (prepass)
+ {
+ if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
+ return;
+ if (!rsurface.texture->currentnumlayers)
+ return;
+ R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
+ }
else if (r_showsurfaces.integer && !r_refdef.view.showdebug)
{
RSurf_SetupDepthAndCulling();
else
{
// the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
- R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST));
+ R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
}
CHECKGLERROR
}
-void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly)
+void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
{
int i, j;
texture_t *texture;
// use skin 1 instead)
texture = surfacelist[i]->texture;
rsurface.texture = R_GetCurrentTexture(texture);
- rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
+ rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL && !depthonly && !prepass;
if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
{
// if this texture is not the kind we want, skip ahead to the next one
for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
;
// render the range of surfaces
- R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent);
+ R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent, prepass);
}
}
memset(decalsystem, 0, sizeof(*decalsystem));
}
-void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, const float *v1, const float *v2, const float *t0, const float *t1, const float *t2, const float *c0, const float *c1, const float *c2, int triangleindex)
+static void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, const float *v1, const float *v2, const float *t0, const float *t1, const float *t2, const float *c0, const float *c1, const float *c2, int triangleindex, int surfaceindex, int decalsequence)
{
- float *v3f;
- float *tc2f;
- float *c4f;
- float ca;
tridecal_t *decal;
tridecal_t *decals;
int i;
decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
if (decalsystem->numdecals)
- {
memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
- memcpy(decalsystem->vertex3f, old.vertex3f, decalsystem->numdecals * sizeof(float[3][3]));
- memcpy(decalsystem->texcoord2f, old.texcoord2f, decalsystem->numdecals * sizeof(float[3][2]));
- memcpy(decalsystem->color4f, old.color4f, decalsystem->numdecals * sizeof(float[3][4]));
- }
- Mem_Free(old.decals);
+ if (old.decals)
+ Mem_Free(old.decals);
for (i = 0;i < decalsystem->maxdecals*3;i++)
decalsystem->element3i[i] = i;
if (useshortelements)
maxdecals = decalsystem->maxdecals;
decals = decalsystem->decals;
decal = decalsystem->decals + (i = decalsystem->freedecal++);
- v3f = decalsystem->vertex3f + 9*i;
- tc2f = decalsystem->texcoord2f + 6*i;
- c4f = decalsystem->color4f + 12*i;
- for (i = decalsystem->freedecal;i < maxdecals && decals[i].colors[0][3];i++)
+ for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4ub[0][3];i++)
;
decalsystem->freedecal = i;
if (decalsystem->numdecals <= i)
// initialize the decal
decal->lived = 0;
decal->triangleindex = triangleindex;
- decal->colors[0][0] = (unsigned char)(c0[0]*255.0f);
- decal->colors[0][1] = (unsigned char)(c0[1]*255.0f);
- decal->colors[0][2] = (unsigned char)(c0[2]*255.0f);
- decal->colors[0][3] = 255;
- decal->colors[1][0] = (unsigned char)(c1[0]*255.0f);
- decal->colors[1][1] = (unsigned char)(c1[1]*255.0f);
- decal->colors[1][2] = (unsigned char)(c1[2]*255.0f);
- decal->colors[1][3] = 255;
- decal->colors[2][0] = (unsigned char)(c2[0]*255.0f);
- decal->colors[2][1] = (unsigned char)(c2[1]*255.0f);
- decal->colors[2][2] = (unsigned char)(c2[2]*255.0f);
- decal->colors[2][3] = 255;
- v3f[0] = v0[0];
- v3f[1] = v0[1];
- v3f[2] = v0[2];
- v3f[3] = v1[0];
- v3f[4] = v1[1];
- v3f[5] = v1[2];
- v3f[6] = v2[0];
- v3f[7] = v2[1];
- v3f[8] = v2[2];
- tc2f[0] = t0[0];
- tc2f[1] = t0[1];
- tc2f[2] = t1[0];
- tc2f[3] = t1[1];
- tc2f[4] = t2[0];
- tc2f[5] = t2[1];
- ca = (1.0f/255.0f);
- c4f[ 0] = decal->colors[0][0] * ca;
- c4f[ 1] = decal->colors[0][1] * ca;
- c4f[ 2] = decal->colors[0][2] * ca;
- c4f[ 3] = 1;
- c4f[ 4] = decal->colors[1][0] * ca;
- c4f[ 5] = decal->colors[1][1] * ca;
- c4f[ 6] = decal->colors[1][2] * ca;
- c4f[ 7] = 1;
- c4f[ 8] = decal->colors[2][0] * ca;
- c4f[ 9] = decal->colors[2][1] * ca;
- c4f[10] = decal->colors[2][2] * ca;
- c4f[11] = 1;
+ decal->surfaceindex = surfaceindex;
+ decal->decalsequence = decalsequence;
+ decal->color4ub[0][0] = (unsigned char)(c0[0]*255.0f);
+ decal->color4ub[0][1] = (unsigned char)(c0[1]*255.0f);
+ decal->color4ub[0][2] = (unsigned char)(c0[2]*255.0f);
+ decal->color4ub[0][3] = 255;
+ decal->color4ub[1][0] = (unsigned char)(c1[0]*255.0f);
+ decal->color4ub[1][1] = (unsigned char)(c1[1]*255.0f);
+ decal->color4ub[1][2] = (unsigned char)(c1[2]*255.0f);
+ decal->color4ub[1][3] = 255;
+ decal->color4ub[2][0] = (unsigned char)(c2[0]*255.0f);
+ decal->color4ub[2][1] = (unsigned char)(c2[1]*255.0f);
+ decal->color4ub[2][2] = (unsigned char)(c2[2]*255.0f);
+ decal->color4ub[2][3] = 255;
+ decal->vertex3f[0][0] = v0[0];
+ decal->vertex3f[0][1] = v0[1];
+ decal->vertex3f[0][2] = v0[2];
+ decal->vertex3f[1][0] = v1[0];
+ decal->vertex3f[1][1] = v1[1];
+ decal->vertex3f[1][2] = v1[2];
+ decal->vertex3f[2][0] = v2[0];
+ decal->vertex3f[2][1] = v2[1];
+ decal->vertex3f[2][2] = v2[2];
+ decal->texcoord2f[0][0] = t0[0];
+ decal->texcoord2f[0][1] = t0[1];
+ decal->texcoord2f[1][0] = t1[0];
+ decal->texcoord2f[1][1] = t1[1];
+ decal->texcoord2f[2][0] = t2[0];
+ decal->texcoord2f[2][1] = t2[1];
}
extern cvar_t cl_decals_bias;
extern cvar_t cl_decals_models;
-void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize)
+extern cvar_t cl_decals_newsystem_intensitymultiplier;
+static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, int decalsequence)
{
matrix4x4_t projection;
decalsystem_t *decalsystem;
int numtriangles;
int numsurfacelist;
int surfacelistindex;
+ int surfaceindex;
int triangleindex;
+ int decalsurfaceindex;
int cornerindex;
int index;
int numpoints;
surfaces = model->data_surfaces;
for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
{
- surface = surfaces + surfacelist[surfacelistindex];
+ surfaceindex = surfacelist[surfacelistindex];
+ surface = surfaces + surfaceindex;
// skip transparent surfaces
texture = surface->texture;
if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
continue;
if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
continue;
- if (texture->currentalpha < 1)
- continue;
if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
continue;
+ decalsurfaceindex = ent == r_refdef.scene.worldentity ? surfaceindex : -1;
numvertices = surface->num_vertices;
numtriangles = surface->num_triangles;
for (triangleindex = 0, e = model->surfmesh.data_element3i + 3*surface->num_firsttriangle;triangleindex < numtriangles;triangleindex++, e += 3)
tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
// calculate distance fade from the projection origin
- f = a * (1.0f-fabs(temp[0]));
- f = max(0.0f, f);
+ f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
+ f = bound(0.0f, f, 1.0f);
c[cornerindex][0] = r * f;
c[cornerindex][1] = g * f;
c[cornerindex][2] = b * f;
//VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
}
if (dynamic)
- R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[1], v[2], tc[0], tc[1], tc[2], c[0], c[1], c[2], triangleindex);
+ R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[1], v[2], tc[0], tc[1], tc[2], c[0], c[1], c[2], triangleindex+surface->num_firsttriangle, surfaceindex, decalsequence);
else
for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
- R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[cornerindex+1], v[cornerindex+2], tc[0], tc[cornerindex+1], tc[cornerindex+2], c[0], c[cornerindex+1], c[cornerindex+2], -1);
+ R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[cornerindex+1], v[cornerindex+2], tc[0], tc[cornerindex+1], tc[cornerindex+2], c[0], c[cornerindex+1], c[cornerindex+2], -1, surfaceindex, decalsequence);
}
}
}
-void R_DecalSystem_SplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize)
+// do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
+static void R_DecalSystem_ApplySplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, int decalsequence)
{
int renderentityindex;
float worldmins[3];
float worldmaxs[3];
entity_render_t *ent;
+ if (!cl_decals_newsystem.integer)
+ return;
+
worldmins[0] = worldorigin[0] - worldsize;
worldmins[1] = worldorigin[1] - worldsize;
worldmins[2] = worldorigin[2] - worldsize;
worldmaxs[1] = worldorigin[1] + worldsize;
worldmaxs[2] = worldorigin[2] + worldsize;
- R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize);
+ R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
{
if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
continue;
- R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize);
+ R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
+ }
+}
+
+typedef struct r_decalsystem_splatqueue_s
+{
+ vec3_t worldorigin;
+ vec3_t worldnormal;
+ float color[4];
+ float tcrange[4];
+ float worldsize;
+ int decalsequence;
+}
+r_decalsystem_splatqueue_t;
+
+int r_decalsystem_numqueued = 0;
+#define MAX_DECALSYSTEM_QUEUE 1024
+r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
+
+void R_DecalSystem_SplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize)
+{
+ r_decalsystem_splatqueue_t *queue;
+
+ if (!cl_decals_newsystem.integer || r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
+ return;
+
+ queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
+ VectorCopy(worldorigin, queue->worldorigin);
+ VectorCopy(worldnormal, queue->worldnormal);
+ Vector4Set(queue->color, r, g, b, a);
+ Vector4Set(queue->tcrange, s1, t1, s2, t2);
+ queue->worldsize = worldsize;
+ queue->decalsequence = cl.decalsequence++;
+}
+
+static void R_DecalSystem_ApplySplatEntitiesQueue(void)
+{
+ int i;
+ r_decalsystem_splatqueue_t *queue;
+
+ for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
+ R_DecalSystem_ApplySplatEntities(queue->worldorigin, queue->worldnormal, queue->color[0], queue->color[1], queue->color[2], queue->color[3], queue->tcrange[0], queue->tcrange[1], queue->tcrange[2], queue->tcrange[3], queue->worldsize, queue->decalsequence);
+ r_decalsystem_numqueued = 0;
+}
+
+extern cvar_t cl_decals_max;
+static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
+{
+ int i;
+ decalsystem_t *decalsystem = &ent->decalsystem;
+ int numdecals;
+ int killsequence;
+ tridecal_t *decal;
+ float frametime;
+ float lifetime;
+
+ if (!decalsystem->numdecals)
+ return;
+
+ if (r_showsurfaces.integer)
+ return;
+
+ if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
+ {
+ R_DecalSystem_Reset(decalsystem);
+ return;
+ }
+
+ killsequence = cl.decalsequence - max(1, cl_decals_max.integer);
+ lifetime = cl_decals_time.value + cl_decals_fadetime.value;
+
+ if (decalsystem->lastupdatetime)
+ frametime = (cl.time - decalsystem->lastupdatetime);
+ else
+ frametime = 0;
+ decalsystem->lastupdatetime = cl.time;
+ decal = decalsystem->decals;
+ numdecals = decalsystem->numdecals;
+
+ for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
+ {
+ if (decal->color4ub[0][3])
+ {
+ decal->lived += frametime;
+ if (killsequence - decal->decalsequence > 0 || decal->lived >= lifetime)
+ {
+ memset(decal, 0, sizeof(*decal));
+ if (decalsystem->freedecal > i)
+ decalsystem->freedecal = i;
+ }
+ }
+ }
+ decal = decalsystem->decals;
+ while (numdecals > 0 && !decal[numdecals-1].color4ub[0][3])
+ numdecals--;
+
+ // collapse the array by shuffling the tail decals into the gaps
+ for (;;)
+ {
+ while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4ub[0][3])
+ decalsystem->freedecal++;
+ if (decalsystem->freedecal == numdecals)
+ break;
+ decal[decalsystem->freedecal] = decal[--numdecals];
+ }
+
+ decalsystem->numdecals = numdecals;
+
+ if (numdecals <= 0)
+ {
+ // if there are no decals left, reset decalsystem
+ R_DecalSystem_Reset(decalsystem);
}
}
decalsystem_t *decalsystem = &ent->decalsystem;
int numdecals;
tridecal_t *decal;
- float frametime;
float fadedelay;
float faderate;
float alpha;
float *v3f;
float *c4f;
+ float *t2f;
const int *e;
+ const unsigned char *surfacevisible = r_refdef.viewcache.world_surfacevisible;
+ int numtris = 0;
- if (!decalsystem->numdecals)
+ numdecals = decalsystem->numdecals;
+ if (!numdecals)
return;
if (r_showsurfaces.integer)
else
RSurf_ActiveModelEntity(ent, false, false);
- if (decalsystem->lastupdatetime)
- frametime = cl.time - decalsystem->lastupdatetime;
- else
- frametime = 0;
decalsystem->lastupdatetime = cl.time;
decal = decalsystem->decals;
- numdecals = decalsystem->numdecals;
fadedelay = cl_decals_time.value;
faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
+ // update vertex positions for animated models
+ v3f = decalsystem->vertex3f;
+ c4f = decalsystem->color4f;
+ t2f = decalsystem->texcoord2f;
for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
{
- if (!decal->colors[0][3])
+ if (!decal->color4ub[0][3])
+ continue;
+
+ if (decal->surfaceindex >= 0 && !surfacevisible[decal->surfaceindex])
continue;
- decal->lived += frametime;
- if (decal->lived >= fadedelay)
+ // update color values for fading decals
+ if (decal->lived >= cl_decals_time.value)
{
alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
- if (alpha <= 0)
- {
- // kill the decal by zeroing vertex data
- memset(decalsystem->vertex3f + 9*i, 0, sizeof(float[3][3]));
- memset(decalsystem->texcoord2f + 6*i, 0, sizeof(float[3][2]));
- memset(decalsystem->color4f + 12*i, 0, sizeof(float[3][4]));
- memset(decal, 0, sizeof(*decal));
- if (decalsystem->freedecal > i)
- decalsystem->freedecal = i;
- continue;
- }
-
- // update color values for fading decals
alpha *= (1.0f/255.0f);
- c4f = decalsystem->color4f + 12*i;
- c4f[ 0] = decal->colors[0][0] * alpha;
- c4f[ 1] = decal->colors[0][1] * alpha;
- c4f[ 2] = decal->colors[0][2] * alpha;
- c4f[ 3] = 1;
- c4f[ 4] = decal->colors[1][0] * alpha;
- c4f[ 5] = decal->colors[1][1] * alpha;
- c4f[ 6] = decal->colors[1][2] * alpha;
- c4f[ 7] = 1;
- c4f[ 8] = decal->colors[2][0] * alpha;
- c4f[ 9] = decal->colors[2][1] * alpha;
- c4f[10] = decal->colors[2][2] * alpha;
- c4f[11] = 1;
}
+ else
+ alpha = 1.0f/255.0f;
+
+ c4f[ 0] = decal->color4ub[0][0] * alpha;
+ c4f[ 1] = decal->color4ub[0][1] * alpha;
+ c4f[ 2] = decal->color4ub[0][2] * alpha;
+ c4f[ 3] = 1;
+ c4f[ 4] = decal->color4ub[1][0] * alpha;
+ c4f[ 5] = decal->color4ub[1][1] * alpha;
+ c4f[ 6] = decal->color4ub[1][2] * alpha;
+ c4f[ 7] = 1;
+ c4f[ 8] = decal->color4ub[2][0] * alpha;
+ c4f[ 9] = decal->color4ub[2][1] * alpha;
+ c4f[10] = decal->color4ub[2][2] * alpha;
+ c4f[11] = 1;
+
+ t2f[0] = decal->texcoord2f[0][0];
+ t2f[1] = decal->texcoord2f[0][1];
+ t2f[2] = decal->texcoord2f[1][0];
+ t2f[3] = decal->texcoord2f[1][1];
+ t2f[4] = decal->texcoord2f[2][0];
+ t2f[5] = decal->texcoord2f[2][1];
// update vertex positions for animated models
if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnum_triangles)
{
e = rsurface.modelelement3i + 3*decal->triangleindex;
- v3f = decalsystem->vertex3f + 9*i;
VectorCopy(rsurface.vertex3f + 3*e[0], v3f);
VectorCopy(rsurface.vertex3f + 3*e[1], v3f + 3);
VectorCopy(rsurface.vertex3f + 3*e[2], v3f + 6);
}
- }
+ else
+ {
+ VectorCopy(decal->vertex3f[0], v3f);
+ VectorCopy(decal->vertex3f[1], v3f + 3);
+ VectorCopy(decal->vertex3f[2], v3f + 6);
+ }
- // reduce numdecals if possible
- while (numdecals > 0 && !decalsystem->decals[numdecals - 1].colors[0][3])
- numdecals--;
- decalsystem->numdecals = numdecals;
+ v3f += 9;
+ c4f += 12;
+ t2f += 6;
+ numtris++;
+ }
- if (numdecals > 0)
+ if (numtris > 0)
{
- r_refdef.stats.decals += numdecals;
+ r_refdef.stats.drawndecals += numtris;
// now render the decals all at once
// (this assumes they all use one particle font texture!)
- RSurf_ActiveCustomEntity(&rsurface.matrix, &rsurface.inversematrix, rsurface.ent_flags, rsurface.ent_shadertime, 1, 1, 1, 1, numdecals*3, decalsystem->vertex3f, decalsystem->texcoord2f, NULL, NULL, NULL, decalsystem->color4f, numdecals, decalsystem->element3i, decalsystem->element3s, false, false);
+ RSurf_ActiveCustomEntity(&rsurface.matrix, &rsurface.inversematrix, rsurface.ent_flags, rsurface.ent_shadertime, 1, 1, 1, 1, numdecals*3, decalsystem->vertex3f, decalsystem->texcoord2f, NULL, NULL, NULL, decalsystem->color4f, numtris, decalsystem->element3i, decalsystem->element3s, false, false);
R_Mesh_ResetTextureState();
R_Mesh_VertexPointer(decalsystem->vertex3f, 0, 0);
R_Mesh_TexCoordPointer(0, 2, decalsystem->texcoord2f, 0, 0);
GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
R_Mesh_TexBind(0, R_GetTexture(decalskinframe->base));
//R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
- GL_LockArrays(0, numdecals * 3);
- R_Mesh_Draw(0, numdecals * 3, 0, numdecals, decalsystem->element3i, decalsystem->element3s, 0, 0);
+ GL_LockArrays(0, numtris * 3);
+ R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, decalsystem->element3s, 0, 0);
GL_LockArrays(0, 0);
}
+}
- if (numdecals <= 0)
+static void R_DrawModelDecals(void)
+{
+ int i, numdecals;
+
+ // fade faster when there are too many decals
+ numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
+ for (i = 0;i < r_refdef.scene.numentities;i++)
+ numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
+
+ R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
+ for (i = 0;i < r_refdef.scene.numentities;i++)
+ if (r_refdef.scene.entities[i]->decalsystem.numdecals)
+ R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
+
+ R_DecalSystem_ApplySplatEntitiesQueue();
+
+ numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
+ for (i = 0;i < r_refdef.scene.numentities;i++)
+ numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
+
+ r_refdef.stats.totaldecals += numdecals;
+
+ if (r_showsurfaces.integer)
+ return;
+
+ R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
+
+ for (i = 0;i < r_refdef.scene.numentities;i++)
{
- // if there are no decals left, reset decalsystem
- R_DecalSystem_Reset(decalsystem);
+ if (!r_refdef.viewcache.entityvisible[i])
+ continue;
+ if (r_refdef.scene.entities[i]->decalsystem.numdecals)
+ R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
}
}
extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
int r_maxsurfacelist = 0;
const msurface_t **r_surfacelist = NULL;
-void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug)
+void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
{
int i, j, endj, f, flagsmask;
texture_t *t;
{
r_maxsurfacelist = model->num_surfaces;
if (r_surfacelist)
- Mem_Free(r_surfacelist);
+ Mem_Free((msurface_t**)r_surfacelist);
r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
}
update = model->brushq1.lightmapupdateflags;
// update light styles on this submodel
- if (!skysurfaces && !depthonly && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0)
+ if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0)
{
model_brush_lightstyleinfo_t *style;
for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
return;
}
- R_QueueWorldSurfaceList(numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly);
+ R_QueueWorldSurfaceList(numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass);
GL_AlphaTest(false);
// add to stats if desired
rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
}
-void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug)
+void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
{
int i, j, endj, f, flagsmask;
texture_t *t;
{
r_maxsurfacelist = model->num_surfaces;
if (r_surfacelist)
- Mem_Free(r_surfacelist);
+ Mem_Free((msurface_t **)r_surfacelist);
r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
}
RSurf_ActiveWorldEntity();
else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
RSurf_ActiveModelEntity(ent, false, false);
+ else if (prepass)
+ RSurf_ActiveModelEntity(ent, true, true);
+ else if (depthonly)
+ RSurf_ActiveModelEntity(ent, false, false);
else
- RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader && !depthonly);
+ {
+ switch (vid.renderpath)
+ {
+ case RENDERPATH_GL20:
+ RSurf_ActiveModelEntity(ent, true, true);
+ break;
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL11:
+ RSurf_ActiveModelEntity(ent, true, false);
+ break;
+ }
+ }
surfaces = model->data_surfaces;
update = model->brushq1.lightmapupdateflags;
// update light styles
- if (!skysurfaces && !depthonly && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0)
+ if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0)
{
model_brush_lightstyleinfo_t *style;
for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
if (update[j])
R_BuildLightMap(ent, surfaces + j);
- R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly);
+ R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass);
GL_AlphaTest(false);
// add to stats if desired
rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
}
-void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth)
+void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
{
static texture_t texture;
static msurface_t surface;
// now render it
rsurface.texture = R_GetCurrentTexture(surface.texture);
rsurface.uselightmaptexture = false;
- R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth);
+ R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
}