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_postprocess_uservec1_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
+cvar_t r_glsl_postprocess_uservec2_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
+cvar_t r_glsl_postprocess_uservec3_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
+cvar_t r_glsl_postprocess_uservec4_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
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_water_resolutionmultiplier = {CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
+cvar_t r_water_scissormode = {0, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
cvar_t r_overheadsprites_pushback = {CVAR_SAVE, "r_overheadsprites_pushback", "16", "how far to pull the SPR_OVERHEAD sprites toward the eye (used to avoid intersections with 3D models)"};
cvar_t r_glsl_saturation = {CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
+cvar_t r_glsl_saturation_redcompensate = {CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
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)"};
"#ifdef USESATURATION\n"
" //apply saturation BEFORE gamma ramps, so v_glslgamma value does not matter\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"
+" // 'vampire sight' effect, wheres red is compensated\n"
+" #ifdef SATURATION_REDCOMPENSATE\n"
+" float rboost = max(0.0, (gl_FragColor.r - max(gl_FragColor.g, gl_FragColor.b))*(1.0 - Saturation));\n"
+" gl_FragColor.rgb = mix(vec3(y), gl_FragColor.rgb, Saturation);\n"
+" gl_FragColor.r += rboost;\n"
+" #else\n"
+" // normal desaturation\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"
"#endif\n"
"\n"
"#ifdef USEGAMMARAMPS\n"
"\n"
"void main(void)\n"
"{\n"
+"#ifdef USEVIEWTINT\n"
" gl_FragColor = gl_Color;\n"
+"#else\n"
+" gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
+"#endif\n"
"#ifdef USEDIFFUSE\n"
" gl_FragColor *= texture2D(Texture_First, TexCoord1);\n"
"#endif\n"
"uniform vec4 ReflectColor;\n"
"uniform float ReflectFactor;\n"
"uniform float ReflectOffset;\n"
+"uniform float ClientTime;\n"
+"#ifdef USENORMALMAPSCROLLBLEND\n"
+"uniform vec2 NormalmapScrollBlend;\n"
+"#endif\n"
"\n"
"void main(void)\n"
"{\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"
" //SafeScreenTexCoord = gl_FragCoord.xyxy * vec4(1.0 / 1920.0, 1.0 / 1200.0, 1.0 / 1920.0, 1.0 / 1200.0);\n"
-" vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5))).xyxy * DistortScaleRefractReflect;\n"
+" // slight water animation via 2 layer scrolling (todo: tweak)\n"
+" #ifdef USENORMALMAPSCROLLBLEND\n"
+" vec3 normal = texture2D(Texture_Normal, (TexCoord + vec2(0.08, 0.08)*ClientTime*NormalmapScrollBlend.x*0.5)*NormalmapScrollBlend.y).rgb - vec3(1.0);\n"
+" normal += texture2D(Texture_Normal, (TexCoord + vec2(-0.06, -0.09)*ClientTime*NormalmapScrollBlend.x)*NormalmapScrollBlend.y*0.75).rgb;\n"
+" vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(normal) + vec3(0.15)).xyxy * DistortScaleRefractReflect;\n"
+" #else\n"
+" vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(vec3(texture2D(Texture_Normal, TexCoord)) - vec3(0.5))).xyxy * DistortScaleRefractReflect;\n"
+" #endif\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"
+" float f = min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.005, 0.01)).rgb) / 0.002);\n"
+" f *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.005, -0.01)).rgb) / 0.002);\n"
+" f *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.005, 0.01)).rgb) / 0.002);\n"
+" f *= min(1.0, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.005, -0.01)).rgb) / 0.002);\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"
+" float f = min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.005, 0.005)).rgb) / 0.002);\n"
+" f *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.005, -0.005)).rgb) / 0.002);\n"
+" f *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.005, 0.005)).rgb) / 0.002);\n"
+" f *= min(1.0, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.005, -0.005)).rgb) / 0.002);\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(vec4(texture2D(Texture_Refraction, ScreenTexCoord.xy).rgb, 1) * RefractColor, vec4(texture2D(Texture_Reflection, ScreenTexCoord.zw).rgb, 1) * ReflectColor, Fresnel);\n"
" RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.0625 - 0.03125);\n"
" return RT.xy;\n"
"#else\n"
-" // 3 sample offset mapping (only 3 samples because of ATI Radeon 9500-9800/X300 limits)\n"
+" // 2 sample offset mapping (only 2 samples because of ATI Radeon 9500-9800/X300 limits)\n"
" // this basically moves forward the full distance, and then backs up based\n"
" // on height of samples\n"
" //vec2 OffsetVector = vec2(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * vec2(-1, 1));\n"
" //vec2 OffsetVector = vec2(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-1, 1));\n"
" vec2 OffsetVector = vec2(normalize(EyeVector).xy * OffsetMapping_Scale * vec2(-1, 1));\n"
" TexCoord += OffsetVector;\n"
-" OffsetVector *= 0.333;\n"
-" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
+" OffsetVector *= 0.5;\n"
" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
" return TexCoord;\n"
" lightnormal.x = dot(lightnormal_modelspace, myhalf3(VectorS));\n"
" lightnormal.y = dot(lightnormal_modelspace, myhalf3(VectorT));\n"
" lightnormal.z = dot(lightnormal_modelspace, myhalf3(VectorR));\n"
+" lightnormal = normalize(lightnormal); // VectorS/T/R are not always perfectly normalized, and EXACTSPECULARMATH is very picky about this\n"
" // calculate directional shading (and undoing the existing angle attenuation on the lightmap by the division)\n"
" // note that q3map2 is too stupid to calculate proper surface normals when q3map_nonplanar\n"
" // is used (the lightmap and deluxemap coords correspond to virtually random coordinates\n"
"out float4 gl_FragColor : COLOR\n"
")\n"
"{\n"
-"// float3 temp = float3(Depth,Depth*(65536.0/255.0),Depth*(16777216.0/255.0));\n"
+"// float4 temp = float4(Depth,Depth*(65536.0/255.0),Depth*(16777216.0/255.0),0.0);\n"
" float4 temp = float4(Depth,Depth*256.0,Depth*65536.0,0.0);\n"
" temp.yz -= floor(temp.yz);\n"
" gl_FragColor = temp;\n"
"#ifdef USESATURATION\n"
" //apply saturation BEFORE gamma ramps, so v_glslgamma value does not matter\n"
" float y = dot(gl_FragColor.rgb, float3(0.299, 0.587, 0.114));\n"
-" //gl_FragColor = float3(y,y,y) + (gl_FragColor.rgb - float3(y)) * Saturation;\n"
-" gl_FragColor.rgb = lerp(float3(y,y,y), gl_FragColor.rgb, Saturation);\n"
+" // 'vampire sight' effect, wheres red is compensated\n"
+" #ifdef SATURATION_REDCOMPENSATE\n"
+" float rboost = max(0.0, (gl_FragColor.r - max(gl_FragColor.g, gl_FragColor.b))*(1.0 - Saturation));\n"
+" gl_FragColor.rgb = mix(float3(y,y,y), gl_FragColor.rgb, Saturation);\n"
+" gl_FragColor.r += r;\n"
+" #else\n"
+" // normal desaturation\n"
+" //gl_FragColor = float3(y,y,y) + (gl_FragColor.rgb - float3(y)) * Saturation;\n"
+" gl_FragColor.rgb = lerp(float3(y,y,y), gl_FragColor.rgb, Saturation);\n"
+" #endif\n"
"#endif\n"
"\n"
"#ifdef USEGAMMARAMPS\n"
"out float4 gl_FragColor : COLOR\n"
")\n"
"{\n"
+"#ifdef USEVIEWTINT\n"
" gl_FragColor = gl_FrontColor;\n"
+"#else\n"
+" gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
+"#endif\n"
"#ifdef USEDIFFUSE\n"
" gl_FragColor *= tex2D(Texture_First, TexCoord1);\n"
"#endif\n"
" float2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n"
" //float2 ScreenTexCoord = (ModelViewProjectionPosition.xy + normalize(tex2D(Texture_Normal, TexCoord).rgb - float3(0.5,0.5,0.5)).xy * DistortScaleRefractReflect.xy * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
" float2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
-" float2 ScreenTexCoord = SafeScreenTexCoord + float2(normalize(tex2D(Texture_Normal, TexCoord).rgb - float3(0.5,0.5,0.5))).xy * DistortScaleRefractReflect.xy;\n"
+" float2 ScreenTexCoord = SafeScreenTexCoord + normalize(tex2D(Texture_Normal, TexCoord).rgb - float3(0.5,0.5,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"
"#ifdef MODE_FAKELIGHT\n"
"#define SHADING\n"
"half3 lightnormal = half3(normalize(EyeVector));\n"
-"half3 lightcolor = half3(1.0);\n"
+"half3 lightcolor = half3(1.0,1.0,1.0);\n"
"#endif // MODE_FAKELIGHT\n"
"\n"
"\n"
{
SHADERPERMUTATION_DIFFUSE = 1<<0, ///< (lightsource) whether to use directional shading
SHADERPERMUTATION_VERTEXTEXTUREBLEND = 1<<1, ///< indicates this is a two-layer material blend based on vertex alpha (q3bsp)
- SHADERPERMUTATION_VIEWTINT = 1<<2, ///< view tint (postprocessing only)
+ SHADERPERMUTATION_VIEWTINT = 1<<2, ///< view tint (postprocessing only), use vertex colors (generic only)
SHADERPERMUTATION_COLORMAPPING = 1<<3, ///< indicates this is a colormapped skin
SHADERPERMUTATION_SATURATION = 1<<4, ///< saturation (postprocessing only)
SHADERPERMUTATION_FOGINSIDE = 1<<5, ///< tint the color by fog color or black if using additive blend mode
SHADERPERMUTATION_BLOOM = 1<<11, ///< bloom (postprocessing only)
SHADERPERMUTATION_SPECULAR = 1<<12, ///< (lightsource or deluxemapping) render specular effects
SHADERPERMUTATION_POSTPROCESSING = 1<<13, ///< user defined postprocessing (postprocessing only)
- SHADERPERMUTATION_EXACTSPECULARMATH = 1<<14, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
- SHADERPERMUTATION_REFLECTION = 1<<15, ///< normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface
- SHADERPERMUTATION_OFFSETMAPPING = 1<<16, ///< adjust texcoords to roughly simulate a displacement mapped surface
- SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<17, ///< adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!)
- SHADERPERMUTATION_SHADOWMAP2D = 1<<18, ///< (lightsource) use shadowmap texture as light filter
- SHADERPERMUTATION_SHADOWMAPPCF = 1<<19, ///< (lightsource) use percentage closer filtering on shadowmap test results
- SHADERPERMUTATION_SHADOWMAPPCF2 = 1<<20, ///< (lightsource) use higher quality percentage closer filtering on shadowmap test results
- SHADERPERMUTATION_SHADOWSAMPLER = 1<<21, ///< (lightsource) use hardware shadowmap test
- SHADERPERMUTATION_SHADOWMAPVSDCT = 1<<22, ///< (lightsource) use virtual shadow depth cube texture for shadowmap indexing
- SHADERPERMUTATION_SHADOWMAPORTHO = 1<<23, //< (lightsource) use orthographic shadowmap projection
- SHADERPERMUTATION_DEFERREDLIGHTMAP = 1<<24, ///< (lightmap) read Texture_ScreenDiffuse/Specular textures and add them on top of lightmapping
- SHADERPERMUTATION_ALPHAKILL = 1<<25, ///< (deferredgeometry) discard pixel if diffuse texture alpha below 0.5
- SHADERPERMUTATION_REFLECTCUBE = 1<<26, ///< fake reflections using global cubemap (not HDRI light probe)
+ SHADERPERMUTATION_REFLECTION = 1<<14, ///< normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface
+ SHADERPERMUTATION_OFFSETMAPPING = 1<<15, ///< adjust texcoords to roughly simulate a displacement mapped surface
+ SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<16, ///< adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!)
+ SHADERPERMUTATION_SHADOWMAP2D = 1<<17, ///< (lightsource) use shadowmap texture as light filter
+ SHADERPERMUTATION_SHADOWMAPPCF = 1<<18, ///< (lightsource) use percentage closer filtering on shadowmap test results
+ SHADERPERMUTATION_SHADOWMAPPCF2 = 1<<19, ///< (lightsource) use higher quality percentage closer filtering on shadowmap test results
+ SHADERPERMUTATION_SHADOWSAMPLER = 1<<20, ///< (lightsource) use hardware shadowmap test
+ SHADERPERMUTATION_SHADOWMAPVSDCT = 1<<21, ///< (lightsource) use virtual shadow depth cube texture for shadowmap indexing
+ SHADERPERMUTATION_SHADOWMAPORTHO = 1<<22, //< (lightsource) use orthographic shadowmap projection
+ SHADERPERMUTATION_DEFERREDLIGHTMAP = 1<<23, ///< (lightmap) read Texture_ScreenDiffuse/Specular textures and add them on top of lightmapping
+ SHADERPERMUTATION_ALPHAKILL = 1<<24, ///< (deferredgeometry) discard pixel if diffuse texture alpha below 0.5
+ SHADERPERMUTATION_REFLECTCUBE = 1<<25, ///< fake reflections using global cubemap (not HDRI light probe)
+ SHADERPERMUTATION_NORMALMAPSCROLLBLEND = 1<<26, // (water) counter-direction normalmaps scrolling
SHADERPERMUTATION_LIMIT = 1<<27, ///< size of permutations array
SHADERPERMUTATION_COUNT = 27 ///< size of shaderpermutationinfo array
}
{"#define USEBLOOM\n", " bloom"},
{"#define USESPECULAR\n", " specular"},
{"#define USEPOSTPROCESSING\n", " postprocessing"},
- {"#define USEEXACTSPECULARMATH\n", " exactspecularmath"},
{"#define USEREFLECTION\n", " reflection"},
{"#define USEOFFSETMAPPING\n", " offsetmapping"},
{"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
{"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
{"#define USEALPHAKILL\n", " alphakill"},
{"#define USEREFLECTCUBE\n", " reflectcube"},
+ {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
};
-/// this enum is multiplied by SHADERPERMUTATION_MODEBASE
+// this enum selects which of the glslshadermodeinfo entries should be used
typedef enum shadermode_e
{
SHADERMODE_GENERIC, ///< (particles/HUD/etc) vertex color, optionally multiplied by one texture
{
{"cg/default.cg", NULL, "cg/default.cg", "#define MODE_GENERIC\n", " generic"},
{"cg/default.cg", NULL, "cg/default.cg", "#define MODE_POSTPROCESS\n", " postprocess"},
- {"cg/default.cg", NULL, NULL , "#define MODE_DEPTH_OR_SHADOW\n", " depth"},
+ {"cg/default.cg", NULL, "cg/default.cg", "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
{"cg/default.cg", NULL, "cg/default.cg", "#define MODE_FLATCOLOR\n", " flatcolor"},
{"cg/default.cg", NULL, "cg/default.cg", "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
{"cg/default.cg", NULL, "cg/default.cg", "#define MODE_LIGHTMAP\n", " lightmap"},
{
{"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_GENERIC\n", " generic"},
{"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_POSTPROCESS\n", " postprocess"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_DEPTH_OR_SHADOW\n", " depth"},
+ {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
{"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_FLATCOLOR\n", " flatcolor"},
{"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
{"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTMAP\n", " lightmap"},
+ {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_FAKELIGHT\n", " fakelight"},
{"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
{"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
{"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
int loc_ModelToReflectCube;
int loc_ShadowMapMatrix;
int loc_BloomColorSubtract;
+ int loc_NormalmapScrollBlend;
}
r_glsl_permutation_t;
#define SHADERPERMUTATION_HASHSIZE 256
+
+// non-degradable "lightweight" shader parameters to keep the permutations simpler
+// these can NOT degrade! only use for simple stuff
+enum
+{
+ SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
+ SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
+ SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
+ SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
+ SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
+ SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5 ///< postprocess uservec4 is enabled
+};
+#define SHADERSTATICPARMS_COUNT 6
+
+static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
+static int shaderstaticparms_count = 0;
+
+static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
+#define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
+qboolean R_CompileShader_CheckStaticParms(void)
+{
+ static int r_compileshader_staticparms_save[1];
+ memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
+ memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
+
+ // detect all
+ if (r_glsl_saturation_redcompensate.integer)
+ R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
+ if (r_shadow_glossexact.integer)
+ R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
+ if (r_glsl_postprocess.integer)
+ {
+ if (r_glsl_postprocess_uservec1_enable.integer)
+ R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
+ if (r_glsl_postprocess_uservec2_enable.integer)
+ R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
+ if (r_glsl_postprocess_uservec3_enable.integer)
+ R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
+ if (r_glsl_postprocess_uservec4_enable.integer)
+ R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
+ }
+ return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
+}
+
+#define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
+ if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
+ shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
+ else \
+ shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
+void R_CompileShader_AddStaticParms(unsigned int mode, unsigned int permutation)
+{
+ shaderstaticparms_count = 0;
+
+ // emit all
+ R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
+ R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
+ R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
+ R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
+ R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
+ R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
+}
+
/// information about each possible shader permutation
r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
/// currently selected permutation
{
int i;
shadermodeinfo_t *modeinfo = glslshadermodeinfo + mode;
+ char *vertexstring, *geometrystring, *fragmentstring;
+ char permutationname[256];
int vertstrings_count = 0;
int geomstrings_count = 0;
int fragstrings_count = 0;
- char *vertexstring, *geometrystring, *fragmentstring;
- const char *vertstrings_list[32+3];
- const char *geomstrings_list[32+3];
- const char *fragstrings_list[32+3];
- char permutationname[256];
+ const char *vertstrings_list[32+3+SHADERSTATICPARMS_COUNT+1];
+ const char *geomstrings_list[32+3+SHADERSTATICPARMS_COUNT+1];
+ const char *fragstrings_list[32+3+SHADERSTATICPARMS_COUNT+1];
if (p->compiled)
return;
}
}
+ // add static parms
+ R_CompileShader_AddStaticParms(mode, permutation);
+ memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
+ vertstrings_count += shaderstaticparms_count;
+ memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
+ geomstrings_count += shaderstaticparms_count;
+ memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
+ fragstrings_count += shaderstaticparms_count;
+
// now append the shader text itself
vertstrings_list[vertstrings_count++] = vertexstring;
geomstrings_list[geomstrings_count++] = geometrystring;
p->loc_ModelToReflectCube = qglGetUniformLocationARB(p->program, "ModelToReflectCube");
p->loc_ShadowMapMatrix = qglGetUniformLocationARB(p->program, "ShadowMapMatrix");
p->loc_BloomColorSubtract = qglGetUniformLocationARB(p->program, "BloomColorSubtract");
+ p->loc_NormalmapScrollBlend = qglGetUniformLocationARB(p->program, "NormalmapScrollBlend");
// 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);
CGparameter fp_PixelToScreenTexCoord;
CGparameter fp_ModelToReflectCube;
CGparameter fp_BloomColorSubtract;
+ CGparameter fp_NormalmapScrollBlend;
}
r_cg_permutation_t;
{
int i;
shadermodeinfo_t *modeinfo = cgshadermodeinfo + mode;
- int vertstrings_count = 0, vertstring_length = 0;
- int geomstrings_count = 0, geomstring_length = 0;
- int fragstrings_count = 0, fragstring_length = 0;
+ int vertstring_length = 0;
+ int geomstring_length = 0;
+ int fragstring_length = 0;
char *t;
char *vertexstring, *geometrystring, *fragmentstring;
char *vertstring, *geomstring, *fragstring;
- const char *vertstrings_list[32+3];
- const char *geomstrings_list[32+3];
- const char *fragstrings_list[32+3];
char permutationname[256];
char cachename[256];
CGprofile vertexProfile;
CGprofile fragmentProfile;
+ int vertstrings_count = 0;
+ int geomstrings_count = 0;
+ int fragstrings_count = 0;
+ const char *vertstrings_list[32+3+SHADERSTATICPARMS_COUNT+1];
+ const char *geomstrings_list[32+3+SHADERSTATICPARMS_COUNT+1];
+ const char *fragstrings_list[32+3+SHADERSTATICPARMS_COUNT+1];
if (p->compiled)
return;
}
}
+ // add static parms
+ R_CompileShader_AddStaticParms(mode, permutation);
+ memcpy(vertstrings_list + vertstrings_count, shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
+ vertstrings_count += shaderstaticparms_count;
+ memcpy(geomstrings_list + geomstrings_count, shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
+ geomstrings_count += shaderstaticparms_count;
+ memcpy(fragstrings_list + fragstrings_count, shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
+ fragstrings_count += shaderstaticparms_count;
+
// replace spaces in the cachename with _ characters
for (i = 0;cachename[i];i++)
if (cachename[i] == ' ')
p->fp_PixelToScreenTexCoord = cgGetNamedParameter(p->fprogram, "PixelToScreenTexCoord");
p->fp_ModelToReflectCube = cgGetNamedParameter(p->fprogram, "ModelToReflectCube");
p->fp_BloomColorSubtract = cgGetNamedParameter(p->fprogram, "BloomColorSubtract");
+ p->fp_NormalmapScrollBlend = cgGetNamedParameter(p->fprogram, "NormalmapScrollBlend");
CHECKCGERROR
}
D3DPSREGISTER_BloomColorSubtract = 43,
D3DPSREGISTER_ViewToLight = 44, // float4x4
D3DPSREGISTER_ModelToReflectCube = 48, // float4x4
- // next at 52
+ D3DPSREGISTER_NormalmapScrollBlend = 52,
+ // next at 53
}
D3DPSREGISTER_t;
{
int i;
shadermodeinfo_t *modeinfo = hlslshadermodeinfo + mode;
- int vertstrings_count = 0, vertstring_length = 0;
- int geomstrings_count = 0, geomstring_length = 0;
- int fragstrings_count = 0, fragstring_length = 0;
+ int vertstring_length = 0;
+ int geomstring_length = 0;
+ int fragstring_length = 0;
char *t;
char *vertexstring, *geometrystring, *fragmentstring;
char *vertstring, *geomstring, *fragstring;
- const char *vertstrings_list[32+3];
- const char *geomstrings_list[32+3];
- const char *fragstrings_list[32+3];
char permutationname[256];
char cachename[256];
+ int vertstrings_count = 0;
+ int geomstrings_count = 0;
+ int fragstrings_count = 0;
+ const char *vertstrings_list[32+3+SHADERSTATICPARMS_COUNT+1];
+ const char *geomstrings_list[32+3+SHADERSTATICPARMS_COUNT+1];
+ const char *fragstrings_list[32+3+SHADERSTATICPARMS_COUNT+1];
if (p->compiled)
return;
strlcat(cachename, "hlsl/", sizeof(cachename));
// define HLSL so that the shader can tell apart the HLSL compiler and the Cg compiler
+ vertstrings_count = 0;
+ geomstrings_count = 0;
+ fragstrings_count = 0;
vertstrings_list[vertstrings_count++] = "#define HLSL\n";
geomstrings_list[geomstrings_count++] = "#define HLSL\n";
fragstrings_list[fragstrings_count++] = "#define HLSL\n";
}
}
+ // add static parms
+ R_CompileShader_AddStaticParms(mode, permutation);
+ memcpy(vertstrings_list + vertstrings_count, shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
+ vertstrings_count += shaderstaticparms_count;
+ memcpy(geomstrings_list + geomstrings_count, shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
+ geomstrings_count += shaderstaticparms_count;
+ memcpy(fragstrings_list + fragstrings_count, shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
+ fragstrings_count += shaderstaticparms_count;
+
// replace spaces in the cachename with _ characters
for (i = 0;cachename[i];i++)
if (cachename[i] == ' ')
{
case RENDERPATH_D3D9:
#ifdef SUPPORTD3D
- R_SetupShader_SetPermutationHLSL(SHADERMODE_GENERIC, (first ? SHADERPERMUTATION_DIFFUSE : 0) | (second ? SHADERPERMUTATION_SPECULAR : 0) | (r_shadow_glossexact.integer ? SHADERPERMUTATION_EXACTSPECULARMATH : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
+ R_SetupShader_SetPermutationHLSL(SHADERMODE_GENERIC, SHADERPERMUTATION_VIEWTINT | (first ? SHADERPERMUTATION_DIFFUSE : 0) | (second ? SHADERPERMUTATION_SPECULAR : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
R_Mesh_TexBind(GL20TU_FIRST , first );
R_Mesh_TexBind(GL20TU_SECOND, second);
#endif
Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
break;
case RENDERPATH_GL20:
- R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, (first ? SHADERPERMUTATION_DIFFUSE : 0) | (second ? SHADERPERMUTATION_SPECULAR : 0) | (r_shadow_glossexact.integer ? SHADERPERMUTATION_EXACTSPECULARMATH : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
+ R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, SHADERPERMUTATION_VIEWTINT | (first ? SHADERPERMUTATION_DIFFUSE : 0) | (second ? SHADERPERMUTATION_SPECULAR : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
R_Mesh_TexBind(GL20TU_FIRST , first );
R_Mesh_TexBind(GL20TU_SECOND, second);
break;
case RENDERPATH_CGGL:
#ifdef SUPPORTCG
CHECKCGERROR
- R_SetupShader_SetPermutationCG(SHADERMODE_GENERIC, (first ? SHADERPERMUTATION_DIFFUSE : 0) | (second ? SHADERPERMUTATION_SPECULAR : 0) | (r_shadow_glossexact.integer ? SHADERPERMUTATION_EXACTSPECULARMATH : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
+ R_SetupShader_SetPermutationCG(SHADERMODE_GENERIC, SHADERPERMUTATION_VIEWTINT | (first ? SHADERPERMUTATION_DIFFUSE : 0) | (second ? SHADERPERMUTATION_SPECULAR : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
if (r_cg_permutation->fp_Texture_First ) CG_BindTexture(r_cg_permutation->fp_Texture_First , first );CHECKCGERROR
if (r_cg_permutation->fp_Texture_Second) CG_BindTexture(r_cg_permutation->fp_Texture_Second, second);CHECKCGERROR
#endif
if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
{
mode = SHADERMODE_WATER;
+ if (rsurface.texture->r_water_waterscroll[0] && rsurface.texture->r_water_waterscroll[1])
+ permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND;
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
allow_colormod = R_BlendFuncAllowsColormod(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
if (diffusescale > 0)
permutation |= SHADERPERMUTATION_DIFFUSE;
if (specularscale > 0)
- {
permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
- if (r_shadow_glossexact.integer)
- permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
- }
if (r_refdef.fogenabled)
permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
if (rsurface.texture->colormapping)
permutation |= SHADERPERMUTATION_GLOW;
permutation |= SHADERPERMUTATION_DIFFUSE;
if (specularscale > 0)
- {
permutation |= SHADERPERMUTATION_SPECULAR;
- if (r_shadow_glossexact.integer)
- permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
- }
if (r_refdef.fogenabled)
permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
if (rsurface.texture->colormapping)
mode = SHADERMODE_FAKELIGHT;
permutation |= SHADERPERMUTATION_DIFFUSE;
if (specularscale > 0)
- {
permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
- if (r_shadow_glossexact.integer)
- permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
- }
}
else if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
{
mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
permutation |= SHADERPERMUTATION_DIFFUSE;
if (specularscale > 0)
- {
permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
- if (r_shadow_glossexact.integer)
- permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
- }
}
else if (r_glsl_deluxemapping.integer >= 2 && rsurface.uselightmaptexture)
{
mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
permutation |= SHADERPERMUTATION_DIFFUSE;
if (specularscale > 0)
- {
permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
- if (r_shadow_glossexact.integer)
- permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
- }
}
else if (rsurface.uselightmaptexture)
{
// additive passes are only darkened by fog, not tinted
hlslPSSetParameter3f(D3DPSREGISTER_FogColor, 0, 0, 0);
- hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, rsurface.texture->specularpower * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));
+ hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f));
}
else
{
hlslPSSetParameter4f(D3DPSREGISTER_ReflectColor, rsurface.texture->reflectcolor4f[0], rsurface.texture->reflectcolor4f[1], rsurface.texture->reflectcolor4f[2], rsurface.texture->reflectcolor4f[3] * rsurface.texture->lightmapcolor[3]);
hlslPSSetParameter1f(D3DPSREGISTER_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin);
hlslPSSetParameter1f(D3DPSREGISTER_ReflectOffset, rsurface.texture->reflectmin);
- hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, rsurface.texture->specularpower * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));
+ hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f));
+ if (mode == SHADERMODE_WATER)
+ hlslPSSetParameter2f(D3DPSREGISTER_NormalmapScrollBlend, rsurface.texture->r_water_waterscroll[0], rsurface.texture->r_water_waterscroll[1]);
}
hlslPSSetParameter2f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
// 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_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));
+ if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f));
}
else
{
}
else if (mode == SHADERMODE_LIGHTDIRECTION)
{
- if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Ambient, (r_refdef.scene.ambient + rsurface.modellight_ambient[0] * r_refdef.lightmapintensity) * colormod[0], (r_refdef.scene.ambient + rsurface.modellight_ambient[1] * r_refdef.lightmapintensity) * colormod[1], (r_refdef.scene.ambient + rsurface.modellight_ambient[2] * r_refdef.lightmapintensity) * colormod[2]);
+ if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Ambient, (r_refdef.scene.ambient + rsurface.modellight_ambient[0] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[0], (r_refdef.scene.ambient + rsurface.modellight_ambient[1] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[1], (r_refdef.scene.ambient + rsurface.modellight_ambient[2] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[2]);
if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Diffuse, r_refdef.lightmapintensity * colormod[0], r_refdef.lightmapintensity * colormod[1], r_refdef.lightmapintensity * colormod[2]);
if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3fARB(r_glsl_permutation->loc_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale);
if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3fARB(r_glsl_permutation->loc_DeferredMod_Diffuse, colormod[0] * r_shadow_deferred_8bitrange.value, colormod[1] * r_shadow_deferred_8bitrange.value, colormod[2] * r_shadow_deferred_8bitrange.value);
if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3fARB(r_glsl_permutation->loc_DeferredMod_Specular, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value);
- if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, rsurface.modellight_diffuse[0], rsurface.modellight_diffuse[1], rsurface.modellight_diffuse[2]);
+ if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, rsurface.modellight_diffuse[0] * r_refdef.scene.rtlightstylevalue[0], rsurface.modellight_diffuse[1] * r_refdef.scene.rtlightstylevalue[0], rsurface.modellight_diffuse[2] * r_refdef.scene.rtlightstylevalue[0]);
if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);
}
else
if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_ReflectColor, rsurface.texture->reflectcolor4f[0], rsurface.texture->reflectcolor4f[1], rsurface.texture->reflectcolor4f[2], rsurface.texture->reflectcolor4f[3] * rsurface.texture->lightmapcolor[3]);
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_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));
+ if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f));
+ if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2fARB(r_glsl_permutation->loc_NormalmapScrollBlend, rsurface.texture->r_water_waterscroll[0], rsurface.texture->r_water_waterscroll[1]);
}
if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currenttexmatrix, m16f);qglUniformMatrix4fvARB(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fvARB(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
// additive passes are only darkened by fog, not tinted
if (r_cg_permutation->fp_FogColor) cgGLSetParameter3f(r_cg_permutation->fp_FogColor, 0, 0, 0);CHECKCGERROR
- if (r_cg_permutation->fp_SpecularPower) cgGLSetParameter1f(r_cg_permutation->fp_SpecularPower, rsurface.texture->specularpower * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));CHECKCGERROR
+ if (r_cg_permutation->fp_SpecularPower) cgGLSetParameter1f(r_cg_permutation->fp_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f));CHECKCGERROR
}
else
{
if (r_cg_permutation->fp_ReflectColor) cgGLSetParameter4fv(r_cg_permutation->fp_ReflectColor, rsurface.texture->reflectcolor4f[0], rsurface.texture->reflectcolor4f[1], rsurface.texture->reflectcolor4f[2], rsurface.texture->reflectcolor4f[3] * rsurface.texture->lightmapcolor[3]);CHECKCGERROR
if (r_cg_permutation->fp_ReflectFactor) cgGLSetParameter1f(r_cg_permutation->fp_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin);CHECKCGERROR
if (r_cg_permutation->fp_ReflectOffset) cgGLSetParameter1f(r_cg_permutation->fp_ReflectOffset, rsurface.texture->reflectmin);CHECKCGERROR
- if (r_cg_permutation->fp_SpecularPower) cgGLSetParameter1f(r_cg_permutation->fp_SpecularPower, rsurface.texture->specularpower * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));CHECKCGERROR
+ if (r_cg_permutation->fp_SpecularPower) cgGLSetParameter1f(r_cg_permutation->fp_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f));CHECKCGERROR
+ if (r_cg_permutation->fp_NormalmapScrollBlend) cgGLSetParameter2f(r_cg_permutation->fp_NormalmapScrollBlend, rsurface.texture->r_water_waterscroll[0], rsurface.texture->r_water_waterscroll[1]);
}
if (r_cg_permutation->fp_ShadowMap_TextureScale) cgGLSetParameter2f(r_cg_permutation->fp_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);CHECKCGERROR
if (r_cg_permutation->fp_ShadowMap_Parameters) cgGLSetParameter4f(r_cg_permutation->fp_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);CHECKCGERROR
if (diffusescale > 0)
permutation |= SHADERPERMUTATION_DIFFUSE;
if (specularscale > 0)
- {
permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
- if (r_shadow_glossexact.integer)
- permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
- }
if (r_shadow_usingshadowmap2d)
{
permutation |= SHADERPERMUTATION_SHADOWMAP2D;
hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Specular, lightcolorbase[0] * specularscale * range, lightcolorbase[1] * specularscale * range, lightcolorbase[2] * specularscale * range);
hlslPSSetParameter2f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
- hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));
+ hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f));
hlslPSSetParameter2f(D3DPSREGISTER_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
hlslPSSetParameter2f(D3DPSREGISTER_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height);
if (r_glsl_permutation->loc_DeferredColor_Specular >= 0) qglUniform3fARB( r_glsl_permutation->loc_DeferredColor_Specular , lightcolorbase[0] * specularscale * range, lightcolorbase[1] * specularscale * range, lightcolorbase[2] * specularscale * range);
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_SpecularPower >= 0) qglUniform1fARB( r_glsl_permutation->loc_SpecularPower , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));
+ if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB( r_glsl_permutation->loc_SpecularPower , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f));
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]);
if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2fARB(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
if (r_cg_permutation->fp_DeferredColor_Specular ) cgGLSetParameter3f(r_cg_permutation->fp_DeferredColor_Specular, lightcolorbase[0] * specularscale * range, lightcolorbase[1] * specularscale * range, lightcolorbase[2] * specularscale * range);CHECKCGERROR
if (r_cg_permutation->fp_ShadowMap_TextureScale ) cgGLSetParameter2f(r_cg_permutation->fp_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);CHECKCGERROR
if (r_cg_permutation->fp_ShadowMap_Parameters ) cgGLSetParameter4f(r_cg_permutation->fp_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);CHECKCGERROR
- if (r_cg_permutation->fp_SpecularPower ) cgGLSetParameter1f(r_cg_permutation->fp_SpecularPower, (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * ((permutation & SHADERPERMUTATION_EXACTSPECULARMATH) ? 0.25f : 1.0f));CHECKCGERROR
+ if (r_cg_permutation->fp_SpecularPower ) cgGLSetParameter1f(r_cg_permutation->fp_SpecularPower, (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f));CHECKCGERROR
if (r_cg_permutation->fp_ScreenToDepth ) cgGLSetParameter2f(r_cg_permutation->fp_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);CHECKCGERROR
if (r_cg_permutation->fp_PixelToScreenTexCoord ) cgGLSetParameter2f(r_cg_permutation->fp_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height);CHECKCGERROR
r_texture_gammaramps = NULL;
r_texture_numcubemaps = 0;
- r_loaddds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_load.integer;
+ r_loaddds = r_texture_dds_load.integer;
r_savedds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
switch(vid.renderpath)
Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
+ Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
+ Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
+ Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
+ Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
+
Cvar_RegisterVariable(&r_water);
Cvar_RegisterVariable(&r_water_resolutionmultiplier);
Cvar_RegisterVariable(&r_water_clippingplanebias);
Cvar_RegisterVariable(&r_water_refractdistort);
Cvar_RegisterVariable(&r_water_reflectdistort);
+ Cvar_RegisterVariable(&r_water_scissormode);
Cvar_RegisterVariable(&r_lerpsprites);
Cvar_RegisterVariable(&r_lerpmodels);
Cvar_RegisterVariable(&r_lerplightstyles);
Cvar_RegisterVariable(&gl_lightmaps);
Cvar_RegisterVariable(&r_test);
Cvar_RegisterVariable(&r_glsl_saturation);
+ Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
Cvar_RegisterVariable(&r_framedatasize);
if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
Cvar_SetValue("r_fullbrights", 0);
{
vec3_t org;
Matrix4x4_OriginFromMatrix(&ent->matrix, org);
- r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal);
+
+ // complete lightning for lit sprites
+ // todo: make a EF_ field so small ents could be lit purely by modellight and skipping real rtlight pass (like EF_NORTLIGHT)?
+ if (ent->model->type == mod_sprite && !(ent->model->data_textures[0].basematerialflags & MATERIALFLAG_FULLBRIGHT))
+ {
+ if (ent->model->sprite.sprnum_type == SPR_OVERHEAD) // apply offset for overhead sprites
+ org[2] = org[2] + r_overheadsprites_pushback.value;
+ R_CompleteLightPoint(ent->modellight_ambient, ent->modellight_diffuse, ent->modellight_lightdir, org, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT);
+ }
+ else
+ r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal);
+
if(ent->flags & RENDER_EQUALIZE)
{
// first fix up ambient lighting...
if(r_equalize_entities_to.value > 0 && r_equalize_entities_by.value != 0)
{
- VectorMA(ent->modellight_ambient, 0.25f, ent->modellight_diffuse, avg);
- f = 0.299f * avg[0] + 0.587f * avg[1] + 0.114f * avg[2];
+ fa = 0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2];
+ fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2];
+ f = fa + 0.25 * fd;
if(f > 0)
{
- f = pow(f / r_equalize_entities_to.value, -r_equalize_entities_by.value);
- VectorScale(ent->modellight_ambient, f, ent->modellight_ambient);
- VectorScale(ent->modellight_diffuse, f, ent->modellight_diffuse);
+ // adjust brightness and saturation to target
+ avg[0] = avg[1] = avg[2] = fa / f;
+ VectorLerp(ent->modellight_ambient, r_equalize_entities_by.value, avg, ent->modellight_ambient);
+ avg[0] = avg[1] = avg[2] = fd / f;
+ VectorLerp(ent->modellight_diffuse, r_equalize_entities_by.value, avg, ent->modellight_diffuse);
}
}
}
}
}
-static void R_View_SetFrustum(void)
+static void R_View_SetFrustum(const int *scissor)
{
int i;
- double slopex, slopey;
- vec3_t forward, left, up, origin;
+ double fpx = +1, fnx = -1, fpy = +1, fny = -1;
+ vec3_t forward, left, up, origin, v;
+
+ if(scissor)
+ {
+ // flipped x coordinates (because x points left here)
+ fpx = 1.0 - 2.0 * (scissor[0] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
+ fnx = 1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
+
+ // D3D Y coordinate is top to bottom, OpenGL is bottom to top, fix the D3D one
+ switch(vid.renderpath)
+ {
+ case RENDERPATH_D3D9:
+ case RENDERPATH_D3D10:
+ case RENDERPATH_D3D11:
+ // non-flipped y coordinates
+ fny = -1.0 + 2.0 * (vid.height - scissor[1] - scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
+ fpy = -1.0 + 2.0 * (vid.height - scissor[1] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
+ break;
+ case RENDERPATH_GL11:
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL20:
+ case RENDERPATH_CGGL:
+ // non-flipped y coordinates
+ fny = -1.0 + 2.0 * (scissor[1] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
+ fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
+ break;
+ }
+ }
// we can't trust r_refdef.view.forward and friends in reflected scenes
Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
if (r_refdef.view.useperspective)
{
- slopex = 1.0 / r_refdef.view.frustum_x;
- slopey = 1.0 / r_refdef.view.frustum_y;
- VectorMA(forward, -slopex, left, r_refdef.view.frustum[0].normal);
- VectorMA(forward, slopex, left, r_refdef.view.frustum[1].normal);
- VectorMA(forward, -slopey, up , r_refdef.view.frustum[2].normal);
- VectorMA(forward, slopey, up , r_refdef.view.frustum[3].normal);
- VectorCopy(forward, r_refdef.view.frustum[4].normal);
+ // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
+ VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[0]);
+ VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[1]);
+ VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[2]);
+ VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[3]);
+
+ // then the normals from the corners relative to origin
+ CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
+ CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
+ CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
+ CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
+
+ // in a NORMAL view, forward cross left == up
+ // in a REFLECTED view, forward cross left == down
+ // so our cross products above need to be adjusted for a left handed coordinate system
+ CrossProduct(forward, left, v);
+ if(DotProduct(v, up) < 0)
+ {
+ VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
+ VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
+ VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
+ VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
+ }
// Leaving those out was a mistake, those were in the old code, and they
// fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
VectorNormalize(r_refdef.view.frustum[2].normal);
VectorNormalize(r_refdef.view.frustum[3].normal);
- // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
- VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, -1024 * r_refdef.view.frustum_x, left, -1024 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[0]);
- VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, 1024 * r_refdef.view.frustum_x, left, -1024 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[1]);
- VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, -1024 * r_refdef.view.frustum_x, left, 1024 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[2]);
- VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, 1024 * r_refdef.view.frustum_x, left, 1024 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[3]);
+ // make the corners absolute
+ VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
+ VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
+ VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
+ VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
+
+ // one more normal
+ VectorCopy(forward, r_refdef.view.frustum[4].normal);
r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
//PlaneClassify(&frustum[4]);
}
+void R_View_UpdateWithScissor(const int *myscissor)
+{
+ R_Main_ResizeViewCache();
+ R_View_SetFrustum(myscissor);
+ R_View_WorldVisibility(r_refdef.view.useclipplane);
+ R_View_UpdateEntityVisible();
+ R_View_UpdateEntityLighting();
+}
+
void R_View_Update(void)
{
R_Main_ResizeViewCache();
- R_View_SetFrustum();
+ R_View_SetFrustum(NULL);
R_View_WorldVisibility(r_refdef.view.useclipplane);
R_View_UpdateEntityVisible();
R_View_UpdateEntityLighting();
p->materialflags = 0;
p->pvsvalid = false;
p->camera_entity = t->camera_entity;
+ VectorCopy(surface->mins, p->mins);
+ VectorCopy(surface->maxs, p->maxs);
+ }
+ else
+ {
+ // merge mins/maxs
+ p->mins[0] = min(p->mins[0], surface->mins[0]);
+ p->mins[1] = min(p->mins[1], surface->mins[1]);
+ p->mins[2] = min(p->mins[2], surface->mins[2]);
+ p->maxs[0] = max(p->maxs[0], surface->maxs[0]);
+ p->maxs[1] = max(p->maxs[1], surface->maxs[1]);
+ p->maxs[2] = max(p->maxs[2], surface->maxs[2]);
}
// merge this surface's materialflags into the waterplane
p->materialflags |= t->currentmaterialflags;
static void R_Water_ProcessPlanes(void)
{
+ int myscissor[4];
r_refdef_view_t originalview;
r_refdef_view_t myview;
int planeindex;
if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
{
r_refdef.view = myview;
+ if(r_water_scissormode.integer)
+ {
+ R_SetupView(true);
+ if(R_ScissorForBBox(p->mins, p->maxs, myscissor))
+ continue; // FIXME the plane then still may get rendered but with broken texture, but it sure won't be visible
+ }
+
// render reflected scene and copy into texture
Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
// update the r_refdef.view.origin because otherwise the sky renders at the wrong location (amongst other problems)
Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
r_refdef.view.clipplane = p->plane;
+
// reverse the cullface settings for this render
r_refdef.view.cullface_front = GL_FRONT;
r_refdef.view.cullface_back = GL_BACK;
R_ResetViewRendering3D();
R_ClearScreen(r_refdef.fogenabled);
- R_View_Update();
+ if(r_water_scissormode.integer & 2)
+ R_View_UpdateWithScissor(myscissor);
+ else
+ R_View_Update();
+ if(r_water_scissormode.integer & 1)
+ GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
R_RenderScene();
R_Mesh_CopyToTexture(p->texture_reflection, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
// (except that a clipping plane should be used to hide everything on one side of the water, and the viewer's weapon model should be omitted)
if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
{
- r_waterstate.renderingrefraction = true;
r_refdef.view = myview;
+ if(r_water_scissormode.integer)
+ {
+ R_SetupView(true);
+ if(R_ScissorForBBox(p->mins, p->maxs, myscissor))
+ continue; // FIXME the plane then still may get rendered but with broken texture, but it sure won't be visible
+ }
+
+ r_waterstate.renderingrefraction = true;
r_refdef.view.clipplane = p->plane;
VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
R_ResetViewRendering3D();
R_ClearScreen(r_refdef.fogenabled);
- R_View_Update();
+ if(r_water_scissormode.integer & 2)
+ R_View_UpdateWithScissor(myscissor);
+ else
+ R_View_Update();
+ if(r_water_scissormode.integer & 1)
+ GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
R_RenderScene();
R_Mesh_CopyToTexture(p->texture_refraction, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
}
+ // note: all of the view is used for displaying... so
+ // there is no use in scissoring
+
// reverse the cullface settings for this render
r_refdef.view.cullface_front = GL_FRONT;
r_refdef.view.cullface_back = GL_BACK;
{
int oldwidth, oldheight;
float oldcolorscale;
+ int oldwaterstate;
+ oldwaterstate = r_waterstate.enabled;
oldcolorscale = r_refdef.view.colorscale;
oldwidth = r_refdef.view.width;
oldheight = r_refdef.view.height;
r_refdef.view.width = r_bloomstate.bloomwidth;
r_refdef.view.height = r_bloomstate.bloomheight;
+ if(r_hdr.integer < 2)
+ r_waterstate.enabled = false;
+
// TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer? it might improve SLI performance.
// TODO: add exposure compensation features
// TODO: add fp16 framebuffer support (using GL_EXT_framebuffer_object)
// only do secondary renders with HDR if r_hdr is 2 or higher
r_waterstate.numwaterplanes = 0;
- if (r_waterstate.enabled && r_hdr.integer >= 2)
+ if (r_waterstate.enabled)
R_RenderWaterPlanes();
r_refdef.view.showdebug = true;
R_Bloom_MakeTexture();
// restore the view settings
+ r_waterstate.enabled = oldwaterstate;
r_refdef.view.width = oldwidth;
r_refdef.view.height = oldheight;
r_refdef.view.colorscale = oldcolorscale;
#define sscanf sscanf_s
#endif
memset(uservecs, 0, sizeof(uservecs));
- sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
- sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
- sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
- sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
+ if (r_glsl_postprocess_uservec1_enable.integer)
+ sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
+ if (r_glsl_postprocess_uservec2_enable.integer)
+ sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
+ if (r_glsl_postprocess_uservec3_enable.integer)
+ sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
+ if (r_glsl_postprocess_uservec4_enable.integer)
+ sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
R_ResetViewRendering2D();
GL_Color(1, 1, 1, 1);
r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
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.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
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 (FAKELIGHT_ENABLED)
*/
void R_RenderView(void)
{
+ matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
if (r_timereport_active)
R_TimeReport("start");
r_textureframe++; // used only by R_GetCurrentTexture
rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
+ if(R_CompileShader_CheckStaticParms())
+ R_GLSL_Restart_f();
+
if (!r_drawentities.integer)
r_refdef.scene.numentities = 0;
R_AnimCache_ClearCache();
R_FrameData_NewFrame();
+ /* adjust for stereo display */
+ if(R_Stereo_Active())
+ {
+ Matrix4x4_CreateFromQuakeEntity(&offsetmatrix, 0, r_stereo_separation.value * (0.5f - r_stereo_side), 0, 0, r_stereo_angle.value * (0.5f - r_stereo_side), 0, 1);
+ Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
+ }
+
if (r_refdef.view.isoverlay)
{
// TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
R_RenderScene();
+ r_refdef.view.matrix = originalmatrix;
+
CHECKGLERROR
return;
}
if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
+ {
+ r_refdef.view.matrix = originalmatrix;
return; //Host_Error ("R_RenderView: NULL worldmodel");
+ }
r_refdef.view.colorscale = r_hdr_scenebrightness.value;
GL_Scissor(0, 0, vid.width, vid.height);
GL_ScissorTest(false);
+
+ r_refdef.view.matrix = originalmatrix;
+
CHECKGLERROR
}
R_TimeReport("coronas");
}
+#if 0
+ {
+ GL_DepthTest(false);
+ qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ GL_Color(1, 1, 1, 1);
+ qglBegin(GL_POLYGON);
+ qglVertex3f(r_refdef.view.frustumcorner[0][0], r_refdef.view.frustumcorner[0][1], r_refdef.view.frustumcorner[0][2]);
+ qglVertex3f(r_refdef.view.frustumcorner[1][0], r_refdef.view.frustumcorner[1][1], r_refdef.view.frustumcorner[1][2]);
+ qglVertex3f(r_refdef.view.frustumcorner[3][0], r_refdef.view.frustumcorner[3][1], r_refdef.view.frustumcorner[3][2]);
+ qglVertex3f(r_refdef.view.frustumcorner[2][0], r_refdef.view.frustumcorner[2][1], r_refdef.view.frustumcorner[2][2]);
+ qglEnd();
+ qglBegin(GL_POLYGON);
+ qglVertex3f(r_refdef.view.frustumcorner[0][0] + 1000 * r_refdef.view.forward[0], r_refdef.view.frustumcorner[0][1] + 1000 * r_refdef.view.forward[1], r_refdef.view.frustumcorner[0][2] + 1000 * r_refdef.view.forward[2]);
+ qglVertex3f(r_refdef.view.frustumcorner[1][0] + 1000 * r_refdef.view.forward[0], r_refdef.view.frustumcorner[1][1] + 1000 * r_refdef.view.forward[1], r_refdef.view.frustumcorner[1][2] + 1000 * r_refdef.view.forward[2]);
+ qglVertex3f(r_refdef.view.frustumcorner[3][0] + 1000 * r_refdef.view.forward[0], r_refdef.view.frustumcorner[3][1] + 1000 * r_refdef.view.forward[1], r_refdef.view.frustumcorner[3][2] + 1000 * r_refdef.view.forward[2]);
+ qglVertex3f(r_refdef.view.frustumcorner[2][0] + 1000 * r_refdef.view.forward[0], r_refdef.view.frustumcorner[2][1] + 1000 * r_refdef.view.forward[1], r_refdef.view.frustumcorner[2][2] + 1000 * r_refdef.view.forward[2]);
+ qglEnd();
+ qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+#endif
+
// don't let sound skip if going slow
if (r_refdef.scene.extraupdate)
S_ExtraUpdate ();
GL_DepthMask(false);
GL_DepthRange(0, 1);
GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
- R_Mesh_ResetTextureState();
+// R_Mesh_ResetTextureState();
vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2]; //
vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
- R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
for (i = 0, c = color4f;i < 6;i++, c += 4)
{
c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
}
}
- R_Mesh_ResetTextureState();
+// R_Mesh_ResetTextureState();
+ R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
}
void RSurf_ActiveWorldEntity(void)
{
+ int newvertices;
dp_model_t *model = r_refdef.scene.worldmodel;
//if (rsurface.entity == r_refdef.scene.worldentity)
// return;
rsurface.ent_qwskin = -1;
rsurface.ent_shadertime = 0;
rsurface.ent_flags = r_refdef.scene.worldentity->flags;
- if (rsurface.array_size < model->surfmesh.num_vertices)
- R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
+ newvertices = max(model->surfmesh.num_vertices, model->surfmesh.num_triangles);
+ if (rsurface.array_size < newvertices)
+ R_Mesh_ResizeArrays(newvertices);
rsurface.matrix = identitymatrix;
rsurface.inversematrix = identitymatrix;
rsurface.matrixscale = 1;
void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
{
+ int newvertices;
dp_model_t *model = ent->model;
//if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
// return;
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;
rsurface.ent_flags = ent->flags;
- if (rsurface.array_size < model->surfmesh.num_vertices)
- R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
+ newvertices = max(model->surfmesh.num_vertices, model->surfmesh.num_triangles);
+ if (rsurface.array_size < newvertices)
+ R_Mesh_ResizeArrays(newvertices);
rsurface.matrix = ent->matrix;
rsurface.inversematrix = ent->inversematrix;
rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
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)
{
- int i;
+ int newvertices;
rsurface.entity = r_refdef.scene.worldentity;
rsurface.skeleton = NULL;
rsurface.ent_flags = entflags;
rsurface.modelnumvertices = numvertices;
rsurface.modelnumtriangles = numtriangles;
- if (rsurface.array_size < rsurface.modelnumvertices)
- R_Mesh_ResizeArrays(rsurface.modelnumvertices);
+ newvertices = max(rsurface.modelnumvertices, rsurface.modelnumtriangles);
+ if (rsurface.array_size < newvertices)
+ R_Mesh_ResizeArrays(newvertices);
rsurface.matrix = *matrix;
rsurface.inversematrix = *inversematrix;
rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
rsurface.modeltvector3f = rsurface.array_modeltvector3f;
}
}
-
- // now convert arrays into vertexmesh structs
- for (i = 0;i < numvertices;i++)
- {
- VectorCopy(rsurface.modelvertex3f + 3*i, rsurface.array_modelvertexposition[i].vertex3f);
- VectorCopy(rsurface.modelvertex3f + 3*i, rsurface.array_modelvertexmesh[i].vertex3f);
- if (rsurface.modelsvector3f)
- VectorCopy(rsurface.modelsvector3f + 3*i, rsurface.array_modelvertexmesh[i].svector3f);
- if (rsurface.modeltvector3f)
- VectorCopy(rsurface.modeltvector3f + 3*i, rsurface.array_modelvertexmesh[i].tvector3f);
- if (rsurface.modelnormal3f)
- VectorCopy(rsurface.modelnormal3f + 3*i, rsurface.array_modelvertexmesh[i].normal3f);
- if (rsurface.modellightmapcolor4f)
- Vector4Scale(rsurface.modellightmapcolor4f + 4*i, 255.0f, rsurface.array_modelvertexmesh[i].color4ub);
- if (rsurface.modeltexcoordtexture2f)
- Vector2Copy(rsurface.modeltexcoordtexture2f + 2*i, rsurface.array_modelvertexmesh[i].texcoordtexture2f);
- if (rsurface.modeltexcoordlightmap2f)
- Vector2Copy(rsurface.modeltexcoordlightmap2f + 2*i, rsurface.array_modelvertexmesh[i].texcoordlightmap2f);
- }
}
float RSurf_FogPoint(const float *v)
endvertex = surfaceendvertex;
numtriangles += surfacenumtriangles;
}
- if (!numtriangles)
- return;
// we now know the vertex range used, and if there are any gaps in it
rsurface.batchfirstvertex = firstvertex;
}
}
// if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
- Mod_BuildNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchnormal3f, true);
- Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, true);
+ Mod_BuildNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
+ Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
rsurface.batchvertex3f = rsurface.array_batchvertex3f;
rsurface.batchvertex3f_vertexbuffer = NULL;
rsurface.batchvertex3f_bufferoffset = 0;
rsurface.batchvertex3f_bufferoffset = 0;
if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
{
- Mod_BuildNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchnormal3f, true);
+ Mod_BuildNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
rsurface.batchnormal3f = rsurface.array_batchnormal3f;
rsurface.batchnormal3f_vertexbuffer = NULL;
rsurface.batchnormal3f_bufferoffset = 0;
}
if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
{
- Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, true);
+ Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
rsurface.batchsvector3f = rsurface.array_batchsvector3f;
rsurface.batchsvector3f_vertexbuffer = NULL;
rsurface.batchsvector3f_bufferoffset = 0;
rsurface.batchnormal3f_bufferoffset = 0;
if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
{
- Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, true);
+ Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
rsurface.batchsvector3f = rsurface.array_batchsvector3f;
rsurface.batchsvector3f_vertexbuffer = NULL;
rsurface.batchsvector3f_bufferoffset = 0;
VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.array_batchvertex3f + 3*j);
}
// if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
- Mod_BuildNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchnormal3f, true);
+ Mod_BuildNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
rsurface.batchvertex3f = rsurface.array_batchvertex3f;
rsurface.batchvertex3f_vertexbuffer = NULL;
rsurface.batchvertex3f_bufferoffset = 0;
rsurface.batchnormal3f_bufferoffset = 0;
if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
{
- Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, true);
+ Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
rsurface.batchsvector3f = rsurface.array_batchsvector3f;
rsurface.batchsvector3f_vertexbuffer = NULL;
rsurface.batchsvector3f_bufferoffset = 0;
VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.array_batchvertex3f + 3*j);
}
// if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
- Mod_BuildNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchnormal3f, true);
+ Mod_BuildNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
rsurface.batchvertex3f = rsurface.array_batchvertex3f;
rsurface.batchvertex3f_vertexbuffer = NULL;
rsurface.batchvertex3f_bufferoffset = 0;
rsurface.batchnormal3f_bufferoffset = 0;
if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
{
- Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, true);
+ Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
rsurface.batchsvector3f = rsurface.array_batchsvector3f;
rsurface.batchsvector3f_vertexbuffer = NULL;
rsurface.batchsvector3f_bufferoffset = 0;
void RSurf_DrawBatch(void)
{
+ // sometimes a zero triangle surface (usually a degenerate patch) makes it
+ // through the pipeline, killing it earlier in the pipeline would have
+ // per-surface overhead rather than per-batch overhead, so it's best to
+ // reject it here, before it hits glDraw.
+ if (rsurface.batchnumtriangles == 0)
+ return;
+#if 0
+ // batch debugging code
+ if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
+ {
+ int i;
+ int j;
+ int c;
+ const int *e;
+ e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
+ for (i = 0;i < rsurface.batchnumtriangles*3;i++)
+ {
+ c = e[i];
+ for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
+ {
+ if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
+ {
+ if (rsurface.modelsurfaces[j].texture != rsurface.texture)
+ Sys_Error("RSurf_DrawBatch: index %i uses different texture (%s) than surface %i which it belongs to (which uses %s)\n", c, rsurface.texture->name, j, rsurface.modelsurfaces[j].texture->name);
+ break;
+ }
+ }
+ }
+ }
+#endif
R_Mesh_Draw(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchfirsttriangle, rsurface.batchnumtriangles, rsurface.batchelement3i, rsurface.batchelement3i_indexbuffer, rsurface.batchelement3i_bufferoffset, rsurface.batchelement3s, rsurface.batchelement3s_indexbuffer, rsurface.batchelement3s_bufferoffset);
}
vec3_t vert;
const float *v;
r_waterstate_waterplane_t *p;
+ qboolean prepared = false;
bestd = 0;
for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
{
if(p->camera_entity != rsurface.texture->camera_entity)
continue;
d = 0;
- RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
+ if(!prepared)
+ {
+ RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
+ prepared = true;
+ if(rsurface.batchnumvertices == 0)
+ break;
+ }
for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
{
Matrix4x4_Transform(&rsurface.matrix, v, vert);
}
}
return bestplaneindex;
+ // NOTE: this MAY return a totally unrelated water plane; we can ignore
+ // this situation though, as it might be better to render single larger
+ // batches with useless stuff (backface culled for example) than to
+ // render multiple smaller batches
}
static void RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(void)
// bind lightmap texture
// water/refraction/reflection/camera surfaces have to be handled specially
- if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)) && !r_waterstate.renderingscene)
+ if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
{
int start, end, startplaneindex;
for (start = 0;start < texturenumsurfaces;start = end)
{
startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
+ if(startplaneindex < 0)
+ {
+ // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
+ // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
+ end = start + 1;
+ continue;
+ }
for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
;
// now that we have a batch using the same planeindex, render it
- if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)) && !r_waterstate.renderingscene)
+ if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
{
// render water or distortion background
GL_DepthMask(true);
R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL);
RSurf_DrawBatch();
}
- else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION) && !r_waterstate.renderingscene)
+ else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
{
// render surface with reflection texture as input
GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
float c[4];
GL_AlphaTest(false);
- R_Mesh_ResetTextureState();
+// R_Mesh_ResetTextureState();
R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
if(rsurface.texture && rsurface.texture->currentskinframe)
GL_BlendFunc(GL_ONE, GL_ZERO);
GL_DepthMask(true);
GL_AlphaTest(false);
- R_Mesh_ResetTextureState();
+// R_Mesh_ResetTextureState();
R_SetupShader_DepthOrShadow();
}
RSurf_SetupDepthAndCulling();
GL_CullFace(GL_NONE);
R_EntityMatrix(&identitymatrix);
- R_Mesh_ResetTextureState();
+// R_Mesh_ResetTextureState();
i = surfacelist[0];
GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
{
e = rsurface.modelelement3i + 3*decal->triangleindex;
- VectorCopy(rsurface.modelvertexposition[e[0]].vertex3f, v3f);
- VectorCopy(rsurface.modelvertexposition[e[1]].vertex3f, v3f + 3);
- VectorCopy(rsurface.modelvertexposition[e[2]].vertex3f, v3f + 6);
+ VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
+ VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
+ VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
}
else
{
// 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, numtris, decalsystem->element3i, decalsystem->element3s, false, false);
- R_Mesh_ResetTextureState();
+// R_Mesh_ResetTextureState();
R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
GL_DepthMask(false);
GL_DepthRange(0, 1);
flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
- R_Mesh_ResetTextureState();
+// R_Mesh_ResetTextureState();
R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
GL_DepthRange(0, 1);
GL_DepthTest(!r_showdisabledepthtest.integer);
GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
- if (r_showtris.integer || r_shownormals.integer)
+ if (r_showtris.integer || (r_shownormals.value != 0))
{
if (r_showdisabledepthtest.integer)
{
if (r_shownormals.value < 0)
{
qglBegin(GL_LINES);
- for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
+ for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
{
VectorCopy(rsurface.batchvertex3f + l * 3, v);
- GL_Color(r_refdef.view.colorscale, 0, 0, 1);
+ GL_Color(0, 0, r_refdef.view.colorscale, 1);
qglVertex3f(v[0], v[1], v[2]);
- VectorMA(v, -r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
- GL_Color(r_refdef.view.colorscale, 1, 1, 1);
+ VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
+ GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
qglVertex3f(v[0], v[1], v[2]);
}
qglEnd();
if (r_shownormals.value > 0 && rsurface.batchsvector3f)
{
qglBegin(GL_LINES);
- for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
+ for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
{
VectorCopy(rsurface.batchvertex3f + l * 3, v);
GL_Color(r_refdef.view.colorscale, 0, 0, 1);
qglVertex3f(v[0], v[1], v[2]);
VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
- GL_Color(r_refdef.view.colorscale, 1, 1, 1);
+ GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
qglVertex3f(v[0], v[1], v[2]);
}
qglEnd();
CHECKGLERROR
qglBegin(GL_LINES);
- for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
+ for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
{
VectorCopy(rsurface.batchvertex3f + l * 3, v);
GL_Color(0, r_refdef.view.colorscale, 0, 1);
qglVertex3f(v[0], v[1], v[2]);
VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
- GL_Color(r_refdef.view.colorscale, 1, 1, 1);
+ GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
qglVertex3f(v[0], v[1], v[2]);
}
qglEnd();
CHECKGLERROR
qglBegin(GL_LINES);
- for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
+ for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
{
VectorCopy(rsurface.batchvertex3f + l * 3, v);
GL_Color(0, 0, r_refdef.view.colorscale, 1);
qglVertex3f(v[0], v[1], v[2]);
VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
- GL_Color(r_refdef.view.colorscale, 1, 1, 1);
+ GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
qglVertex3f(v[0], v[1], v[2]);
}
qglEnd();
const msurface_t *surfacelist = &surface;
// fake enough texture and surface state to render this geometry
-
surface.texture = texture;
surface.num_triangles = numtriangles;
surface.num_firsttriangle = firsttriangle;