summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSmileTheory <SmileTheory@gmail.com>2013-09-16 00:54:26 -0700
committerTim Angus <tim@ngus.net>2014-06-17 17:43:34 +0100
commit75fe4796280cc95fe6b96cc9c9df5d74fc478ffa (patch)
treed031d5af29fb83215f6d140df94e5d4b48ce7309
parent57ba5d4419af6c57be928ca57da090622411215f (diff)
#5979: Cubemap support for opengl2.
-rw-r--r--src/renderercommon/qgl.h5
-rw-r--r--src/renderergl2/glsl/lightall_fp.glsl482
-rw-r--r--src/renderergl2/glsl/lightall_vp.glsl163
-rw-r--r--src/renderergl2/tr_animation.c13
-rw-r--r--src/renderergl2/tr_backend.c116
-rw-r--r--src/renderergl2/tr_bsp.c225
-rw-r--r--src/renderergl2/tr_extensions.c50
-rw-r--r--src/renderergl2/tr_fbo.c16
-rw-r--r--src/renderergl2/tr_flares.c2
-rw-r--r--src/renderergl2/tr_glsl.c63
-rw-r--r--src/renderergl2/tr_image.c98
-rw-r--r--src/renderergl2/tr_init.c15
-rw-r--r--src/renderergl2/tr_light.c29
-rw-r--r--src/renderergl2/tr_local.h69
-rw-r--r--src/renderergl2/tr_main.c150
-rw-r--r--src/renderergl2/tr_mesh.c5
-rw-r--r--src/renderergl2/tr_model_iqm.c9
-rw-r--r--src/renderergl2/tr_scene.c97
-rw-r--r--src/renderergl2/tr_shade.c47
-rw-r--r--src/renderergl2/tr_shader.c70
-rw-r--r--src/renderergl2/tr_sky.c4
-rw-r--r--src/renderergl2/tr_surface.c8
-rw-r--r--src/renderergl2/tr_world.c2
23 files changed, 1245 insertions, 493 deletions
diff --git a/src/renderercommon/qgl.h b/src/renderercommon/qgl.h
index 1a9b7ae0..14d388a4 100644
--- a/src/renderercommon/qgl.h
+++ b/src/renderercommon/qgl.h
@@ -722,6 +722,11 @@ extern void (APIENTRY * qglDrawBuffersARB)(GLsizei n, const GLenum *bufs);
#define GL_DEPTH_CLAMP 0x864F
#endif
+#ifndef GL_ARB_seamless_cube_map
+#define GL_ARB_seamless_cube_map
+#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
+#endif
+
#if defined(WIN32)
// WGL_ARB_create_context
#ifndef WGL_ARB_create_context
diff --git a/src/renderergl2/glsl/lightall_fp.glsl b/src/renderergl2/glsl/lightall_fp.glsl
index 0b455dd6..efd01399 100644
--- a/src/renderergl2/glsl/lightall_fp.glsl
+++ b/src/renderergl2/glsl/lightall_fp.glsl
@@ -20,14 +20,11 @@ uniform sampler2D u_SpecularMap;
uniform sampler2D u_ShadowMap;
#endif
-uniform vec3 u_ViewOrigin;
-
-#if defined(USE_TCGEN)
-uniform int u_TCGen0;
+#if defined(USE_CUBEMAP)
+uniform samplerCube u_CubeMap;
#endif
#if defined(USE_LIGHT_VECTOR)
-uniform vec4 u_LightOrigin;
uniform vec3 u_DirectedLight;
uniform vec3 u_AmbientLight;
uniform float u_LightRadius;
@@ -39,7 +36,6 @@ uniform vec3 u_PrimaryLightAmbient;
uniform float u_PrimaryLightRadius;
#endif
-
#if defined(USE_LIGHT)
uniform vec2 u_MaterialInfo;
#endif
@@ -50,43 +46,35 @@ varying vec2 var_LightTex;
#endif
varying vec4 var_Color;
-#if defined(USE_NORMALMAP) && !defined(USE_VERT_TANGENT_SPACE)
-varying vec3 var_Position;
-#endif
-
-#if defined(USE_TCGEN) || defined(USE_NORMALMAP) || (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT))
-varying vec3 var_SampleToView;
-#endif
-
-#if !defined(USE_FAST_LIGHT)
+#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) || defined(USE_PARALLAXMAP)
+varying vec3 var_ViewDir;
varying vec3 var_Normal;
-#endif
-
-#if defined(USE_VERT_TANGENT_SPACE)
varying vec3 var_Tangent;
varying vec3 var_Bitangent;
#endif
-varying vec3 var_VertLight;
+#if defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT)
+varying vec3 var_lightColor;
+#endif
#if defined(USE_LIGHT) && !defined(USE_DELUXEMAP)
-varying vec3 var_LightDirection;
+varying vec4 var_LightDir;
#endif
#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
-varying vec3 var_PrimaryLightDirection;
+varying vec3 var_PrimaryLightDir;
#endif
#define EPSILON 0.00000001
#if defined(USE_PARALLAXMAP)
-float SampleHeight(sampler2D normalMap, vec2 t)
+float SampleDepth(sampler2D normalMap, vec2 t)
{
#if defined(SWIZZLE_NORMALMAP)
- return texture2D(normalMap, t).r;
+ return 1.0 - texture2D(normalMap, t).r;
#else
- return texture2D(normalMap, t).a;
+ return 1.0 - texture2D(normalMap, t).a;
#endif
}
@@ -95,10 +83,8 @@ float RayIntersectDisplaceMap(vec2 dp, vec2 ds, sampler2D normalMap)
const int linearSearchSteps = 16;
const int binarySearchSteps = 6;
- float depthStep = 1.0 / float(linearSearchSteps);
-
// current size of search window
- float size = depthStep;
+ float size = 1.0 / float(linearSearchSteps);
// current depth position
float depth = 0.0;
@@ -111,7 +97,7 @@ float RayIntersectDisplaceMap(vec2 dp, vec2 ds, sampler2D normalMap)
{
depth += size;
- float t = 1.0 - SampleHeight(normalMap, dp + ds * depth);
+ float t = SampleDepth(normalMap, dp + ds * depth);
if(bestDepth > 0.996) // if no depth found yet
if(depth >= t)
@@ -125,7 +111,7 @@ float RayIntersectDisplaceMap(vec2 dp, vec2 ds, sampler2D normalMap)
{
size *= 0.5;
- float t = 1.0 - SampleHeight(normalMap, dp + ds * depth);
+ float t = SampleDepth(normalMap, dp + ds * depth);
if(depth >= t)
{
@@ -157,7 +143,7 @@ vec3 CalcDiffuse(vec3 diffuseAlbedo, vec3 N, vec3 L, vec3 E, float NE, float NL,
if (gamma >= 0.0)
#endif
{
- B *= max(max(NL, NE), EPSILON);
+ B = max(B * max(NL, NE), EPSILON);
}
return diffuseAlbedo * (A + gamma / B);
@@ -166,60 +152,135 @@ vec3 CalcDiffuse(vec3 diffuseAlbedo, vec3 N, vec3 L, vec3 E, float NE, float NL,
#endif
}
-#if defined(USE_SPECULARMAP)
-vec3 CalcSpecular(vec3 specularReflectance, float NH, float NL, float NE, float EH, float shininess)
+vec3 EnvironmentBRDF(float gloss, float NE, vec3 specular)
{
- #if defined(USE_BLINN) || defined(USE_TRIACE) || defined(USE_TORRANCE_SPARROW)
- float blinn = pow(NH, shininess);
+ #if 1
+ // from http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf
+ vec4 t = vec4( 1/0.96, 0.475, (0.0275 - 0.25 * 0.04)/0.96,0.25 ) * gloss;
+ t += vec4( 0.0, 0.0, (0.015 - 0.75 * 0.04)/0.96,0.75 );
+ float a0 = t.x * min( t.y, exp2( -9.28 * NE ) ) + t.z;
+ float a1 = t.w;
+ return clamp( a0 + specular * ( a1 - a0 ), 0.0, 1.0 );
+ #elif 0
+ // from http://seblagarde.wordpress.com/2011/08/17/hello-world/
+ return mix(specular.rgb, max(specular.rgb, vec3(gloss)), CalcFresnel(NE));
+ #else
+ // from http://advances.realtimerendering.com/s2011/Lazarov-Physically-Based-Lighting-in-Black-Ops%20%28Siggraph%202011%20Advances%20in%20Real-Time%20Rendering%20Course%29.pptx
+ return mix(specular.rgb, vec3(1.0), CalcFresnel(NE) / (4.0 - 3.0 * gloss));
#endif
+}
- #if defined(USE_BLINN)
- return specularReflectance * blinn;
- #endif
+float CalcBlinn(float NH, float shininess)
+{
+#if 0
+ // from http://seblagarde.wordpress.com/2012/06/03/spherical-gaussien-approximation-for-blinn-phong-phong-and-fresnel/
+ float a = shininess + 0.775;
+ return exp(a * NH - a);
+#else
+ return pow(NH, shininess);
+#endif
+}
- #if defined(USE_COOK_TORRANCE) || defined (USE_TRIACE) || defined (USE_TORRANCE_SPARROW)
- vec3 fresnel = specularReflectance + (vec3(1.0) - specularReflectance) * pow(1.0 - EH, 5);
- #endif
+float CalcGGX(float NH, float shininess)
+{
+ // from http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes.pdf
+ float m_sq = 2.0 / shininess;
+ float d = ((NH * NH) * (m_sq - 1.0) + 1.0);
+ return m_sq / (d * d);
+}
- #if defined(USE_COOK_TORRANCE) || defined(USE_TORRANCE_SPARROW)
+float CalcFresnel(float EH)
+{
+#if 1
+ // From http://seblagarde.wordpress.com/2012/06/03/spherical-gaussien-approximation-for-blinn-phong-phong-and-fresnel/
+ return exp2((-5.55473 * EH - 6.98316) * EH);
+#elif 0
+ float blend = 1.0 - EH;
+ float blend2 = blend * blend;
+ blend *= blend2 * blend2;
+
+ return blend;
+#else
+ return pow(1.0 - NH, 5.0);
+#endif
+}
+
+float CalcVisibility(float NH, float NL, float NE, float EH, float shininess)
+{
+#if 0
float geo = 2.0 * NH * min(NE, NL);
geo /= max(EH, geo);
- #endif
-
- #if defined(USE_COOK_TORRANCE)
- float m_sq = 2.0 / max(shininess, EPSILON);
- float NH_sq = NH * NH;
- float m_NH_sq = m_sq * NH_sq;
- float beckmann = exp((NH_sq - 1.0) / max(m_NH_sq, EPSILON)) / max(4.0 * m_NH_sq * NH_sq, EPSILON);
-
- return fresnel * geo * beckmann / max(NE, EPSILON);
+
+ return geo;
+#else
+ // Modified from http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes.pdf
+ // NL, NE in numerator factored out from cook-torrance
+ #if defined(USE_GGX)
+ float roughness = sqrt(2.0 / (shininess + 2.0));
+ float k = (roughness + 1.0);
+ k *= k * 0.125;
+ #else
+ float k = 2.0 / sqrt(3.1415926535 * (shininess + 2.0));
+ #endif
+ float k2 = 1.0 - k;
+
+ float invGeo1 = NL * k2 + k;
+ float invGeo2 = NE * k2 + k;
+
+ return 1.0 / (invGeo1 * invGeo2);
#endif
+}
- #if defined(USE_TRIACE)
- float scale = 0.1248582 * shininess + 0.2691817;
- return fresnel * scale * blinn / max(max(NL, NE), EPSILON);
- #endif
-
- #if defined(USE_TORRANCE_SPARROW)
- float scale = 0.125 * shininess + 1.0;
+vec3 CalcSpecular(vec3 specular, float NH, float NL, float NE, float EH, float shininess)
+{
+ float blinn = CalcBlinn(NH, shininess);
+ vec3 fSpecular = mix(specular, vec3(1.0), CalcFresnel(EH));
+ float vis = CalcVisibility(NH, NL, NE, EH, shininess);
- return fresnel * geo * scale * blinn / max(NE, EPSILON);
+ #if defined(USE_BLINN)
+ // Normalized Blinn-Phong
+ return specular * blinn * (shininess * 0.125 + 1.0);
+ #elif defined(USE_BLINN_FRESNEL)
+ // Normalized Blinn-Phong with Fresnel
+ return fSpecular * blinn * (shininess * 0.125 + 1.0);
+ #elif defined(USE_MCAULEY)
+ // Cook-Torrance as done by Stephen McAuley
+ // http://blog.selfshadow.com/publications/s2012-shading-course/mcauley/s2012_pbs_farcry3_notes_v2.pdf
+ return fSpecular * blinn * (shininess * 0.25 + 0.125);
+ #elif defined(USE_GOTANDA)
+ // Neumann-Neumann as done by Yoshiharu Gotanda
+ // http://research.tri-ace.com/Data/s2012_beyond_CourseNotes.pdf
+ return fSpecular * blinn * (shininess * 0.124858 + 0.269182) / max(max(NL, NE), EPSILON);
+ #elif defined(USE_LAZAROV)
+ // Cook-Torrance as done by Dimitar Lazarov
+ // http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf
+ return fSpecular * blinn * (shininess * 0.125 + 0.25) * vis;
#endif
+
+ return vec3(0.0);
}
-#endif
void main()
{
-#if !defined(USE_FAST_LIGHT) && (defined(USE_LIGHT) || defined(USE_NORMALMAP))
- vec3 surfN = normalize(var_Normal);
+ vec3 L, N, E, H;
+ float NL, NH, NE, EH;
+
+#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) || defined(USE_PARALLAXMAP)
+ mat3 tangentToWorld = mat3(var_Tangent, var_Bitangent, var_Normal);
#endif
#if defined(USE_DELUXEMAP)
- vec3 L = 2.0 * texture2D(u_DeluxeMap, var_LightTex).xyz - vec3(1.0);
- //L += var_LightDirection * 0.0001;
-#elif defined(USE_LIGHT)
- vec3 L = var_LightDirection;
+ L = (2.0 * texture2D(u_DeluxeMap, var_LightTex).xyz - vec3(1.0));
+ #if defined(USE_TANGENT_SPACE_LIGHT)
+ L = L * tangentToWorld;
+ #endif
+#elif defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
+ L = var_LightDir.xyz;
+#endif
+
+#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) || defined(USE_PARALLAXMAP)
+ E = normalize(var_ViewDir);
#endif
#if defined(USE_LIGHTMAP)
@@ -229,94 +290,80 @@ void main()
#endif
vec3 lightColor = lightSample.rgb;
#elif defined(USE_LIGHT_VECTOR) && !defined(USE_FAST_LIGHT)
- #if defined(USE_INVSQRLIGHT)
- float intensity = 1.0 / dot(L, L);
- #else
- float intensity = clamp((1.0 - dot(L, L) / (u_LightRadius * u_LightRadius)) * 1.07, 0.0, 1.0);
- #endif
+ // inverse square light
+ float attenuation = u_LightRadius * u_LightRadius / dot(L, L);
+
+ // zero light at radius, approximating q3 style
+ attenuation = 0.5 * attenuation - 0.5;
+ //attenuation = 0.0697168 * attenuation;
+ //attenuation *= step(0.294117, attenuation);
+
+ // clamp attenuation
+ #if defined(NO_LIGHT_CLAMP)
+ attenuation *= step(0.0, attenuation);
+ #else
+ attenuation = clamp(attenuation, 0.0, 1.0);
+ #endif
+
+ // don't attenuate directional light
+ attenuation = (attenuation - 1.0) * var_LightDir.w + 1.0;
- vec3 lightColor = u_DirectedLight * intensity;
- vec3 ambientColor = u_AmbientLight;
+ vec3 lightColor = u_DirectedLight * attenuation;
+ vec3 ambientColor = u_AmbientLight;
#elif defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT)
- vec3 lightColor = var_VertLight;
+ vec3 lightColor = var_lightColor;
#endif
-#if defined(USE_TCGEN) || defined(USE_NORMALMAP) || (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT))
- vec3 E = normalize(var_SampleToView);
-#endif
vec2 texCoords = var_DiffuseTex;
- float ambientDiff = 1.0;
-
-#if defined(USE_NORMALMAP)
- #if defined(USE_VERT_TANGENT_SPACE)
- mat3 tangentToWorld = mat3(var_Tangent, var_Bitangent, var_Normal);
+#if defined(USE_PARALLAXMAP)
+ #if defined(USE_TANGENT_SPACE_LIGHT)
+ vec3 offsetDir = E;
#else
- vec3 q0 = dFdx(var_Position);
- vec3 q1 = dFdy(var_Position);
- vec2 st0 = dFdx(texCoords);
- vec2 st1 = dFdy(texCoords);
- float dir = sign(st1.t * st0.s - st0.t * st1.s);
-
- vec3 tangent = normalize(q0 * st1.t - q1 * st0.t) * dir;
- vec3 bitangent = -normalize(q0 * st1.s - q1 * st0.s) * dir;
-
- mat3 tangentToWorld = mat3(tangent, bitangent, var_Normal);
+ vec3 offsetDir = E * tangentToWorld;
#endif
- #if defined(USE_PARALLAXMAP)
- vec3 offsetDir = normalize(E * tangentToWorld);
offsetDir.xy *= -0.05 / offsetDir.z;
texCoords += offsetDir.xy * RayIntersectDisplaceMap(texCoords, offsetDir.xy, u_NormalMap);
- #endif
- vec3 texN;
- #if defined(SWIZZLE_NORMALMAP)
- texN.xy = 2.0 * texture2D(u_NormalMap, texCoords).ag - 1.0;
- #else
- texN.xy = 2.0 * texture2D(u_NormalMap, texCoords).rg - 1.0;
- #endif
- texN.z = sqrt(clamp(1.0 - dot(texN.xy, texN.xy), 0.0, 1.0));
- vec3 N = tangentToWorld * texN;
- #if defined(r_normalAmbient)
- ambientDiff = 0.781341 * texN.z + 0.218659;
- #endif
-#elif defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
- vec3 N = surfN;
#endif
-#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) || (defined(USE_TCGEN) && defined(USE_NORMALMAP))
- N = normalize(N);
-#endif
+ vec4 diffuse = texture2D(u_DiffuseMap, texCoords);
-#if defined(USE_TCGEN) && defined(USE_NORMALMAP)
- if (u_TCGen0 == TCGEN_ENVIRONMENT_MAPPED)
- {
- texCoords = -reflect(E, N).yz * vec2(0.5, -0.5) + 0.5;
- }
-#endif
+#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
- vec4 diffuseAlbedo = texture2D(u_DiffuseMap, texCoords);
-#if defined(USE_LIGHT) && defined(USE_GAMMA2_TEXTURES)
- diffuseAlbedo.rgb *= diffuseAlbedo.rgb;
-#endif
+ #if defined(USE_LINEAR_LIGHT)
+ diffuse.rgb *= diffuse.rgb;
+ #endif
-#if defined(USE_LIGHT) && defined(USE_FAST_LIGHT)
- gl_FragColor = diffuse.rgb;
- #if defined(USE_LIGHTMAP)
- gl_FragColor *= lightColor;
+ #if defined(USE_NORMALMAP)
+ #if defined(SWIZZLE_NORMALMAP)
+ N.xy = 2.0 * texture2D(u_NormalMap, texCoords).ag - vec2(1.0);
+ #else
+ N.xy = 2.0 * texture2D(u_NormalMap, texCoords).rg - vec2(1.0);
+ #endif
+ N.z = sqrt(1.0 - clamp(dot(N.xy, N.xy), 0.0, 1.0));
+ #if !defined(USE_TANGENT_SPACE_LIGHT)
+ N = normalize(tangentToWorld * N);
+ #endif
+ #elif defined(USE_TANGENT_SPACE_LIGHT)
+ N = vec3(0.0, 0.0, 1.0);
+ #else
+ N = normalize(var_Normal);
#endif
-#elif defined(USE_LIGHT)
+
L = normalize(L);
- float surfNL = clamp(dot(surfN, L), 0.0, 1.0);
-
#if defined(USE_SHADOWMAP)
vec2 shadowTex = gl_FragCoord.xy * r_FBufScale;
float shadowValue = texture2D(u_ShadowMap, shadowTex).r;
// surfaces not facing the light are always shadowed
- shadowValue *= step(0.0, dot(surfN, var_PrimaryLightDirection));
+ #if defined(USE_TANGENT_SPACE_LIGHT)
+ shadowValue *= step(0.0, var_PrimaryLightDir.z);
+ #else
+ shadowValue *= step(0.0, dot(var_Normal, var_PrimaryLightDir));
+ #endif
#if defined(SHADOWMAP_MODULATE)
//vec3 shadowColor = min(u_PrimaryLightAmbient, lightColor);
@@ -324,106 +371,141 @@ void main()
#if 0
// Only shadow when the world light is parallel to the primary light
- shadowValue = 1.0 + (shadowValue - 1.0) * clamp(dot(L, var_PrimaryLightDirection), 0.0, 1.0);
+ shadowValue = 1.0 + (shadowValue - 1.0) * clamp(dot(L, var_PrimaryLightDir), 0.0, 1.0);
#endif
lightColor = mix(shadowColor, lightColor, shadowValue);
#endif
#endif
#if defined(USE_LIGHTMAP) || defined(USE_LIGHT_VERTEX)
- #if defined(USE_STANDARD_DELUXEMAP)
- // Standard deluxe mapping treats the light sample as fully directed
- // and doesn't compensate for light angle attenuation.
- vec3 ambientColor = vec3(0.0);
- #else
- // Separate the light sample into directed and ambient parts.
- //
- // ambientMax - if the cosine of the angle between the surface
- // normal and the light is below this value, the light
- // is fully ambient.
- // directedMax - if the cosine of the angle between the surface
- // normal and the light is above this value, the light
- // is fully directed.
- const float ambientMax = 0.25;
- const float directedMax = 0.5;
-
- float directedScale = clamp((surfNL - ambientMax) / (directedMax - ambientMax), 0.0, 1.0);
-
- // Scale the directed portion to compensate for the baked-in
- // light angle attenuation.
- directedScale /= max(surfNL, ambientMax);
-
- #if defined(r_normalAmbient)
- directedScale *= 1.0 - r_normalAmbient;
- #endif
-
- // Recover any unused light as ambient
vec3 ambientColor = lightColor;
- lightColor *= directedScale;
+
+ #if defined(USE_TANGENT_SPACE_LIGHT)
+ float surfNL = L.z;
+ #else
+ float surfNL = clamp(dot(var_Normal, L), 0.0, 1.0);
+ #endif
+
+ // Scale the incoming light to compensate for the baked-in light angle
+ // attenuation.
+ lightColor /= max(surfNL, 0.25);
+
+ // Recover any unused light as ambient, in case attenuation is over 4x or
+ // light is below the surface
ambientColor -= lightColor * surfNL;
- #endif
#endif
+
+ vec3 reflectance;
- float NL = clamp(dot(N, L), 0.0, 1.0);
- float NE = clamp(dot(N, E), 0.0, 1.0);
-
- float maxReflectance = u_MaterialInfo.x;
- float shininess = u_MaterialInfo.y;
+ NL = clamp(dot(N, L), 0.0, 1.0);
+ NE = clamp(dot(N, E), 0.0, 1.0);
#if defined(USE_SPECULARMAP)
- vec4 specularReflectance = texture2D(u_SpecularMap, texCoords);
- specularReflectance.rgb *= maxReflectance;
- shininess *= specularReflectance.a;
+ vec4 specular = texture2D(u_SpecularMap, texCoords);
+ #if defined(USE_LINEAR_LIGHT)
+ specular.rgb *= specular.rgb;
+ #endif
+ #else
+ vec4 specular = vec4(1.0);
+ #endif
+
+ specular *= u_MaterialInfo.xxxy;
+
+ float gloss = specular.a;
+ float shininess = exp2(gloss * 13.0);
+ float localOcclusion = clamp((diffuse.r + diffuse.g + diffuse.b) * 16.0f, 0.0, 1.0);
+
+ #if defined(SPECULAR_IS_METALLIC)
+ // diffuse is actually base color, and red of specular is metallicness
+ float metallic = specular.r;
+
+ specular.rgb = vec3(0.04) + 0.96 * diffuse.rgb * metallic;
+ diffuse.rgb *= 1.0 - metallic;
+ #else
// adjust diffuse by specular reflectance, to maintain energy conservation
- diffuseAlbedo.rgb *= vec3(1.0) - specularReflectance.rgb;
+ diffuse.rgb *= vec3(1.0) - specular.rgb;
#endif
+
+
+ reflectance = CalcDiffuse(diffuse.rgb, N, L, E, NE, NL, shininess);
- gl_FragColor.rgb = lightColor * NL * CalcDiffuse(diffuseAlbedo.rgb, N, L, E, NE, NL, shininess);
- gl_FragColor.rgb += ambientDiff * ambientColor * diffuseAlbedo.rgb;
- #if defined(USE_PRIMARY_LIGHT)
- vec3 L2 = var_PrimaryLightDirection;
- float NL2 = clamp(dot(N, L2), 0.0, 1.0);
+ #if defined(r_deluxeSpecular) || defined(USE_LIGHT_VECTOR)
+ float adjShininess = shininess;
+
+ #if !defined(USE_LIGHT_VECTOR)
+ adjShininess = exp2(gloss * r_deluxeSpecular * 13.0);
+ #endif
+
+ H = normalize(L + E);
- #if defined(USE_SHADOWMAP)
- gl_FragColor.rgb += u_PrimaryLightColor * shadowValue * NL2 * CalcDiffuse(diffuseAlbedo.rgb, N, L2, E, NE, NL2, shininess);
+ EH = clamp(dot(E, H), 0.0, 1.0);
+ NH = clamp(dot(N, H), 0.0, 1.0);
+
+ #if !defined(USE_LIGHT_VECTOR)
+ reflectance += CalcSpecular(specular.rgb, NH, NL, NE, EH, adjShininess) * r_deluxeSpecular * localOcclusion;
#else
- gl_FragColor.rgb += u_PrimaryLightColor * NL2 * CalcDiffuse(diffuseAlbedo.rgb, N, L2, E, NE, NL2, shininess);
+ reflectance += CalcSpecular(specular.rgb, NH, NL, NE, EH, adjShininess) * localOcclusion;
#endif
#endif
-
- #if defined(USE_SPECULARMAP)
- vec3 H = normalize(L + E);
+
+ gl_FragColor.rgb = lightColor * reflectance * NL;
+ gl_FragColor.rgb += ambientColor * (diffuse.rgb + specular.rgb);
+
+ #if defined(USE_CUBEMAP)
+ reflectance = EnvironmentBRDF(gloss, NE, specular.rgb);
- float EH = clamp(dot(E, H), 0.0, 1.0);
- float NH = clamp(dot(N, H), 0.0, 1.0);
+ vec3 R = reflect(E, N);
+ #if defined(USE_TANGENT_SPACE_LIGHT)
+ R = tangentToWorld * R;
+ #endif
- gl_FragColor.rgb += lightColor * NL * CalcSpecular(specularReflectance.rgb, NH, NL, NE, EH, shininess);
-
- #if defined(r_normalAmbient)
- vec3 ambientHalf = normalize(surfN + E);
- float ambientSpec = max(dot(ambientHalf, N) + 0.5, 0.0);
- ambientSpec *= ambientSpec * 0.44;
- gl_FragColor.rgb += specularReflectance.rgb * ambientSpec * ambientColor;
+ vec3 cubeLightColor = textureCubeLod(u_CubeMap, R, 7.0 - gloss * 7.0).rgb;
+
+ #if defined(USE_LINEAR_LIGHT)
+ cubeLightColor *= cubeLightColor;
#endif
- #if defined(USE_PRIMARY_LIGHT)
- vec3 H2 = normalize(L2 + E);
- float EH2 = clamp(dot(E, H2), 0.0, 1.0);
- float NH2 = clamp(dot(N, H2), 0.0, 1.0);
+ #if defined(USE_LIGHTMAP)
+ cubeLightColor *= lightSample.rgb;
+ #elif defined (USE_LIGHT_VERTEX)
+ cubeLightColor *= var_lightColor;
+ #else
+ cubeLightColor *= lightColor * NL + ambientColor;
+ #endif
+
+ //gl_FragColor.rgb += diffuse.rgb * textureCubeLod(u_CubeMap, N, 7.0).rgb;
+ gl_FragColor.rgb += cubeLightColor * reflectance * localOcclusion;
+ #endif
+ #if defined(USE_PRIMARY_LIGHT)
+ L = normalize(var_PrimaryLightDir);
+ NL = clamp(dot(N, L), 0.0, 1.0);
- #if defined(USE_SHADOWMAP)
- gl_FragColor.rgb += u_PrimaryLightColor * shadowValue * NL2 * CalcSpecular(specularReflectance.rgb, NH2, NL2, NE, EH2, shininess);
- #else
- gl_FragColor.rgb += u_PrimaryLightColor * NL2 * CalcSpecular(specularReflectance.rgb, NH2, NL2, NE, EH2, shininess);
- #endif
+ H = normalize(L + E);
+ EH = clamp(dot(E, H), 0.0, 1.0);
+ NH = clamp(dot(N, H), 0.0, 1.0);
+
+ reflectance = CalcDiffuse(diffuse.rgb, N, L, E, NE, NL, shininess);
+ reflectance += CalcSpecular(specular.rgb, NH, NL, NE, EH, shininess);
+
+ #if defined(USE_SHADOWMAP)
+ reflectance *= shadowValue;
#endif
- #endif
+
+ gl_FragColor.rgb += u_PrimaryLightColor * reflectance * NL;
+ #endif
+
+ #if defined(USE_LINEAR_LIGHT)
+ gl_FragColor.rgb = sqrt(gl_FragColor.rgb);
+ #endif
+
+ gl_FragColor.a = diffuse.a;
#else
- gl_FragColor.rgb = diffuseAlbedo.rgb;
+ gl_FragColor = diffuse;
+ #if defined(USE_LIGHTMAP)
+ gl_FragColor.rgb *= lightColor;
+ #endif
#endif
- gl_FragColor.a = diffuseAlbedo.a;
-
gl_FragColor *= var_Color;
}
diff --git a/src/renderergl2/glsl/lightall_vp.glsl b/src/renderergl2/glsl/lightall_vp.glsl
index 03775caf..d2bfb395 100644
--- a/src/renderergl2/glsl/lightall_vp.glsl
+++ b/src/renderergl2/glsl/lightall_vp.glsl
@@ -4,21 +4,16 @@ attribute vec4 attr_TexCoord1;
#endif
attribute vec4 attr_Color;
-attribute vec4 attr_Position;
+attribute vec3 attr_Position;
attribute vec3 attr_Normal;
-
-#if defined(USE_VERT_TANGENT_SPACE)
attribute vec3 attr_Tangent;
attribute vec3 attr_Bitangent;
-#endif
#if defined(USE_VERTEX_ANIMATION)
-attribute vec4 attr_Position2;
+attribute vec3 attr_Position2;
attribute vec3 attr_Normal2;
- #if defined(USE_VERT_TANGENT_SPACE)
attribute vec3 attr_Tangent2;
attribute vec3 attr_Bitangent2;
- #endif
#endif
#if defined(USE_LIGHT) && !defined(USE_LIGHT_VECTOR)
@@ -71,35 +66,28 @@ varying vec2 var_DiffuseTex;
varying vec2 var_LightTex;
#endif
-#if defined(USE_TCGEN) || defined(USE_NORMALMAP) || (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT))
-varying vec3 var_SampleToView;
+#if defined(USE_NORMALMAP) || (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT))
+varying vec3 var_ViewDir;
#endif
varying vec4 var_Color;
-#if defined(USE_NORMALMAP) && !defined(USE_VERT_TANGENT_SPACE)
-varying vec3 var_Position;
-#endif
-
-
-#if !defined(USE_FAST_LIGHT)
+#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) || defined(USE_PARALLAXMAP)
varying vec3 var_Normal;
- #if defined(USE_VERT_TANGENT_SPACE)
varying vec3 var_Tangent;
varying vec3 var_Bitangent;
- #endif
#endif
#if defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT)
-varying vec3 var_VertLight;
+varying vec3 var_lightColor;
#endif
#if defined(USE_LIGHT) && !defined(USE_DELUXEMAP) && !defined(USE_FAST_LIGHT)
-varying vec3 var_LightDirection;
+varying vec4 var_LightDir;
#endif
#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
-varying vec3 var_PrimaryLightDirection;
+varying vec3 var_PrimaryLightDir;
#endif
#if defined(USE_TCGEN)
@@ -132,7 +120,7 @@ vec2 ModTexCoords(vec2 st, vec3 position, vec4 texMatrix, vec4 offTurb)
float phase = offTurb.w;
vec2 st2 = vec2(dot(st, texMatrix.xz), dot(st, texMatrix.yw)) + offTurb.xy;
- vec3 offsetPos = vec3(0); //position / 1024.0;
+ vec3 offsetPos = position * 0.0009765625;
offsetPos.x += offsetPos.z;
vec2 texOffset = sin((offsetPos.xy + vec2(phase)) * 2.0 * M_PI);
@@ -145,83 +133,53 @@ vec2 ModTexCoords(vec2 st, vec3 position, vec4 texMatrix, vec4 offTurb)
void main()
{
#if defined(USE_VERTEX_ANIMATION)
- vec4 position = mix(attr_Position, attr_Position2, u_VertexLerp);
+ vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp);
vec3 normal = normalize(mix(attr_Normal, attr_Normal2, u_VertexLerp));
- #if defined(USE_VERT_TANGENT_SPACE)
vec3 tangent = normalize(mix(attr_Tangent, attr_Tangent2, u_VertexLerp));
vec3 bitangent = normalize(mix(attr_Bitangent, attr_Bitangent2, u_VertexLerp));
- #endif
#else
- vec4 position = attr_Position;
+ vec3 position = attr_Position;
vec3 normal = attr_Normal;
- #if defined(USE_VERT_TANGENT_SPACE)
vec3 tangent = attr_Tangent;
vec3 bitangent = attr_Bitangent;
- #endif
-#endif
-
- gl_Position = u_ModelViewProjectionMatrix * position;
-
-#if (defined(USE_LIGHTMAP) || defined(USE_LIGHT_VERTEX)) && !defined(USE_DELUXEMAP) && !defined(USE_FAST_LIGHT)
- vec3 L = attr_LightDirection;
-#endif
-
-#if defined(USE_MODELMATRIX)
- position = u_ModelMatrix * position;
- normal = (u_ModelMatrix * vec4(normal, 0.0)).xyz;
- #if defined(USE_VERT_TANGENT_SPACE)
- tangent = (u_ModelMatrix * vec4(tangent, 0.0)).xyz;
- bitangent = (u_ModelMatrix * vec4(bitangent, 0.0)).xyz;
- #endif
-
- #if defined(USE_LIGHTMAP) && !defined(USE_DELUXEMAP) && !defined(USE_FAST_LIGHT)
- L = (u_ModelMatrix * vec4(L, 0.0)).xyz;
- #endif
-#endif
-
-#if defined(USE_NORMALMAP) && !defined(USE_VERT_TANGENT_SPACE)
- var_Position = position.xyz;
-#endif
-
-#if defined(USE_TCGEN) || defined(USE_NORMALMAP) || (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT))
- var_SampleToView = u_ViewOrigin - position.xyz;
#endif
#if defined(USE_TCGEN)
- vec2 texCoords = GenTexCoords(u_TCGen0, position.xyz, normal, u_TCGen0Vector0, u_TCGen0Vector1);
+ vec2 texCoords = GenTexCoords(u_TCGen0, position, normal, u_TCGen0Vector0, u_TCGen0Vector1);
#else
vec2 texCoords = attr_TexCoord0.st;
#endif
#if defined(USE_TCMOD)
- var_DiffuseTex = ModTexCoords(texCoords, position.xyz, u_DiffuseTexMatrix, u_DiffuseTexOffTurb);
+ var_DiffuseTex = ModTexCoords(texCoords, position, u_DiffuseTexMatrix, u_DiffuseTexOffTurb);
#else
var_DiffuseTex = texCoords;
#endif
-#if defined(USE_LIGHTMAP)
- var_LightTex = attr_TexCoord1.st;
+ gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0);
+
+#if defined(USE_MODELMATRIX)
+ position = (u_ModelMatrix * vec4(position, 1.0)).xyz;
+ normal = (u_ModelMatrix * vec4(normal, 0.0)).xyz;
+ tangent = (u_ModelMatrix * vec4(tangent, 0.0)).xyz;
+ bitangent = (u_ModelMatrix * vec4(bitangent, 0.0)).xyz;
#endif
-#if !defined(USE_FAST_LIGHT)
- var_Normal = normal;
- #if defined(USE_VERT_TANGENT_SPACE)
- var_Tangent = tangent;
- var_Bitangent = bitangent;
+#if defined(USE_LIGHT_VECTOR)
+ vec3 L = u_LightOrigin.xyz - (position * u_LightOrigin.w);
+#elif defined(USE_LIGHT) && !defined(USE_LIGHT_VECTOR)
+ vec3 L = attr_LightDirection;
+ #if defined(USE_MODELMATRIX)
+ L = (u_ModelMatrix * vec4(L, 0.0)).xyz;
#endif
#endif
-#if defined(USE_LIGHT) && !defined(USE_DELUXEMAP)
- #if defined(USE_LIGHT_VECTOR)
- vec3 L = u_LightOrigin.xyz - (position.xyz * u_LightOrigin.w);
- #endif
- #if !defined(USE_FAST_LIGHT)
- var_LightDirection = L;
- #endif
+#if defined(USE_LIGHTMAP)
+ var_LightTex = attr_TexCoord1.st;
#endif
#if defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT)
- var_VertLight = u_VertColor.rgb * attr_Color.rgb;
+ var_lightColor = u_VertColor.rgb * attr_Color.rgb;
var_Color.rgb = vec3(1.0);
var_Color.a = u_VertColor.a * attr_Color.a + u_BaseColor.a;
#else
@@ -229,17 +187,64 @@ void main()
#endif
#if defined(USE_LIGHT_VECTOR) && defined(USE_FAST_LIGHT)
- #if defined(USE_INVSQRLIGHT)
- float intensity = 1.0 / dot(L, L);
- #else
- float intensity = clamp((1.0 - dot(L, L) / (u_LightRadius * u_LightRadius)) * 1.07, 0.0, 1.0);
- #endif
+ // inverse square light
+ float attenuation = u_LightRadius * u_LightRadius / dot(L, L);
+
+ // zero light at radius, approximating q3 style
+ attenuation = 0.5 * attenuation - 0.5;
+ //attenuation = 0.0697168 * attenuation;
+ //attenuation *= step(0.294117, attenuation);
+
+ // clamp attenuation
+ #if defined(NO_LIGHT_CLAMP)
+ attenuation *= step(0.0, attenuation);
+ #else
+ attenuation = clamp(attenuation, 0.0, 1.0);
+ #endif
+
+ // don't attenuate directional light
+ attenuation = (attenuation - 1.0) * u_LightOrigin.w + 1.0;
+
float NL = clamp(dot(normal, normalize(L)), 0.0, 1.0);
- var_Color.rgb *= u_DirectedLight * intensity * NL + u_AmbientLight;
+ var_Color.rgb *= u_DirectedLight * attenuation * NL + u_AmbientLight;
+#endif
+
+#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) || defined(USE_PARALLAXMAP)
+ var_Normal = normal;
+ var_Tangent = tangent;
+ var_Bitangent = bitangent;
#endif
#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
- var_PrimaryLightDirection = u_PrimaryLightOrigin.xyz - (position.xyz * u_PrimaryLightOrigin.w);
-#endif
+ var_PrimaryLightDir = (u_PrimaryLightOrigin.xyz - (position * u_PrimaryLightOrigin.w));
+#endif
+
+#if defined(USE_LIGHT) && !defined(USE_DELUXEMAP) && !defined(USE_FAST_LIGHT)
+ #if defined(USE_LIGHT_VECTOR)
+ var_LightDir = vec4(L, u_LightOrigin.w);
+ #else
+ var_LightDir = vec4(L, 0.0);
+ #endif
+#endif
+
+#if defined(USE_NORMALMAP) || (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT))
+ var_ViewDir = (u_ViewOrigin - position);
+#endif
+
+#if defined(USE_TANGENT_SPACE_LIGHT)
+ mat3 tangentToWorld = mat3(tangent, bitangent, normal);
+
+ #if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
+ var_PrimaryLightDir = var_PrimaryLightDir * tangentToWorld;
+ #endif
+
+ #if defined(USE_LIGHT) && !defined(USE_DELUXEMAP) && !defined(USE_FAST_LIGHT)
+ var_LightDir.xyz = var_LightDir.xyz * tangentToWorld;
+ #endif
+
+ #if defined(USE_NORMALMAP) || (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT))
+ var_ViewDir = var_ViewDir * tangentToWorld;
+ #endif
+#endif
}
diff --git a/src/renderergl2/tr_animation.c b/src/renderergl2/tr_animation.c
index 7a6092de..5ec58903 100644
--- a/src/renderergl2/tr_animation.c
+++ b/src/renderergl2/tr_animation.c
@@ -44,15 +44,17 @@ void R_AddAnimSurfaces( trRefEntity_t *ent ) {
md4Surface_t *surface;
md4LOD_t *lod;
shader_t *shader;
+ int cubemapIndex;
int i;
header = (md4Header_t *) tr.currentModel->modelData;
lod = (md4LOD_t *)( (byte *)header + header->ofsLODs );
+ cubemapIndex = R_CubemapForPoint(ent->e.origin);
surface = (md4Surface_t *)( (byte *)lod + lod->ofsSurfaces );
for ( i = 0 ; i < lod->numSurfaces ; i++ ) {
shader = R_GetShaderByHandle( surface->shaderIndex );
- R_AddDrawSurf( (void *)surface, shader, 0 /*fogNum*/, qfalse, qfalse );
+ R_AddDrawSurf( (void *)surface, shader, 0 /*fogNum*/, qfalse, qfalse, cubemapIndex );
surface = (md4Surface_t *)( (byte *)surface + surface->ofsEnd );
}
}
@@ -324,6 +326,7 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
int lodnum = 0;
int fogNum = 0;
int cull;
+ int cubemapIndex;
qboolean personalModel;
header = (mdrHeader_t *) tr.currentModel->modelData;
@@ -385,6 +388,8 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
// fogNum?
fogNum = R_MDRComputeFogNum( header, ent );
+ cubemapIndex = R_CubemapForPoint(ent->e.origin);
+
surface = (mdrSurface_t *)( (byte *)lod + lod->ofsSurfaces );
for ( i = 0 ; i < lod->numSurfaces ; i++ )
@@ -420,7 +425,7 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
&& !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
&& shader->sort == SS_OPAQUE )
{
- R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse, qfalse );
+ R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse, qfalse, 0 );
}
// projection shadows work fine with personal models
@@ -429,11 +434,11 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
&& (ent->e.renderfx & RF_SHADOW_PLANE )
&& shader->sort == SS_OPAQUE )
{
- R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, qfalse );
+ R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, qfalse, 0 );
}
if (!personalModel)
- R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse, qfalse );
+ R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse, qfalse, cubemapIndex );
surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd );
}
diff --git a/src/renderergl2/tr_backend.c b/src/renderergl2/tr_backend.c
index 5340867c..559243ca 100644
--- a/src/renderergl2/tr_backend.c
+++ b/src/renderergl2/tr_backend.c
@@ -37,13 +37,13 @@ static float s_flipMatrix[16] = {
/*
-** GL_Bind2
+** GL_Bind
*/
-void GL_Bind2( image_t *image, GLenum type ) {
+void GL_Bind( image_t *image ) {
int texnum;
if ( !image ) {
- ri.Printf( PRINT_WARNING, "GL_Bind2: NULL image\n" );
+ ri.Printf( PRINT_WARNING, "GL_Bind: NULL image\n" );
texnum = tr.defaultImage->texnum;
} else {
texnum = image->texnum;
@@ -58,27 +58,14 @@ void GL_Bind2( image_t *image, GLenum type ) {
image->frameUsed = tr.frameCount;
}
glState.currenttextures[glState.currenttmu] = texnum;
- qglBindTexture (type, texnum);
+ if (image && image->flags & IMGFLAG_CUBEMAP)
+ qglBindTexture( GL_TEXTURE_CUBE_MAP, texnum );
+ else
+ qglBindTexture( GL_TEXTURE_2D, texnum );
}
}
/*
-** GL_Bind2
-*/
-void GL_Bind( image_t *image )
-{
- GL_Bind2( image, GL_TEXTURE_2D );
-}
-
-/*
-** GL_BindCubemap
-*/
-void GL_BindCubemap( image_t *image )
-{
- GL_Bind2( image, GL_TEXTURE_CUBE_MAP );
-}
-
-/*
** GL_SelectTexture
*/
void GL_SelectTexture( int unit )
@@ -96,34 +83,6 @@ void GL_SelectTexture( int unit )
glState.currenttmu = unit;
}
-
-/*
-** GL_BindMultitexture
-*/
-void GL_BindMultitexture( image_t *image0, GLuint env0, image_t *image1, GLuint env1 ) {
- int texnum0, texnum1;
-
- texnum0 = image0->texnum;
- texnum1 = image1->texnum;
-
- if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option
- texnum0 = texnum1 = tr.dlightImage->texnum;
- }
-
- if ( glState.currenttextures[1] != texnum1 ) {
- GL_SelectTexture( 1 );
- image1->frameUsed = tr.frameCount;
- glState.currenttextures[1] = texnum1;
- qglBindTexture( GL_TEXTURE_2D, texnum1 );
- }
- if ( glState.currenttextures[0] != texnum0 ) {
- GL_SelectTexture( 0 );
- image0->frameUsed = tr.frameCount;
- glState.currenttextures[0] = texnum0;
- qglBindTexture( GL_TEXTURE_2D, texnum0 );
- }
-}
-
/*
** GL_BindToTMU
*/
@@ -142,7 +101,11 @@ void GL_BindToTMU( image_t *image, int tmu )
if (image)
image->frameUsed = tr.frameCount;
glState.currenttextures[tmu] = texnum;
- qglBindTexture( GL_TEXTURE_2D, texnum );
+
+ if (image && (image->flags & IMGFLAG_CUBEMAP))
+ qglBindTexture( GL_TEXTURE_CUBE_MAP, texnum );
+ else
+ qglBindTexture( GL_TEXTURE_2D, texnum );
GL_SelectTexture( oldtmu );
}
}
@@ -497,6 +460,13 @@ void RB_BeginDrawingView (void) {
else
{
FBO_Bind(backEnd.viewParms.targetFbo);
+
+ // FIXME: hack for cubemap testing
+ if (backEnd.viewParms.targetFbo == tr.renderCubeFbo)
+ {
+ //qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, backEnd.viewParms.targetFbo->colorImage[0]->texnum, 0);
+ qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex]->texnum, 0);
+ }
}
}
@@ -531,6 +501,13 @@ void RB_BeginDrawingView (void) {
qglClearColor( 1.0f, 1.0f, 1.0f, 1.0f );
}
+ // clear to black for cube maps
+ if (backEnd.viewParms.targetFbo == tr.renderCubeFbo)
+ {
+ clearBits |= GL_COLOR_BUFFER_BIT;
+ qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
+ }
+
qglClear( clearBits );
if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) )
@@ -582,6 +559,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
int entityNum, oldEntityNum;
int dlighted, oldDlighted;
int pshadowed, oldPshadowed;
+ int cubemapIndex, oldCubemapIndex;
qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair;
int i;
drawSurf_t *drawSurf;
@@ -607,6 +585,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
wasCrosshair = qfalse;
oldDlighted = qfalse;
oldPshadowed = qfalse;
+ oldCubemapIndex = -1;
oldSort = -1;
depth[0] = 0.f;
@@ -615,7 +594,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
backEnd.pc.c_surfaces += numDrawSurfs;
for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) {
- if ( drawSurf->sort == oldSort ) {
+ if ( drawSurf->sort == oldSort && drawSurf->cubemapIndex == oldCubemapIndex) {
if (backEnd.depthFill && shader && shader->sort != SS_OPAQUE)
continue;
@@ -625,22 +604,24 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
}
oldSort = drawSurf->sort;
R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed );
+ cubemapIndex = drawSurf->cubemapIndex;
//
// change the tess parameters if needed
// a "entityMergable" shader is a shader that can have surfaces from seperate
// entities merged into a single batch, like smoke and blood puff sprites
- if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || pshadowed != oldPshadowed
+ if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || pshadowed != oldPshadowed || cubemapIndex != oldCubemapIndex
|| ( entityNum != oldEntityNum && !shader->entityMergable ) ) ) {
if (oldShader != NULL) {
RB_EndSurface();
}
- RB_BeginSurface( shader, fogNum );
+ RB_BeginSurface( shader, fogNum, cubemapIndex );
backEnd.pc.c_surfBatches++;
oldShader = shader;
oldFogNum = fogNum;
oldDlighted = dlighted;
oldPshadowed = pshadowed;
+ oldCubemapIndex = cubemapIndex;
}
if (backEnd.depthFill && shader && shader->sort != SS_OPAQUE)
@@ -982,7 +963,7 @@ const void *RB_StretchPic ( const void *data ) {
RB_EndSurface();
}
backEnd.currentEntity = &backEnd.entity2D;
- RB_BeginSurface( shader, 0 );
+ RB_BeginSurface( shader, 0, 0 );
}
RB_CHECKOVERFLOW( 4, 6 );
@@ -1312,8 +1293,14 @@ const void *RB_DrawSurfs( const void *data ) {
RB_RenderFlares();
}
- //if (glRefConfig.framebufferObject)
- //FBO_Bind(NULL);
+ if (glRefConfig.framebufferObject && backEnd.viewParms.targetFbo == tr.renderCubeFbo)
+ {
+ FBO_Bind(NULL);
+ GL_SelectTexture(TB_CUBEMAP);
+ GL_BindToTMU(tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex], TB_CUBEMAP);
+ qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP);
+ GL_SelectTexture(0);
+ }
return (const void *)(cmd + 1);
}
@@ -1587,7 +1574,7 @@ const void *RB_CapShadowMap(const void *data)
GL_SelectTexture(0);
if (cmd->cubeSide != -1)
{
- GL_BindCubemap(tr.shadowCubemaps[cmd->map]);
+ GL_Bind(tr.shadowCubemaps[cmd->map]);
qglCopyTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cmd->cubeSide, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0);
}
else
@@ -1683,7 +1670,7 @@ const void *RB_PostProcess(const void *data)
color[2] = pow(2, r_cameraExposure->value); //exp2(r_cameraExposure->value);
color[3] = 1.0f;
- FBO_Blit(srcFbo, NULL, NULL, tr.screenScratchFbo, dstBox, NULL, color, 0);
+ FBO_Blit(srcFbo, srcBox, NULL, tr.screenScratchFbo, dstBox, NULL, color, 0);
}
}
@@ -1722,6 +1709,21 @@ const void *RB_PostProcess(const void *data)
FBO_BlitFromTexture(tr.sunRaysImage, NULL, NULL, tr.screenScratchFbo, dstBox, NULL, NULL, 0);
}
+#if 0
+ if (r_cubeMapping->integer && tr.numCubemaps)
+ {
+ vec4i_t dstBox;
+ int cubemapIndex = R_CubemapForPoint( backEnd.viewParms.or.origin );
+
+ if (cubemapIndex)
+ {
+ VectorSet4(dstBox, 0, glConfig.vidHeight - 256, 256, 256);
+ //FBO_BlitFromTexture(tr.renderCubeImage, NULL, NULL, tr.screenScratchFbo, dstBox, &tr.testcubeShader, NULL, 0);
+ FBO_BlitFromTexture(tr.cubemaps[cubemapIndex - 1], NULL, NULL, tr.screenScratchFbo, dstBox, &tr.testcubeShader, NULL, 0);
+ }
+ }
+#endif
+
backEnd.framePostProcessed = qtrue;
return (const void *)(cmd + 1);
diff --git a/src/renderergl2/tr_bsp.c b/src/renderergl2/tr_bsp.c
index adf14c06..f1eb51e3 100644
--- a/src/renderergl2/tr_bsp.c
+++ b/src/renderergl2/tr_bsp.c
@@ -1806,6 +1806,14 @@ static int BSPSurfaceCompare(const void *a, const void *b)
else if(aa->fogIndex > bb->fogIndex)
return 1;
+ // by cubemapIndex
+ if(aa->cubemapIndex < bb->cubemapIndex)
+ return -1;
+
+ else if(aa->cubemapIndex > bb->cubemapIndex)
+ return 1;
+
+
return 0;
}
@@ -2815,6 +2823,191 @@ qboolean R_GetEntityToken( char *buffer, int size ) {
}
}
+#ifndef MAX_SPAWN_VARS
+#define MAX_SPAWN_VARS 64
+#endif
+
+// derived from G_ParseSpawnVars() in g_spawn.c
+qboolean R_ParseSpawnVars( char *spawnVarChars, int maxSpawnVarChars, int *numSpawnVars, char *spawnVars[MAX_SPAWN_VARS][2] )
+{
+ char keyname[MAX_TOKEN_CHARS];
+ char com_token[MAX_TOKEN_CHARS];
+ int numSpawnVarChars = 0;
+
+ *numSpawnVars = 0;
+
+ // parse the opening brace
+ if ( !R_GetEntityToken( com_token, sizeof( com_token ) ) ) {
+ // end of spawn string
+ return qfalse;
+ }
+ if ( com_token[0] != '{' ) {
+ ri.Printf( PRINT_ALL, "R_ParseSpawnVars: found %s when expecting {",com_token );
+ }
+
+ // go through all the key / value pairs
+ while ( 1 ) {
+ int keyLength, tokenLength;
+
+ // parse key
+ if ( !R_GetEntityToken( keyname, sizeof( keyname ) ) ) {
+ ri.Printf( PRINT_ALL, "R_ParseSpawnVars: EOF without closing brace" );
+ }
+
+ if ( keyname[0] == '}' ) {
+ break;
+ }
+
+ // parse value
+ if ( !R_GetEntityToken( com_token, sizeof( com_token ) ) ) {
+ ri.Printf( PRINT_ALL, "R_ParseSpawnVars: EOF without closing brace" );
+ break;
+ }
+
+ if ( com_token[0] == '}' ) {
+ ri.Printf( PRINT_ALL, "R_ParseSpawnVars: closing brace without data" );
+ break;
+ }
+
+ if ( *numSpawnVars == MAX_SPAWN_VARS ) {
+ ri.Printf( PRINT_ALL, "R_ParseSpawnVars: MAX_SPAWN_VARS" );
+ break;
+ }
+
+ keyLength = strlen(keyname) + 1;
+ tokenLength = strlen(com_token) + 1;
+
+ if (numSpawnVarChars + keyLength + tokenLength > maxSpawnVarChars)
+ {
+ ri.Printf( PRINT_ALL, "R_ParseSpawnVars: MAX_SPAWN_VAR_CHARS" );
+ break;
+ }
+
+ strcpy(spawnVarChars + numSpawnVarChars, keyname);
+ spawnVars[ *numSpawnVars ][0] = spawnVarChars + numSpawnVarChars;
+ numSpawnVarChars += keyLength;
+
+ strcpy(spawnVarChars + numSpawnVarChars, com_token);
+ spawnVars[ *numSpawnVars ][1] = spawnVarChars + numSpawnVarChars;
+ numSpawnVarChars += tokenLength;
+
+ (*numSpawnVars)++;
+ }
+
+ return qtrue;
+}
+
+void R_LoadCubemapEntities(char *cubemapEntityName)
+{
+ char spawnVarChars[2048];
+ int numSpawnVars;
+ char *spawnVars[MAX_SPAWN_VARS][2];
+ int numCubemaps = 0;
+
+ // count cubemaps
+ numCubemaps = 0;
+ while(R_ParseSpawnVars(spawnVarChars, sizeof(spawnVarChars), &numSpawnVars, spawnVars))
+ {
+ int i;
+
+ for (i = 0; i < numSpawnVars; i++)
+ {
+ if (!Q_stricmp(spawnVars[i][0], "classname") && !Q_stricmp(spawnVars[i][1], cubemapEntityName))
+ numCubemaps++;
+ }
+ }
+
+ if (!numCubemaps)
+ return;
+
+ tr.numCubemaps = numCubemaps;
+ tr.cubemapOrigins = ri.Hunk_Alloc( tr.numCubemaps * sizeof(*tr.cubemapOrigins), h_low);
+ tr.cubemaps = ri.Hunk_Alloc( tr.numCubemaps * sizeof(*tr.cubemaps), h_low);
+
+ numCubemaps = 0;
+ while(R_ParseSpawnVars(spawnVarChars, sizeof(spawnVarChars), &numSpawnVars, spawnVars))
+ {
+ int i;
+ qboolean isCubemap = qfalse;
+ qboolean positionSet = qfalse;
+ vec3_t origin;
+
+ for (i = 0; i < numSpawnVars; i++)
+ {
+ if (!Q_stricmp(spawnVars[i][0], "classname") && !Q_stricmp(spawnVars[i][1], cubemapEntityName))
+ isCubemap = qtrue;
+
+ if (!Q_stricmp(spawnVars[i][0], "origin"))
+ {
+ sscanf(spawnVars[i][1], "%f %f %f", &origin[0], &origin[1], &origin[2]);
+ positionSet = qtrue;
+ }
+ }
+
+ if (isCubemap && positionSet)
+ {
+ //ri.Printf(PRINT_ALL, "cubemap at %f %f %f\n", origin[0], origin[1], origin[2]);
+ VectorCopy(origin, tr.cubemapOrigins[numCubemaps]);
+ numCubemaps++;
+ }
+ }
+}
+
+void R_AssignCubemapsToWorldSurfaces(void)
+{
+ world_t *w;
+ int i;
+
+ w = &s_worldData;
+
+ for (i = 0; i < w->numsurfaces; i++)
+ {
+ msurface_t *surf = &w->surfaces[i];
+ vec3_t surfOrigin;
+
+ if (surf->cullinfo.type & CULLINFO_SPHERE)
+ {
+ VectorCopy(surf->cullinfo.localOrigin, surfOrigin);
+ }
+ else if (surf->cullinfo.type & CULLINFO_BOX)
+ {
+ surfOrigin[0] = (surf->cullinfo.bounds[0][0] + surf->cullinfo.bounds[1][0]) * 0.5f;
+ surfOrigin[1] = (surf->cullinfo.bounds[0][1] + surf->cullinfo.bounds[1][1]) * 0.5f;
+ surfOrigin[2] = (surf->cullinfo.bounds[0][2] + surf->cullinfo.bounds[1][2]) * 0.5f;
+ }
+ else
+ {
+ //ri.Printf(PRINT_ALL, "surface %d has no cubemap\n", i);
+ continue;
+ }
+
+ surf->cubemapIndex = R_CubemapForPoint(surfOrigin);
+ //ri.Printf(PRINT_ALL, "surface %d has cubemap %d\n", i, surf->cubemapIndex);
+ }
+}
+
+
+void R_RenderAllCubemaps(void)
+{
+ int i, j;
+
+ for (i = 0; i < tr.numCubemaps; i++)
+ {
+ tr.cubemaps[i] = R_CreateImage(va("*cubeMap%d", i), NULL, CUBE_MAP_SIZE, CUBE_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_CUBEMAP, GL_RGBA8);
+ }
+
+ for (i = 0; i < tr.numCubemaps; i++)
+ {
+ for (j = 0; j < 6; j++)
+ {
+ RE_ClearScene();
+ R_RenderCubemapSide(i, j, qfalse);
+ R_IssuePendingRenderCommands();
+ R_InitNextFrame();
+ }
+ }
+}
+
/*
=================
@@ -2867,6 +3060,7 @@ void R_MergeLeafSurfaces(void)
msurface_t *surf1;
shader_t *shader1;
int fogIndex1;
+ int cubemapIndex1;
int surfNum1;
surfNum1 = *(s_worldData.marksurfaces + leaf->firstmarksurface + j);
@@ -2891,6 +3085,7 @@ void R_MergeLeafSurfaces(void)
continue;
fogIndex1 = surf1->fogIndex;
+ cubemapIndex1 = surf1->cubemapIndex;
s_worldData.surfacesViewCount[surfNum1] = surfNum1;
@@ -2899,6 +3094,7 @@ void R_MergeLeafSurfaces(void)
msurface_t *surf2;
shader_t *shader2;
int fogIndex2;
+ int cubemapIndex2;
int surfNum2;
surfNum2 = *(s_worldData.marksurfaces + leaf->firstmarksurface + k);
@@ -2921,6 +3117,11 @@ void R_MergeLeafSurfaces(void)
if (fogIndex1 != fogIndex2)
continue;
+ cubemapIndex2 = surf2->cubemapIndex;
+
+ if (cubemapIndex1 != cubemapIndex2)
+ continue;
+
s_worldData.surfacesViewCount[surfNum2] = surfNum1;
}
}
@@ -3154,6 +3355,7 @@ void R_MergeLeafSurfaces(void)
vboSurf->shader = surf1->shader;
vboSurf->fogIndex = surf1->fogIndex;
+ vboSurf->cubemapIndex = surf1->cubemapIndex;
VectorCopy(bounds[0], vboSurf->bounds[0]);
VectorCopy(bounds[1], vboSurf->bounds[1]);
@@ -3164,6 +3366,7 @@ void R_MergeLeafSurfaces(void)
mergedSurf->cullinfo.type = CULLINFO_BOX;
mergedSurf->data = (surfaceType_t *)vboSurf;
mergedSurf->fogIndex = surf1->fogIndex;
+ mergedSurf->cubemapIndex = surf1->cubemapIndex;
mergedSurf->shader = surf1->shader;
// redirect view surfaces to this surf
@@ -3540,6 +3743,22 @@ void RE_LoadWorldMap( const char *name ) {
ri.Free(primaryLightGrid);
}
+ // load cubemaps
+ if (r_cubeMapping->integer)
+ {
+ R_LoadCubemapEntities("misc_cubemap");
+ if (!tr.numCubemaps)
+ {
+ // use deathmatch spawn points as cubemaps
+ R_LoadCubemapEntities("info_player_deathmatch");
+ }
+
+ if (tr.numCubemaps)
+ {
+ R_AssignCubemapsToWorldSurfaces();
+ }
+ }
+
// create static VBOS from the world
R_CreateWorldVBO();
if (r_mergeLeafSurfaces->integer)
@@ -3556,5 +3775,11 @@ void RE_LoadWorldMap( const char *name ) {
R_BindNullVBO();
R_BindNullIBO();
+ // Render all cubemaps
+ if (r_cubeMapping->integer && tr.numCubemaps)
+ {
+ R_RenderAllCubemaps();
+ }
+
ri.FS_FreeFile( buffer.v );
}
diff --git a/src/renderergl2/tr_extensions.c b/src/renderergl2/tr_extensions.c
index 10e29742..03b5e23d 100644
--- a/src/renderergl2/tr_extensions.c
+++ b/src/renderergl2/tr_extensions.c
@@ -595,19 +595,50 @@ void GLimp_InitExtraExtensions()
// GL_EXT_texture_sRGB
extension = "GL_EXT_texture_sRGB";
- glRefConfig.texture_srgb = qfalse;
+ glRefConfig.textureSrgb = qfalse;
if (GLimp_HaveExtension(extension))
{
if (r_srgb->integer)
- glRefConfig.texture_srgb = qtrue;
+ glRefConfig.textureSrgb = qtrue;
- ri.Printf(PRINT_ALL, result[glRefConfig.texture_srgb], extension);
+ ri.Printf(PRINT_ALL, result[glRefConfig.textureSrgb], extension);
}
else
{
ri.Printf(PRINT_ALL, result[2], extension);
}
+ // GL_EXT_framebuffer_sRGB
+ extension = "GL_EXT_framebuffer_sRGB";
+ glRefConfig.framebufferSrgb = qfalse;
+ if (GLimp_HaveExtension(extension))
+ {
+ if (r_srgb->integer)
+ glRefConfig.framebufferSrgb = qtrue;
+
+ ri.Printf(PRINT_ALL, result[glRefConfig.framebufferSrgb], extension);
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, result[2], extension);
+ }
+
+ // GL_EXT_texture_sRGB_decode
+ extension = "GL_EXT_texture_sRGB_decode";
+ glRefConfig.textureSrgbDecode = qfalse;
+ if (GLimp_HaveExtension(extension))
+ {
+ if (r_srgb->integer)
+ glRefConfig.textureSrgbDecode = qtrue;
+
+ ri.Printf(PRINT_ALL, result[glRefConfig.textureSrgbDecode], extension);
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, result[2], extension);
+ }
+
+
glRefConfig.textureCompression = TCR_NONE;
// GL_EXT_texture_compression_latc
@@ -664,4 +695,17 @@ void GLimp_InitExtraExtensions()
{
ri.Printf(PRINT_ALL, result[2], extension);
}
+
+ // GL_ARB_seamless_cube_map
+ extension = "GL_ARB_seamless_cube_map";
+ glRefConfig.seamlessCubeMap = qfalse;
+ if( GLimp_HaveExtension( extension ) )
+ {
+ glRefConfig.seamlessCubeMap = qtrue;
+ ri.Printf(PRINT_ALL, result[1], extension);
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, result[2], extension);
+ }
}
diff --git a/src/renderergl2/tr_fbo.c b/src/renderergl2/tr_fbo.c
index fee11d5c..a1d1339b 100644
--- a/src/renderergl2/tr_fbo.c
+++ b/src/renderergl2/tr_fbo.c
@@ -579,6 +579,19 @@ void FBO_Init(void)
R_CheckFBO(tr.screenSsaoFbo);
}
+ {
+ tr.renderCubeFbo = FBO_Create("_renderCubeFbo", tr.renderCubeImage->width, tr.renderCubeImage->height);
+ FBO_Bind(tr.renderCubeFbo);
+
+ //FBO_AttachTextureImage(tr.renderCubeImage, 0);
+ R_AttachFBOTexture2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, tr.renderCubeImage->texnum, 0);
+ glState.currentFBO->colorImage[0] = tr.renderCubeImage;
+
+ FBO_CreateBuffer(tr.renderCubeFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
+
+ R_CheckFBO(tr.renderCubeFbo);
+ }
+
GL_CheckErrors();
FBO_Bind(NULL);
@@ -783,7 +796,10 @@ void FBO_Blit(FBO_t *src, vec4i_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, vec4
vec4i_t srcBox;
if (!src)
+ {
+ ri.Printf(PRINT_WARNING, "Tried to blit from a NULL FBO!\n");
return;
+ }
// framebuffers are 0 bottom, Y up.
if (inSrcBox)
diff --git a/src/renderergl2/tr_flares.c b/src/renderergl2/tr_flares.c
index f097c51e..4c047afc 100644
--- a/src/renderergl2/tr_flares.c
+++ b/src/renderergl2/tr_flares.c
@@ -371,7 +371,7 @@ void RB_RenderFlare( flare_t *f ) {
iColor[1] = color[1] * fogFactors[1];
iColor[2] = color[2] * fogFactors[2];
- RB_BeginSurface( tr.flareShader, f->fogNum );
+ RB_BeginSurface( tr.flareShader, f->fogNum, 0 );
// FIXME: use quadstamp?
tess.xyz[tess.numVertexes][0] = f->windowX - size;
diff --git a/src/renderergl2/tr_glsl.c b/src/renderergl2/tr_glsl.c
index d8b07432..38eb7f6d 100644
--- a/src/renderergl2/tr_glsl.c
+++ b/src/renderergl2/tr_glsl.c
@@ -71,6 +71,7 @@ static uniformInfo_t uniformsInfo[] =
{ "u_TextureMap", GLSL_INT },
{ "u_LevelsMap", GLSL_INT },
+ { "u_CubeMap", GLSL_INT },
{ "u_ScreenImageMap", GLSL_INT },
{ "u_ScreenDepthMap", GLSL_INT },
@@ -997,37 +998,35 @@ void GLSL_InitGPUShaders(void)
for (i = 0; i < LIGHTDEF_COUNT; i++)
{
// skip impossible combos
- if ((i & LIGHTDEF_USE_NORMALMAP) && !r_normalMapping->integer)
- continue;
-
if ((i & LIGHTDEF_USE_PARALLAXMAP) && !r_parallaxMapping->integer)
continue;
- if ((i & LIGHTDEF_USE_SPECULARMAP) && !r_specularMapping->integer)
- continue;
-
if ((i & LIGHTDEF_USE_DELUXEMAP) && !r_deluxeMapping->integer)
continue;
- if (!((i & LIGHTDEF_LIGHTTYPE_MASK) == LIGHTDEF_USE_LIGHTMAP) && (i & LIGHTDEF_USE_DELUXEMAP))
+ if ((i & LIGHTDEF_USE_CUBEMAP) && !r_cubeMapping->integer)
continue;
- if (!(i & LIGHTDEF_USE_NORMALMAP) && (i & LIGHTDEF_USE_PARALLAXMAP))
+ if (!((i & LIGHTDEF_LIGHTTYPE_MASK) == LIGHTDEF_USE_LIGHTMAP) && (i & LIGHTDEF_USE_DELUXEMAP))
continue;
- //if (!((i & LIGHTDEF_LIGHTTYPE_MASK) == LIGHTDEF_USE_LIGHT_VECTOR))
if (!(i & LIGHTDEF_LIGHTTYPE_MASK))
{
if (i & LIGHTDEF_USE_SHADOWMAP)
continue;
+ if (i & LIGHTDEF_USE_CUBEMAP)
+ continue;
}
attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_COLOR | ATTR_NORMAL;
extradefines[0] = '\0';
- if (r_normalAmbient->value > 0.003f)
- Q_strcat(extradefines, 1024, va("#define r_normalAmbient %f\n", r_normalAmbient->value));
+ if (r_deluxeSpecular->value > 0.000001f)
+ Q_strcat(extradefines, 1024, va("#define r_deluxeSpecular %f\n", r_deluxeSpecular->value));
+
+ if (r_specularIsMetallic->value)
+ Q_strcat(extradefines, 1024, va("#define SPECULAR_IS_METALLIC\n"));
if (r_dlightMode->integer >= 2)
Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n");
@@ -1065,7 +1064,7 @@ void GLSL_InitGPUShaders(void)
}
}
- if ((i & LIGHTDEF_USE_NORMALMAP) && r_normalMapping->integer)
+ if (r_normalMapping->integer)
{
Q_strcat(extradefines, 1024, "#define USE_NORMALMAP\n");
@@ -1081,7 +1080,7 @@ void GLSL_InitGPUShaders(void)
#endif
}
- if ((i & LIGHTDEF_USE_SPECULARMAP) && r_specularMapping->integer)
+ if (r_specularMapping->integer)
{
Q_strcat(extradefines, 1024, "#define USE_SPECULARMAP\n");
@@ -1089,19 +1088,23 @@ void GLSL_InitGPUShaders(void)
{
case 1:
default:
- Q_strcat(extradefines, 1024, "#define USE_TRIACE\n");
+ Q_strcat(extradefines, 1024, "#define USE_BLINN\n");
break;
case 2:
- Q_strcat(extradefines, 1024, "#define USE_BLINN\n");
+ Q_strcat(extradefines, 1024, "#define USE_BLINN_FRESNEL\n");
break;
case 3:
- Q_strcat(extradefines, 1024, "#define USE_COOK_TORRANCE\n");
+ Q_strcat(extradefines, 1024, "#define USE_MCAULEY\n");
break;
case 4:
- Q_strcat(extradefines, 1024, "#define USE_TORRANCE_SPARROW\n");
+ Q_strcat(extradefines, 1024, "#define USE_GOTANDA\n");
+ break;
+
+ case 5:
+ Q_strcat(extradefines, 1024, "#define USE_LAZAROV\n");
break;
}
}
@@ -1112,6 +1115,9 @@ void GLSL_InitGPUShaders(void)
if ((i & LIGHTDEF_USE_PARALLAXMAP) && !(i & LIGHTDEF_ENTITY) && r_parallaxMapping->integer)
Q_strcat(extradefines, 1024, "#define USE_PARALLAXMAP\n");
+ if ((i & LIGHTDEF_USE_CUBEMAP))
+ Q_strcat(extradefines, 1024, "#define USE_CUBEMAP\n");
+
if (i & LIGHTDEF_USE_SHADOWMAP)
{
Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n");
@@ -1134,7 +1140,7 @@ void GLSL_InitGPUShaders(void)
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
#ifdef USE_VERT_TANGENT_SPACE
- if (i & LIGHTDEF_USE_NORMALMAP && r_normalMapping->integer)
+ if (r_normalMapping->integer)
{
attribs |= ATTR_TANGENT2 | ATTR_BITANGENT2;
}
@@ -1155,6 +1161,7 @@ void GLSL_InitGPUShaders(void)
GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_DELUXEMAP, TB_DELUXEMAP);
GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SPECULARMAP, TB_SPECULARMAP);
GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SHADOWMAP, TB_SHADOWMAP);
+ GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_CUBEMAP, TB_CUBEMAP);
qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.lightallShader[i]);
@@ -1361,6 +1368,26 @@ void GLSL_InitGPUShaders(void)
numEtcShaders++;
}
+#if 0
+ attribs = ATTR_POSITION | ATTR_TEXCOORD;
+ extradefines[0] = '\0';
+
+ if (!GLSL_InitGPUShader(&tr.testcubeShader, "testcube", attribs, qtrue, extradefines, qtrue, NULL, NULL))
+ {
+ ri.Error(ERR_FATAL, "Could not load testcube shader!");
+ }
+
+ GLSL_InitUniforms(&tr.testcubeShader);
+
+ qglUseProgramObjectARB(tr.testcubeShader.program);
+ GLSL_SetUniformInt(&tr.testcubeShader, UNIFORM_TEXTUREMAP, TB_COLORMAP);
+ qglUseProgramObjectARB(0);
+
+ GLSL_FinishGPUShader(&tr.testcubeShader);
+
+ numEtcShaders++;
+#endif
+
endTime = ri.Milliseconds();
diff --git a/src/renderergl2/tr_image.c b/src/renderergl2/tr_image.c
index 7f264983..61af1b64 100644
--- a/src/renderergl2/tr_image.c
+++ b/src/renderergl2/tr_image.c
@@ -409,7 +409,9 @@ static void RGBAtoNormal(const byte *in, byte *out, int width, int height, qbool
for (x = 0; x < width; x++)
{
- *outbyte = (inbyte[0] >> 2) + (inbyte[1] >> 1) + (inbyte[2] >> 2);
+ byte result = (inbyte[0] >> 2) + (inbyte[1] >> 1) + (inbyte[2] >> 2);
+ result = result * result / 255; // Make linear
+ *outbyte = result;
max = MAX(max, *outbyte);
outbyte += 4;
inbyte += 4;
@@ -1857,7 +1859,7 @@ static GLenum RawImage_GetFormat(const byte *data, int numPixels, qboolean light
}
}
- if (glRefConfig.texture_srgb && (flags & IMGFLAG_SRGB))
+ if (glRefConfig.textureSrgb && (flags & IMGFLAG_SRGB))
{
switch(internalFormat)
{
@@ -2050,7 +2052,7 @@ static void Upload32( byte *data, int width, int height, imgType_t type, imgFlag
}
// Convert to RGB if sRGB textures aren't supported in hardware
- if (!glRefConfig.texture_srgb && (flags & IMGFLAG_SRGB))
+ if (!glRefConfig.textureSrgb && (flags & IMGFLAG_SRGB))
{
byte *in = data;
int c = width * height;
@@ -2279,12 +2281,21 @@ image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgT
if (image->flags & IMGFLAG_CUBEMAP)
{
- GL_BindCubemap(image);
+ GL_Bind(image);
qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
- qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ if (image->flags & IMGFLAG_MIPMAP)
+ {
+ qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ }
+ else
+ {
+ qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic);
qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic);
@@ -2600,6 +2611,7 @@ image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags )
normalPic = ri.Malloc(width * height * 4);
RGBAtoNormal(pic, normalPic, width, height, flags & IMGFLAG_CLAMPTOEDGE);
+#if 1
// Brighten up the original image to work with the normal map
RGBAtoYCoCgA(pic, pic, width, height);
for (y = 0; y < height; y++)
@@ -2615,6 +2627,61 @@ image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags )
}
}
YCoCgAtoRGBA(pic, pic, width, height);
+#else
+ // Blur original image's luma to work with the normal map
+ {
+ byte *blurPic;
+
+ RGBAtoYCoCgA(pic, pic, width, height);
+ blurPic = ri.Malloc(width * height);
+
+ for (y = 1; y < height - 1; y++)
+ {
+ byte *picbyte = pic + y * width * 4;
+ byte *blurbyte = blurPic + y * width;
+
+ picbyte += 4;
+ blurbyte += 1;
+
+ for (x = 1; x < width - 1; x++)
+ {
+ int result;
+
+ result = *(picbyte - (width + 1) * 4) + *(picbyte - width * 4) + *(picbyte - (width - 1) * 4) +
+ *(picbyte - 1 * 4) + *(picbyte ) + *(picbyte + 1 * 4) +
+ *(picbyte + (width - 1) * 4) + *(picbyte + width * 4) + *(picbyte + (width + 1) * 4);
+
+ result /= 9;
+
+ *blurbyte = result;
+ picbyte += 4;
+ blurbyte += 1;
+ }
+ }
+
+ // FIXME: do borders
+
+ for (y = 1; y < height - 1; y++)
+ {
+ byte *picbyte = pic + y * width * 4;
+ byte *blurbyte = blurPic + y * width;
+
+ picbyte += 4;
+ blurbyte += 1;
+
+ for (x = 1; x < width - 1; x++)
+ {
+ picbyte[0] = *blurbyte;
+ picbyte += 4;
+ blurbyte += 1;
+ }
+ }
+
+ ri.Free(blurPic);
+
+ YCoCgAtoRGBA(pic, pic, width, height);
+ }
+#endif
R_CreateImage( normalName, normalPic, normalWidth, normalHeight, IMGTYPE_NORMAL, normalFlags, 0 );
ri.Free( normalPic );
@@ -2806,6 +2873,9 @@ void R_CreateBuiltinImages( void ) {
Com_Memset( data, 255, sizeof( data ) );
tr.whiteImage = R_CreateImage("*white", (byte *)data, 8, 8, IMGTYPE_COLORALPHA, IMGFLAG_NONE, 0);
+ Com_Memset( data, 128, sizeof( data ) );
+ tr.greyImage = R_CreateImage("*grey", (byte *)data, 8, 8, IMGTYPE_COLORALPHA, IMGFLAG_NONE, GL_RGBA8);
+
if (r_dlightMode->integer >= 2)
{
for( x = 0; x < MAX_DLIGHTS; x++)
@@ -2838,7 +2908,7 @@ void R_CreateBuiltinImages( void ) {
if (glRefConfig.framebufferObject)
{
- int width, height, hdrFormat;
+ int width, height, hdrFormat, rgbFormat;
if(glRefConfig.textureNonPowerOfTwo)
{
@@ -2855,19 +2925,15 @@ void R_CreateBuiltinImages( void ) {
if (r_hdr->integer && glRefConfig.framebufferObject && glRefConfig.textureFloat)
hdrFormat = GL_RGB16F_ARB;
+ rgbFormat = GL_RGBA8;
+
tr.renderImage = R_CreateImage("_render", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat);
if (r_drawSunRays->integer)
- tr.sunRaysImage = R_CreateImage("*sunRays", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8);
+ tr.sunRaysImage = R_CreateImage("*sunRays", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, rgbFormat);
if (r_softOverbright->integer)
- {
- int format;
-
- format = GL_RGBA8;
-
- tr.screenScratchImage = R_CreateImage("*screenScratch", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, format);
- }
+ tr.screenScratchImage = R_CreateImage("*screenScratch", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, rgbFormat);
if (glRefConfig.framebufferObject)
{
@@ -2927,6 +2993,8 @@ void R_CreateBuiltinImages( void ) {
{
tr.sunShadowDepthImage[x] = R_CreateImage(va("*sunshadowdepth%i", x), NULL, r_shadowMapSize->integer, r_shadowMapSize->integer, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB);
}
+
+ tr.renderCubeImage = R_CreateImage("*renderCube", NULL, CUBE_MAP_SIZE, CUBE_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_CUBEMAP, rgbFormat);
}
}
diff --git a/src/renderergl2/tr_init.c b/src/renderergl2/tr_init.c
index c02c3345..1019bb26 100644
--- a/src/renderergl2/tr_init.c
+++ b/src/renderergl2/tr_init.c
@@ -132,7 +132,11 @@ cvar_t *r_normalMapping;
cvar_t *r_specularMapping;
cvar_t *r_deluxeMapping;
cvar_t *r_parallaxMapping;
-cvar_t *r_normalAmbient;
+cvar_t *r_cubeMapping;
+cvar_t *r_deluxeSpecular;
+cvar_t *r_specularIsMetallic;
+cvar_t *r_baseSpecular;
+cvar_t *r_baseGloss;
cvar_t *r_recalcMD3Normals;
cvar_t *r_mergeLightmaps;
cvar_t *r_dlightMode;
@@ -885,6 +889,9 @@ void GL_SetDefaultState( void )
qglDrawBuffer( GL_BACK );
qglClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_ACCUM_BUFFER_BIT|GL_STENCIL_BUFFER_BIT );
+
+ if (glRefConfig.seamlessCubeMap)
+ qglEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
}
/*
@@ -1115,7 +1122,11 @@ void R_Register( void )
r_specularMapping = ri.Cvar_Get( "r_specularMapping", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_deluxeMapping = ri.Cvar_Get( "r_deluxeMapping", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_parallaxMapping = ri.Cvar_Get( "r_parallaxMapping", "0", CVAR_ARCHIVE | CVAR_LATCH );
- r_normalAmbient = ri.Cvar_Get( "r_normalAmbient", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_cubeMapping = ri.Cvar_Get( "r_cubeMapping", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_deluxeSpecular = ri.Cvar_Get( "r_deluxeSpecular", "0.3", CVAR_ARCHIVE | CVAR_LATCH );
+ r_specularIsMetallic = ri.Cvar_Get( "r_specularIsMetallic", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_baseSpecular = ri.Cvar_Get( "r_baseSpecular", "0.04", CVAR_ARCHIVE | CVAR_LATCH );
+ r_baseGloss = ri.Cvar_Get( "r_baseGloss", "0.3", CVAR_ARCHIVE | CVAR_LATCH );
r_dlightMode = ri.Cvar_Get( "r_dlightMode", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_pshadowDist = ri.Cvar_Get( "r_pshadowDist", "128", CVAR_ARCHIVE );
r_recalcMD3Normals = ri.Cvar_Get( "r_recalcMD3Normals", "0", CVAR_ARCHIVE | CVAR_LATCH );
diff --git a/src/renderergl2/tr_light.c b/src/renderergl2/tr_light.c
index 82e088e8..ba493198 100644
--- a/src/renderergl2/tr_light.c
+++ b/src/renderergl2/tr_light.c
@@ -450,3 +450,32 @@ int R_LightDirForPoint( vec3_t point, vec3_t lightDir, vec3_t normal, world_t *w
return qtrue;
}
+
+
+int R_CubemapForPoint( vec3_t point )
+{
+ int cubemapIndex = -1;
+
+ if (r_cubeMapping->integer && tr.numCubemaps)
+ {
+ int i;
+ vec_t shortest = (float)WORLD_SIZE * (float)WORLD_SIZE;
+
+ for (i = 0; i < tr.numCubemaps; i++)
+ {
+ vec3_t diff;
+ vec_t length;
+
+ VectorSubtract(point, tr.cubemapOrigins[i], diff);
+ length = DotProduct(diff, diff);
+
+ if (shortest > length)
+ {
+ shortest = length;
+ cubemapIndex = i;
+ }
+ }
+ }
+
+ return cubemapIndex + 1;
+}
diff --git a/src/renderergl2/tr_local.h b/src/renderergl2/tr_local.h
index f9b52028..d8950023 100644
--- a/src/renderergl2/tr_local.h
+++ b/src/renderergl2/tr_local.h
@@ -60,6 +60,8 @@ typedef unsigned int glIndex_t;
#define MAX_CALC_PSHADOWS 64
#define MAX_DRAWN_PSHADOWS 16 // do not increase past 32, because bit flags are used on surfaces
#define PSHADOW_MAP_SIZE 512
+#define CUBE_MAP_MIPS 7
+#define CUBE_MAP_SIZE (1 << CUBE_MAP_MIPS)
#define USE_VERT_TANGENT_SPACE
@@ -369,7 +371,8 @@ enum
TB_SHADOWMAP2 = 3,
TB_SPECULARMAP = 4,
TB_SHADOWMAP = 5,
- NUM_TEXTURE_BUNDLES = 6
+ TB_CUBEMAP = 6,
+ NUM_TEXTURE_BUNDLES = 7
};
typedef enum
@@ -699,13 +702,12 @@ enum
LIGHTDEF_LIGHTTYPE_MASK = 0x0003,
LIGHTDEF_ENTITY = 0x0004,
LIGHTDEF_USE_TCGEN_AND_TCMOD = 0x0008,
- LIGHTDEF_USE_NORMALMAP = 0x0010,
- LIGHTDEF_USE_SPECULARMAP = 0x0020,
- LIGHTDEF_USE_DELUXEMAP = 0x0040,
- LIGHTDEF_USE_PARALLAXMAP = 0x0080,
- LIGHTDEF_USE_SHADOWMAP = 0x0100,
- LIGHTDEF_ALL = 0x01FF,
- LIGHTDEF_COUNT = 0x0200
+ LIGHTDEF_USE_DELUXEMAP = 0x0010,
+ LIGHTDEF_USE_PARALLAXMAP = 0x0020,
+ LIGHTDEF_USE_SHADOWMAP = 0x0040,
+ LIGHTDEF_USE_CUBEMAP = 0x0080,
+ LIGHTDEF_ALL = 0x00FF,
+ LIGHTDEF_COUNT = 0x0100
};
enum
@@ -729,6 +731,7 @@ typedef enum
UNIFORM_TEXTUREMAP,
UNIFORM_LEVELSMAP,
+ UNIFORM_CUBEMAP,
UNIFORM_SCREENIMAGEMAP,
UNIFORM_SCREENDEPTHMAP,
@@ -897,12 +900,14 @@ typedef struct {
typedef enum {
VPF_NONE = 0x00,
- VPF_SHADOWMAP = 0x01,
- VPF_DEPTHSHADOW = 0x02,
- VPF_DEPTHCLAMP = 0x04,
- VPF_ORTHOGRAPHIC = 0x08,
- VPF_USESUNLIGHT = 0x10,
- VPF_FARPLANEFRUSTUM = 0x20
+ VPF_NOVIEWMODEL = 0x01,
+ VPF_SHADOWMAP = 0x02,
+ VPF_DEPTHSHADOW = 0x04,
+ VPF_DEPTHCLAMP = 0x08,
+ VPF_ORTHOGRAPHIC = 0x10,
+ VPF_USESUNLIGHT = 0x20,
+ VPF_FARPLANEFRUSTUM = 0x40,
+ VPF_NOCUBEMAPS = 0x80
} viewParmFlags_t;
typedef struct {
@@ -917,6 +922,8 @@ typedef struct {
cplane_t portalPlane; // clip anything behind this if mirroring
int viewportX, viewportY, viewportWidth, viewportHeight;
FBO_t *targetFbo;
+ int targetFboLayer;
+ int targetFboCubemapIndex;
float fovX, fovY;
float projectionMatrix[16];
cplane_t frustum[5];
@@ -959,7 +966,8 @@ typedef enum {
} surfaceType_t;
typedef struct drawSurf_s {
- unsigned sort; // bit combination for fast compares
+ unsigned int sort; // bit combination for fast compares
+ int cubemapIndex;
surfaceType_t *surface; // any of surface*_t
} drawSurf_t;
@@ -1171,6 +1179,7 @@ typedef struct srfVBOMesh_s
struct shader_s *shader; // FIXME move this to somewhere else
int fogIndex;
+ int cubemapIndex;
// dynamic lighting information
int dlightBits;
@@ -1272,6 +1281,7 @@ typedef struct msurface_s {
//int viewCount; // if == tr.viewCount, already added
struct shader_s *shader;
int fogIndex;
+ int cubemapIndex;
cullinfo_t cullinfo;
surfaceType_t *data; // any of srf*_t
@@ -1601,9 +1611,12 @@ typedef struct {
qboolean framebufferMultisample;
qboolean framebufferBlit;
- qboolean texture_srgb;
+ qboolean textureSrgb;
+ qboolean framebufferSrgb;
+ qboolean textureSrgbDecode;
qboolean depthClamp;
+ qboolean seamlessCubeMap;
} glRefConfig_t;
@@ -1696,6 +1709,7 @@ typedef struct {
image_t *fogImage;
image_t *dlightImage; // inverse-quare highlight for projective adding
image_t *flareImage;
+ image_t *greyImage; // full of 0x80
image_t *whiteImage; // full of 0xff
image_t *identityLightImage; // full of tr.identityLightByte
@@ -1716,6 +1730,7 @@ typedef struct {
image_t *screenShadowImage;
image_t *screenSsaoImage;
image_t *hdrDepthImage;
+ image_t *renderCubeImage;
image_t *textureDepthImage;
@@ -1733,6 +1748,7 @@ typedef struct {
FBO_t *screenShadowFbo;
FBO_t *screenSsaoFbo;
FBO_t *hdrDepthFbo;
+ FBO_t *renderCubeFbo;
shader_t *defaultShader;
shader_t *shadowShader;
@@ -1750,6 +1766,10 @@ typedef struct {
int fatLightmapSize;
int fatLightmapStep;
+ int numCubemaps;
+ vec3_t *cubemapOrigins;
+ image_t **cubemaps;
+
trRefEntity_t *currentEntity;
trRefEntity_t worldEntity; // point currentEntity at this when rendering world
int currentEntityNum;
@@ -1773,6 +1793,7 @@ typedef struct {
shaderProgram_t shadowmaskShader;
shaderProgram_t ssaoShader;
shaderProgram_t depthBlurShader[2];
+ shaderProgram_t testcubeShader;
// -----------------------------------------
@@ -1964,7 +1985,11 @@ extern cvar_t *r_normalMapping;
extern cvar_t *r_specularMapping;
extern cvar_t *r_deluxeMapping;
extern cvar_t *r_parallaxMapping;
-extern cvar_t *r_normalAmbient;
+extern cvar_t *r_cubeMapping;
+extern cvar_t *r_deluxeSpecular;
+extern cvar_t *r_specularIsMetallic;
+extern cvar_t *r_baseSpecular;
+extern cvar_t *r_baseGloss;
extern cvar_t *r_dlightMode;
extern cvar_t *r_pshadowDist;
extern cvar_t *r_recalcMD3Normals;
@@ -2011,6 +2036,7 @@ void R_RenderView( viewParms_t *parms );
void R_RenderDlightCubemaps(const refdef_t *fd);
void R_RenderPshadowMaps(const refdef_t *fd);
void R_RenderSunShadowMaps(const refdef_t *fd, int level);
+void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene );
void R_AddMD3Surfaces( trRefEntity_t *e );
void R_AddNullModelSurfaces( trRefEntity_t *e );
@@ -2024,7 +2050,7 @@ void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader,
int *fogNum, int *dlightMap, int *pshadowMap );
void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader,
- int fogIndex, int dlightMap, int pshadowMap );
+ int fogIndex, int dlightMap, int pshadowMap, int cubemap );
void R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, vec3_t normal,
const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t t0, const vec2_t t1, const vec2_t t2);
@@ -2050,7 +2076,6 @@ void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms,
** GL wrapper/helper functions
*/
void GL_Bind( image_t *image );
-void GL_BindCubemap( image_t *image );
void GL_BindToTMU( image_t *image, int tmu );
void GL_SetDefaultState (void);
void GL_SelectTexture( int unit );
@@ -2201,6 +2226,7 @@ typedef struct shaderCommands_s
shader_t *shader;
float shaderTime;
int fogNum;
+ int cubemapIndex;
int dlightBits; // or together of all vertexDlightBits
int pshadowBits;
@@ -2226,7 +2252,7 @@ typedef struct shaderCommands_s
extern shaderCommands_t tess;
-void RB_BeginSurface(shader_t *shader, int fogNum );
+void RB_BeginSurface(shader_t *shader, int fogNum, int cubemapIndex );
void RB_EndSurface(void);
void RB_CheckOverflow( int verts, int indexes );
#define RB_CHECKOVERFLOW(v,i) if (tess.numVertexes + (v) >= SHADER_MAX_VERTEXES || tess.numIndexes + (i) >= SHADER_MAX_INDEXES ) {RB_CheckOverflow(v,i);}
@@ -2286,6 +2312,7 @@ void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent );
void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or );
int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
int R_LightDirForPoint( vec3_t point, vec3_t lightDir, vec3_t normal, world_t *world );
+int R_CubemapForPoint( vec3_t point );
/*
@@ -2408,7 +2435,9 @@ void RE_AddRefEntityToScene( const refEntity_t *ent );
void RE_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num );
void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b );
+void RE_BeginScene( const refdef_t *fd );
void RE_RenderScene( const refdef_t *fd );
+void RE_EndScene( void );
/*
=============================================================
diff --git a/src/renderergl2/tr_main.c b/src/renderergl2/tr_main.c
index dc8a478c..e10be3a1 100644
--- a/src/renderergl2/tr_main.c
+++ b/src/renderergl2/tr_main.c
@@ -1608,7 +1608,7 @@ static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128
R_RotateForViewer();
R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed );
- RB_BeginSurface( shader, fogNum );
+ RB_BeginSurface( shader, fogNum, drawSurf->cubemapIndex);
rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
assert( tess.numVertexes < 128 );
@@ -1726,6 +1726,9 @@ qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) {
return qfalse; // bad portal, no portalentity
}
+ if (newParms.isMirror)
+ newParms.flags |= VPF_NOVIEWMODEL;
+
R_MirrorPoint (oldParms.or.origin, &surface, &camera, newParms.or.origin );
VectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal );
@@ -1845,7 +1848,7 @@ R_AddDrawSurf
=================
*/
void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader,
- int fogIndex, int dlightMap, int pshadowMap ) {
+ int fogIndex, int dlightMap, int pshadowMap, int cubemap ) {
int index;
// instead of checking for overflow, we just mask the index
@@ -1856,6 +1859,7 @@ void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader,
tr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT)
| tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT )
| ((int)pshadowMap << QSORT_PSHADOW_SHIFT) | (int)dlightMap;
+ tr.refdef.drawSurfs[index].cubemapIndex = cubemap;
tr.refdef.drawSurfs[index].surface = surface;
tr.refdef.numDrawSurfs++;
}
@@ -1959,8 +1963,7 @@ static void R_AddEntitySurface (int entityNum)
// we don't want the hacked weapon position showing in
// mirrors, because the true body position will already be drawn
//
- if ( (ent->e.renderfx & RF_FIRST_PERSON) && (tr.viewParms.isPortal
- || (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW))) ) {
+ if ( (ent->e.renderfx & RF_FIRST_PERSON) && (tr.viewParms.flags & VPF_NOVIEWMODEL)) {
return;
}
@@ -1980,7 +1983,7 @@ static void R_AddEntitySurface (int entityNum)
return;
}
shader = R_GetShaderByHandle( ent->e.customShader );
- R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0, 0 );
+ R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0, 0, 0 /*cubeMap*/ );
break;
case RT_MODEL:
@@ -1989,7 +1992,7 @@ static void R_AddEntitySurface (int entityNum)
tr.currentModel = R_GetModelByHandle( ent->e.hModel );
if (!tr.currentModel) {
- R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0 );
+ R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0, 0 /*cubeMap*/ );
} else {
switch ( tr.currentModel->type ) {
case MOD_MESH:
@@ -2011,7 +2014,7 @@ static void R_AddEntitySurface (int entityNum)
if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) {
break;
}
- R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0 );
+ R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0, 0 );
break;
default:
ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" );
@@ -2187,7 +2190,7 @@ void R_RenderDlightCubemaps(const refdef_t *fd)
shadowParms.fovX = 90;
shadowParms.fovY = 90;
- shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW;
+ shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW | VPF_NOVIEWMODEL;
shadowParms.zFar = tr.refdef.dlights[i].radius;
VectorCopy( tr.refdef.dlights[i].origin, shadowParms.or.origin );
@@ -2491,7 +2494,7 @@ void R_RenderPshadowMaps(const refdef_t *fd)
if (glRefConfig.framebufferObject)
shadowParms.targetFbo = tr.pshadowFbos[i];
- shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW;
+ shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW | VPF_NOVIEWMODEL;
shadowParms.zFar = shadow->lightRadius;
VectorCopy(shadow->lightOrigin, shadowParms.or.origin);
@@ -2836,7 +2839,7 @@ void R_RenderSunShadowMaps(const refdef_t *fd, int level)
if (glRefConfig.framebufferObject)
shadowParms.targetFbo = tr.sunShadowFbo[level];
- shadowParms.flags = VPF_DEPTHSHADOW | VPF_DEPTHCLAMP | VPF_ORTHOGRAPHIC;
+ shadowParms.flags = VPF_DEPTHSHADOW | VPF_DEPTHCLAMP | VPF_ORTHOGRAPHIC | VPF_NOVIEWMODEL;
shadowParms.zFar = lightviewBounds[1][0];
VectorCopy(lightOrigin, shadowParms.or.origin);
@@ -2875,3 +2878,130 @@ void R_RenderSunShadowMaps(const refdef_t *fd, int level)
Matrix16Multiply(tr.viewParms.projectionMatrix, tr.viewParms.world.modelMatrix, tr.refdef.sunShadowMvp[level]);
}
}
+
+void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene )
+{
+ refdef_t refdef;
+ viewParms_t parms;
+ float oldColorScale = tr.refdef.colorScale;
+
+ memset( &refdef, 0, sizeof( refdef ) );
+ refdef.rdflags = 0;
+ VectorCopy(tr.cubemapOrigins[cubemapIndex], refdef.vieworg);
+
+ switch(cubemapSide)
+ {
+ case 0:
+ // -X
+ VectorSet( refdef.viewaxis[0], -1, 0, 0);
+ VectorSet( refdef.viewaxis[1], 0, 0, -1);
+ VectorSet( refdef.viewaxis[2], 0, 1, 0);
+ break;
+ case 1:
+ // +X
+ VectorSet( refdef.viewaxis[0], 1, 0, 0);
+ VectorSet( refdef.viewaxis[1], 0, 0, 1);
+ VectorSet( refdef.viewaxis[2], 0, 1, 0);
+ break;
+ case 2:
+ // -Y
+ VectorSet( refdef.viewaxis[0], 0, -1, 0);
+ VectorSet( refdef.viewaxis[1], 1, 0, 0);
+ VectorSet( refdef.viewaxis[2], 0, 0, -1);
+ break;
+ case 3:
+ // +Y
+ VectorSet( refdef.viewaxis[0], 0, 1, 0);
+ VectorSet( refdef.viewaxis[1], 1, 0, 0);
+ VectorSet( refdef.viewaxis[2], 0, 0, 1);
+ break;
+ case 4:
+ // -Z
+ VectorSet( refdef.viewaxis[0], 0, 0, -1);
+ VectorSet( refdef.viewaxis[1], 1, 0, 0);
+ VectorSet( refdef.viewaxis[2], 0, 1, 0);
+ break;
+ case 5:
+ // +Z
+ VectorSet( refdef.viewaxis[0], 0, 0, 1);
+ VectorSet( refdef.viewaxis[1], -1, 0, 0);
+ VectorSet( refdef.viewaxis[2], 0, 1, 0);
+ break;
+ }
+
+ refdef.fov_x = 90;
+ refdef.fov_y = 90;
+
+ refdef.x = 0;
+ refdef.y = 0;
+ refdef.width = tr.renderCubeFbo->width;
+ refdef.height = tr.renderCubeFbo->height;
+
+ refdef.time = 0;
+
+ if (!subscene)
+ {
+ RE_BeginScene(&refdef);
+
+ // FIXME: sun shadows aren't rendered correctly in cubemaps
+ // fix involves changing r_FBufScale to fit smaller cubemap image size, or rendering cubemap to framebuffer first
+ if(0) //(glRefConfig.framebufferObject && (r_forceSun->integer || tr.sunShadows))
+ {
+ R_RenderSunShadowMaps(&refdef, 0);
+ R_RenderSunShadowMaps(&refdef, 1);
+ R_RenderSunShadowMaps(&refdef, 2);
+ }
+ }
+
+ {
+ vec3_t ambient, directed, lightDir;
+ R_LightForPoint(tr.refdef.vieworg, ambient, directed, lightDir);
+ tr.refdef.colorScale = 766.0f / (directed[0] + directed[1] + directed[2] + 1.0f);
+ if (directed[0] + directed[1] + directed[2] == 0)
+ {
+ ri.Printf(PRINT_ALL, "cubemap %d (%f, %f, %f) is outside the lightgrid!\n", cubemapIndex, tr.refdef.vieworg[0], tr.refdef.vieworg[1], tr.refdef.vieworg[2]);
+ }
+ }
+
+ Com_Memset( &parms, 0, sizeof( parms ) );
+
+ parms.viewportX = 0;
+ parms.viewportY = 0;
+ parms.viewportWidth = tr.renderCubeFbo->width;
+ parms.viewportHeight = tr.renderCubeFbo->height;
+ parms.isPortal = qfalse;
+ parms.isMirror = qtrue;
+ parms.flags = VPF_NOVIEWMODEL | VPF_NOCUBEMAPS;
+
+ parms.fovX = 90;
+ parms.fovY = 90;
+
+ VectorCopy( refdef.vieworg, parms.or.origin );
+ VectorCopy( refdef.viewaxis[0], parms.or.axis[0] );
+ VectorCopy( refdef.viewaxis[1], parms.or.axis[1] );
+ VectorCopy( refdef.viewaxis[2], parms.or.axis[2] );
+
+ VectorCopy( refdef.vieworg, parms.pvsOrigin );
+
+ // FIXME: sun shadows aren't rendered correctly in cubemaps
+ // fix involves changing r_FBufScale to fit smaller cubemap image size, or rendering cubemap to framebuffer first
+ if (0) //(r_depthPrepass->value && ((r_forceSun->integer) || tr.sunShadows))
+ {
+ parms.flags = VPF_USESUNLIGHT;
+ }
+
+ parms.targetFbo = tr.renderCubeFbo;
+ parms.targetFboLayer = cubemapSide;
+ parms.targetFboCubemapIndex = cubemapIndex;
+
+ R_RenderView(&parms);
+
+ if (subscene)
+ {
+ tr.refdef.colorScale = oldColorScale;
+ }
+ else
+ {
+ RE_EndScene();
+ }
+} \ No newline at end of file
diff --git a/src/renderergl2/tr_mesh.c b/src/renderergl2/tr_mesh.c
index d1adba2c..72078b75 100644
--- a/src/renderergl2/tr_mesh.c
+++ b/src/renderergl2/tr_mesh.c
@@ -289,6 +289,7 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
int cull;
int lod;
int fogNum;
+ int cubemapIndex;
qboolean personalModel;
// don't add third_person objects if not in a portal
@@ -345,6 +346,8 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
//
fogNum = R_ComputeFogNum( model, ent );
+ cubemapIndex = R_CubemapForPoint(ent->e.origin);
+
//
// draw all surfaces
//
@@ -388,7 +391,7 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
{
srfVBOMDVMesh_t *vboSurface = &model->vboSurfaces[i];
- R_AddDrawSurf((void *)vboSurface, shader, fogNum, qfalse, qfalse );
+ R_AddDrawSurf((void *)vboSurface, shader, fogNum, qfalse, qfalse, cubemapIndex );
}
surface++;
diff --git a/src/renderergl2/tr_model_iqm.c b/src/renderergl2/tr_model_iqm.c
index a2f6f250..05b17dc7 100644
--- a/src/renderergl2/tr_model_iqm.c
+++ b/src/renderergl2/tr_model_iqm.c
@@ -786,6 +786,7 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
qboolean personalModel;
int cull;
int fogNum;
+ int cubemapIndex;
shader_t *shader;
skin_t *skin;
@@ -838,6 +839,8 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
//
fogNum = R_ComputeIQMFogNum( data, ent );
+ cubemapIndex = R_CubemapForPoint(ent->e.origin);
+
for ( i = 0 ; i < data->num_surfaces ; i++ ) {
if(ent->e.customShader)
shader = R_GetShaderByHandle( ent->e.customShader );
@@ -866,7 +869,7 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
&& fogNum == 0
&& !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
&& shader->sort == SS_OPAQUE ) {
- R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, 0, 0 );
+ R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, 0, 0, 0 );
}
// projection shadows work fine with personal models
@@ -874,11 +877,11 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
&& fogNum == 0
&& (ent->e.renderfx & RF_SHADOW_PLANE )
&& shader->sort == SS_OPAQUE ) {
- R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, 0, 0 );
+ R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, 0, 0, 0 );
}
if( !personalModel ) {
- R_AddDrawSurf( (void *)surface, shader, fogNum, 0, 0 );
+ R_AddDrawSurf( (void *)surface, shader, fogNum, 0, 0, cubemapIndex );
}
surface++;
diff --git a/src/renderergl2/tr_scene.c b/src/renderergl2/tr_scene.c
index 71e816b4..254626cb 100644
--- a/src/renderergl2/tr_scene.c
+++ b/src/renderergl2/tr_scene.c
@@ -100,7 +100,7 @@ void R_AddPolygonSurfaces( void ) {
for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) {
sh = R_GetShaderByHandle( poly->hShader );
- R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex & fogMask, qfalse, qfalse );
+ R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex & fogMask, qfalse, qfalse, 0 /*cubeMap*/ );
}
}
@@ -284,36 +284,9 @@ void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, flo
RE_AddDynamicLightToScene( org, intensity, r, g, b, qtrue );
}
-/*
-@@@@@@@@@@@@@@@@@@@@@
-RE_RenderScene
-
-Draw a 3D view into a part of the window, then return
-to 2D drawing.
-
-Rendering a scene may require multiple views to be rendered
-to handle mirrors,
-@@@@@@@@@@@@@@@@@@@@@
-*/
-void RE_RenderScene( const refdef_t *fd ) {
- viewParms_t parms;
- int startTime;
-
- if ( !tr.registered ) {
- return;
- }
- GLimp_LogComment( "====== RE_RenderScene =====\n" );
-
- if ( r_norefresh->integer ) {
- return;
- }
-
- startTime = ri.Milliseconds();
-
- if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
- ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel");
- }
+void RE_BeginScene(const refdef_t *fd)
+{
Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) );
tr.refdef.x = fd->x;
@@ -467,6 +440,49 @@ void RE_RenderScene( const refdef_t *fd ) {
// each scene / view.
tr.frameSceneNum++;
tr.sceneCount++;
+}
+
+
+void RE_EndScene()
+{
+ // the next scene rendered in this frame will tack on after this one
+ r_firstSceneDrawSurf = tr.refdef.numDrawSurfs;
+ r_firstSceneEntity = r_numentities;
+ r_firstSceneDlight = r_numdlights;
+ r_firstScenePoly = r_numpolys;
+}
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+RE_RenderScene
+
+Draw a 3D view into a part of the window, then return
+to 2D drawing.
+
+Rendering a scene may require multiple views to be rendered
+to handle mirrors,
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void RE_RenderScene( const refdef_t *fd ) {
+ viewParms_t parms;
+ int startTime;
+
+ if ( !tr.registered ) {
+ return;
+ }
+ GLimp_LogComment( "====== RE_RenderScene =====\n" );
+
+ if ( r_norefresh->integer ) {
+ return;
+ }
+
+ startTime = ri.Milliseconds();
+
+ if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
+ ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel");
+ }
+
+ RE_BeginScene(fd);
// SmileTheory: playing with shadow mapping
if (!( fd->rdflags & RDF_NOWORLDMODEL ) && tr.refdef.num_dlights && r_dlightMode->integer >= 2)
@@ -488,6 +504,21 @@ void RE_RenderScene( const refdef_t *fd ) {
R_RenderSunShadowMaps(fd, 2);
}
+ // playing with cube maps
+ // this is where dynamic cubemaps would be rendered
+ if (0) //(glRefConfig.framebufferObject && !( fd->rdflags & RDF_NOWORLDMODEL ))
+ {
+ int i, j;
+
+ for (i = 0; i < tr.numCubemaps; i++)
+ {
+ for (j = 0; j < 6; j++)
+ {
+ R_RenderCubemapSide(i, j, qtrue);
+ }
+ }
+ }
+
// setup view parms for the initial view
//
// set up viewport
@@ -523,11 +554,7 @@ void RE_RenderScene( const refdef_t *fd ) {
if(!( fd->rdflags & RDF_NOWORLDMODEL ))
R_AddPostProcessCmd();
- // the next scene rendered in this frame will tack on after this one
- r_firstSceneDrawSurf = tr.refdef.numDrawSurfs;
- r_firstSceneEntity = r_numentities;
- r_firstSceneDlight = r_numdlights;
- r_firstScenePoly = r_numpolys;
+ RE_EndScene();
tr.frontEndMsec += ri.Milliseconds() - startTime;
}
diff --git a/src/renderergl2/tr_shade.c b/src/renderergl2/tr_shade.c
index 0810547b..18ecbc9b 100644
--- a/src/renderergl2/tr_shade.c
+++ b/src/renderergl2/tr_shade.c
@@ -187,7 +187,7 @@ because a surface may be forced to perform a RB_End due
to overflow.
==============
*/
-void RB_BeginSurface( shader_t *shader, int fogNum ) {
+void RB_BeginSurface( shader_t *shader, int fogNum, int cubemapIndex ) {
shader_t *state = (shader->remappedShader) ? shader->remappedShader : shader;
@@ -197,6 +197,7 @@ void RB_BeginSurface( shader_t *shader, int fogNum ) {
tess.multiDrawPrimitives = 0;
tess.shader = state;
tess.fogNum = fogNum;
+ tess.cubemapIndex = cubemapIndex;
tess.dlightBits = 0; // will be OR'd in by surface functions
tess.pshadowBits = 0; // will be OR'd in by surface functions
tess.xstages = state->stages;
@@ -847,7 +848,7 @@ static void ForwardDlight( void ) {
if (r_dlightMode->integer >= 2)
{
GL_SelectTexture(TB_SHADOWMAP);
- GL_BindCubemap(tr.shadowCubemaps[l]);
+ GL_Bind(tr.shadowCubemaps[l]);
GL_SelectTexture(0);
}
@@ -1134,6 +1135,11 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
index |= LIGHTDEF_USE_SHADOWMAP;
}
+ if (!(tr.viewParms.flags & VPF_NOCUBEMAPS) && (index & LIGHTDEF_LIGHTTYPE_MASK) && input->cubemapIndex)
+ {
+ index |= LIGHTDEF_USE_CUBEMAP;
+ }
+
if (r_lightmap->integer && index & LIGHTDEF_USE_LIGHTMAP)
{
index = LIGHTDEF_USE_LIGHTMAP;
@@ -1178,39 +1184,10 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
{
vec4_t baseColor;
vec4_t vertColor;
- qboolean tint = qtrue;
- int stage2;
ComputeShaderColors(pStage, baseColor, vertColor);
- for ( stage2 = stage + 1; stage2 < MAX_SHADER_STAGES; stage2++ )
- {
- shaderStage_t *pStage2 = input->xstages[stage2];
- unsigned int srcBlendBits;
- //unsigned int dstBlendBits;
-
- if ( !pStage2 )
- {
- break;
- }
-
- srcBlendBits = pStage2->stateBits & GLS_SRCBLEND_BITS;
- //dstBlendBits = pStage2->stateBits & GLS_DSTBLEND_BITS;
-
- if (srcBlendBits == GLS_SRCBLEND_DST_COLOR)
- {
- tint = qfalse;
- break;
- }
- }
-
- if (!((tr.sunShadows || r_forceSun->integer) && tess.shader->sort <= SS_OPAQUE
- && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) && tess.xstages[0]->glslShaderGroup == tr.lightallShader))
- {
- tint = qfalse;
- }
-
- if (tint)
+ if ((backEnd.refdef.colorScale != 1.0f) && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL))
{
// use VectorScale to only scale first three values, not alpha
VectorScale(baseColor, backEnd.refdef.colorScale, baseColor);
@@ -1375,6 +1352,12 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
}
//
+ // testing cube map
+ //
+ if (!(tr.viewParms.flags & VPF_NOCUBEMAPS) && input->cubemapIndex && r_cubeMapping->integer)
+ GL_BindToTMU( tr.cubemaps[input->cubemapIndex - 1], TB_CUBEMAP);
+
+ //
// draw
//
if (input->multiDrawPrimitives)
diff --git a/src/renderergl2/tr_shader.c b/src/renderergl2/tr_shader.c
index 6bf4fa43..5057b436 100644
--- a/src/renderergl2/tr_shader.c
+++ b/src/renderergl2/tr_shader.c
@@ -911,8 +911,8 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
else if(!Q_stricmp(token, "specularMap"))
{
stage->type = ST_SPECULARMAP;
- stage->materialInfo[0] = 0.04f;
- stage->materialInfo[1] = 256.0f;
+ stage->materialInfo[0] = 1.0f;
+ stage->materialInfo[1] = 1.0f;
}
else
{
@@ -938,12 +938,35 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
//
else if (!Q_stricmp(token, "specularexponent"))
{
+ float exponent;
+
token = COM_ParseExt(text, qfalse);
if ( token[0] == 0 )
{
ri.Printf( PRINT_WARNING, "WARNING: missing parameter for specular exponent in shader '%s'\n", shader.name );
continue;
}
+
+ exponent = atof( token );
+
+ // Change shininess to gloss
+ // FIXME: assumes max exponent of 8192 and min of 1, must change here if altered in lightall_fp.glsl
+ exponent = CLAMP(exponent, 1.0, 8192.0);
+
+ stage->materialInfo[1] = log(exponent) / log(8192.0);
+ }
+ //
+ // gloss <value>
+ //
+ else if (!Q_stricmp(token, "gloss"))
+ {
+ token = COM_ParseExt(text, qfalse);
+ if ( token[0] == 0 )
+ {
+ ri.Printf( PRINT_WARNING, "WARNING: missing parameter for gloss in shader '%s'\n", shader.name );
+ continue;
+ }
+
stage->materialInfo[1] = atof( token );
}
//
@@ -1927,7 +1950,7 @@ static void ComputeVertexAttribs(void)
shader.vertexAttribs |= ATTR_NORMAL;
#ifdef USE_VERT_TANGENT_SPACE
- if (pStage->glslShaderIndex & LIGHTDEF_USE_NORMALMAP)
+ if ((pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && !(r_normalMapping->integer == 0 && r_specularMapping->integer == 0))
{
shader.vertexAttribs |= ATTR_BITANGENT | ATTR_TANGENT;
}
@@ -2201,7 +2224,6 @@ static void CollapseStagesToLightall(shaderStage_t *diffuse,
{
//ri.Printf(PRINT_ALL, ", normalmap %s", normal->bundle[0].image[0]->imgName);
diffuse->bundle[TB_NORMALMAP] = normal->bundle[0];
- defs |= LIGHTDEF_USE_NORMALMAP;
if (parallax && r_parallaxMapping->integer)
defs |= LIGHTDEF_USE_PARALLAXMAP;
}
@@ -2219,13 +2241,22 @@ static void CollapseStagesToLightall(shaderStage_t *diffuse,
if (normalImg)
{
diffuse->bundle[TB_NORMALMAP] = diffuse->bundle[0];
+ diffuse->bundle[TB_NORMALMAP].numImageAnimations = 0;
diffuse->bundle[TB_NORMALMAP].image[0] = normalImg;
- defs |= LIGHTDEF_USE_NORMALMAP;
if (parallax && r_parallaxMapping->integer)
defs |= LIGHTDEF_USE_PARALLAXMAP;
}
}
+
+ if (!diffuse->bundle[TB_NORMALMAP].image[0])
+ {
+ // use 0x80 image, shader will interpret as (0,0,1)
+ diffuse->bundle[TB_NORMALMAP] = diffuse->bundle[0];
+ diffuse->bundle[TB_NORMALMAP].numImageAnimations = 0;
+ diffuse->bundle[TB_NORMALMAP].image[0] = tr.greyImage;
+ //ri.Printf(PRINT_ALL, ", normalmap %s", diffuse->bundle[TB_NORMALMAP].image[0]->imgName);
+ }
}
if (r_specularMapping->integer)
@@ -2236,7 +2267,18 @@ static void CollapseStagesToLightall(shaderStage_t *diffuse,
diffuse->bundle[TB_SPECULARMAP] = specular->bundle[0];
diffuse->materialInfo[0] = specular->materialInfo[0];
diffuse->materialInfo[1] = specular->materialInfo[1];
- defs |= LIGHTDEF_USE_SPECULARMAP;
+ }
+ else if (lightmap || useLightVector || useLightVertex)
+ {
+ // use a white image, materialinfo will do the rest
+ diffuse->bundle[TB_SPECULARMAP] = diffuse->bundle[0];
+ diffuse->bundle[TB_SPECULARMAP].numImageAnimations = 0;
+ diffuse->bundle[TB_SPECULARMAP].image[0] = tr.whiteImage;
+ if (!diffuse->materialInfo[0])
+ diffuse->materialInfo[0] = r_baseSpecular->value;
+ if (!diffuse->materialInfo[1])
+ diffuse->materialInfo[1] = r_baseGloss->value;
+ //ri.Printf(PRINT_ALL, ", specularmap %s", diffuse->bundle[TB_SPECULARMAP].image[0]->imgName);
}
}
@@ -2540,6 +2582,22 @@ static qboolean CollapseStagesToGLSL(void)
}
}
+ // convert any remaining lightingdiffuse stages to a lighting pass
+ for (i = 0; i < MAX_SHADER_STAGES; i++)
+ {
+ shaderStage_t *pStage = &stages[i];
+
+ if (!pStage->active)
+ continue;
+
+ if (pStage->rgbGen == CGEN_LIGHTING_DIFFUSE)
+ {
+ pStage->glslShaderGroup = tr.lightallShader;
+ pStage->glslShaderIndex = LIGHTDEF_USE_LIGHT_VECTOR;
+ }
+ }
+
+
return numStages;
}
diff --git a/src/renderergl2/tr_sky.c b/src/renderergl2/tr_sky.c
index d8fcf506..7c15f732 100644
--- a/src/renderergl2/tr_sky.c
+++ b/src/renderergl2/tr_sky.c
@@ -450,7 +450,7 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max
color[0] =
color[1] =
- color[2] = tr.identityLight;
+ color[2] = tr.identityLight * backEnd.refdef.colorScale;
color[3] = 1.0f;
GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, color);
@@ -827,7 +827,7 @@ void RB_DrawSun( float scale, shader_t *shader ) {
// farthest depth range
qglDepthRange( 1.0, 1.0 );
- RB_BeginSurface( shader, 0 );
+ RB_BeginSurface( shader, 0, 0 );
RB_AddQuadStamp(origin, vec1, vec2, colorWhite);
diff --git a/src/renderergl2/tr_surface.c b/src/renderergl2/tr_surface.c
index ffdb2964..50711594 100644
--- a/src/renderergl2/tr_surface.c
+++ b/src/renderergl2/tr_surface.c
@@ -64,7 +64,7 @@ void RB_CheckOverflow( int verts, int indexes ) {
ri.Error(ERR_DROP, "RB_CheckOverflow: indices > MAX (%d > %d)", indexes, SHADER_MAX_INDEXES );
}
- RB_BeginSurface(tess.shader, tess.fogNum );
+ RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex );
}
void RB_CheckVBOandIBO(VBO_t *vbo, IBO_t *ibo)
@@ -72,7 +72,7 @@ void RB_CheckVBOandIBO(VBO_t *vbo, IBO_t *ibo)
if (!(vbo == glState.currentVBO && ibo == glState.currentIBO) || tess.multiDrawPrimitives >= MAX_MULTIDRAW_PRIMITIVES)
{
RB_EndSurface();
- RB_BeginSurface(tess.shader, tess.fogNum);
+ RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex);
R_BindVBO(vbo);
R_BindIBO(ibo);
@@ -1371,7 +1371,7 @@ static void RB_SurfaceGrid( srfGridMesh_t *srf ) {
// if we don't have enough space for at least one strip, flush the buffer
if ( vrows < 2 || irows < 1 ) {
RB_EndSurface();
- RB_BeginSurface(tess.shader, tess.fogNum );
+ RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex );
} else {
break;
}
@@ -1594,7 +1594,7 @@ void RB_SurfaceVBOMDVMesh(srfVBOMDVMesh_t * surface)
//RB_CheckVBOandIBO(surface->vbo, surface->ibo);
RB_EndSurface();
- RB_BeginSurface(tess.shader, tess.fogNum);
+ RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex);
R_BindVBO(surface->vbo);
R_BindIBO(surface->ibo);
diff --git a/src/renderergl2/tr_world.c b/src/renderergl2/tr_world.c
index a6bb310b..5d35cded 100644
--- a/src/renderergl2/tr_world.c
+++ b/src/renderergl2/tr_world.c
@@ -338,7 +338,7 @@ static void R_AddWorldSurface( msurface_t *surf, int dlightBits, int pshadowBits
pshadowBits = ( pshadowBits != 0 );
}
- R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits, pshadowBits );
+ R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits, pshadowBits, surf->cubemapIndex );
}
/*