cvar_t r_showcollisionbrushes_polygonfactor = {0, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
cvar_t r_showcollisionbrushes_polygonoffset = {0, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
cvar_t r_showdisabledepthtest = {0, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
+cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"};
cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
cvar_t r_bloom_power = {CVAR_SAVE, "r_bloom_power", "2", "how much to darken the image before blurring to make the bloom effect"};
+cvar_t r_hdr = {CVAR_SAVE, "r_hdr", "0", "enables High Dynamic Range bloom effect (higher quality version of r_bloom)"};
+cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
+cvar_t r_hdr_bloomintensity = {CVAR_SAVE, "r_hdr_bloomintensity", "0.5", "amount of bloom"};
+cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
+
cvar_t r_smoothnormals_areaweighting = {0, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
cvar_t developer_texturelogging = {0, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
"\n"
"// common definitions between vertex shader and fragment shader:\n"
"\n"
+"#ifdef __GLSL_CG_DATA_TYPES\n"
+"#define myhalf half\n"
+"#define myhvec2 hvec2\n"
+"#define myhvec3 hvec3\n"
+"#define myhvec4 hvec4\n"
+"#else\n"
+"#define myhalf float\n"
+"#define myhvec2 vec2\n"
+"#define myhvec3 vec3\n"
+"#define myhvec4 vec4\n"
+"#endif\n"
+"\n"
"varying vec2 TexCoord;\n"
"varying vec2 TexCoordLightmap;\n"
"\n"
"uniform sampler2D Texture_Deluxemap;\n"
"uniform sampler2D Texture_Glow;\n"
"\n"
-"uniform vec3 LightColor;\n"
-"uniform vec3 AmbientColor;\n"
-"uniform vec3 DiffuseColor;\n"
-"uniform vec3 SpecularColor;\n"
-"uniform vec3 Color_Pants;\n"
-"uniform vec3 Color_Shirt;\n"
-"uniform vec3 FogColor;\n"
+"uniform myhvec3 LightColor;\n"
+"uniform myhvec3 AmbientColor;\n"
+"uniform myhvec3 DiffuseColor;\n"
+"uniform myhvec3 SpecularColor;\n"
+"uniform myhvec3 Color_Pants;\n"
+"uniform myhvec3 Color_Shirt;\n"
+"uniform myhvec3 FogColor;\n"
+"\n"
+"uniform myhalf GlowScale;\n"
+"uniform myhalf SceneBrightness;\n"
"\n"
"uniform float OffsetMapping_Scale;\n"
"uniform float OffsetMapping_Bias;\n"
"uniform float FogRangeRecip;\n"
"\n"
-"uniform float AmbientScale;\n"
-"uniform float DiffuseScale;\n"
-"uniform float SpecularScale;\n"
-"uniform float SpecularPower;\n"
+"uniform myhalf AmbientScale;\n"
+"uniform myhalf DiffuseScale;\n"
+"uniform myhalf SpecularScale;\n"
+"uniform myhalf SpecularPower;\n"
"\n"
"void main(void)\n"
"{\n"
"\n"
"#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n"
" // 14 sample relief mapping: linear search and then binary search\n"
-" vec3 OffsetVector = vec3(EyeVector.xy * (1.0 / EyeVector.z) * depthbias * OffsetMapping_Scale * vec2(-0.1, 0.1), -0.1);\n"
+" //vec3 OffsetVector = vec3(EyeVector.xy * (1.0 / EyeVector.z) * depthbias * OffsetMapping_Scale * vec2(-0.1, 0.1), -0.1);\n"
+" //vec3 OffsetVector = vec3(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-0.1, 0.1), -0.1);\n"
+" vec3 OffsetVector = vec3(eyedir.xy * OffsetMapping_Scale * vec2(-0.1, 0.1), -0.1);\n"
" vec3 RT = vec3(TexCoord - OffsetVector.xy * 10.0, 1.0) + OffsetVector;\n"
" if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
" if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
" if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;\n"
" if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;\n"
" TexCoord = RT.xy;\n"
-"#else\n"
+"#elif 1\n"
" // 3 sample offset mapping (only 3 samples because of ATI Radeon 9500-9800/X300 limits)\n"
-" vec2 OffsetVector = vec2((EyeVector.xy * (1.0 / EyeVector.z) * depthbias) * OffsetMapping_Scale * vec2(-0.333, 0.333));\n"
+" //vec2 OffsetVector = vec2(EyeVector.xy * (1.0 / EyeVector.z) * depthbias) * OffsetMapping_Scale * vec2(-0.333, 0.333);\n"
+" //vec2 OffsetVector = vec2(normalize(EyeVector.xy)) * OffsetMapping_Scale * vec2(-0.333, 0.333);\n"
+" vec2 OffsetVector = vec2(eyedir.xy) * OffsetMapping_Scale * vec2(-0.333, 0.333);\n"
" //TexCoord += OffsetVector * 3.0;\n"
" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
+"#elif 0\n"
+" // 10 sample offset mapping\n"
+" //vec2 OffsetVector = vec2(EyeVector.xy * (1.0 / EyeVector.z) * depthbias) * OffsetMapping_Scale * vec2(-0.333, 0.333);\n"
+" //vec2 OffsetVector = vec2(normalize(EyeVector.xy)) * OffsetMapping_Scale * vec2(-0.333, 0.333);\n"
+" vec2 OffsetVector = vec2(eyedir.xy) * OffsetMapping_Scale * vec2(-0.1, 0.1);\n"
+" //TexCoord += OffsetVector * 3.0;\n"
+" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
+" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
+" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
+" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
+" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
+" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
+" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
+" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
+" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
+" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
+"#elif 1\n"
+" // parallax mapping as described in the paper\n"
+" // 'Parallax Mapping with Offset Limiting: A Per-Pixel Approximation of Uneven Surfaces' by Terry Welsh\n"
+" // The paper provides code in the ARB fragment program assembly language\n"
+" // I translated it to GLSL but may have done something wrong - SavageX\n"
+" // LordHavoc: removed bias and simplified to one line\n"
+" // LordHavoc: this is just a single sample offsetmapping...\n"
+" TexCoordOffset += vec2(eyedir.x, -1.0 * eyedir.y) * OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).a;\n"
+"#else\n"
+" // parallax mapping as described in the paper\n"
+" // 'Parallax Mapping with Offset Limiting: A Per-Pixel Approximation of Uneven Surfaces' by Terry Welsh\n"
+" // The paper provides code in the ARB fragment program assembly language\n"
+" // I translated it to GLSL but may have done something wrong - SavageX\n"
+" float height = texture2D(Texture_Normal, TexCoord).a;\n"
+" height = (height - 0.5) * OffsetMapping_Scale; // bias and scale\n"
+" TexCoordOffset += height * vec2(eyedir.x, -1.0 * eyedir.y);\n"
"#endif\n"
"#endif\n"
"\n"
" // combine the diffuse textures (base, pants, shirt)\n"
-" vec4 color = vec4(texture2D(Texture_Color, TexCoord));\n"
+" myhvec4 color = myhvec4(texture2D(Texture_Color, TexCoord));\n"
"#ifdef USECOLORMAPPING\n"
-" color.rgb += vec3(texture2D(Texture_Pants, TexCoord)) * Color_Pants + vec3(texture2D(Texture_Shirt, TexCoord)) * Color_Shirt;\n"
+" color.rgb += myhvec3(texture2D(Texture_Pants, TexCoord)) * Color_Pants + myhvec3(texture2D(Texture_Shirt, TexCoord)) * Color_Shirt;\n"
"#endif\n"
"\n"
"\n"
" // light source\n"
"\n"
" // get the surface normal and light normal\n"
-" vec3 surfacenormal = normalize(vec3(texture2D(Texture_Normal, TexCoord)) - 0.5);\n"
-" vec3 diffusenormal = vec3(normalize(LightVector));\n"
+" myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
+" myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
"\n"
" // calculate directional shading\n"
-" color.rgb *= (AmbientScale + DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
+" color.rgb *= AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
"#ifdef USESPECULAR\n"
-" vec3 specularnormal = vec3(normalize(diffusenormal + vec3(normalize(EyeVector))));\n"
-" color.rgb += vec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower);\n"
+" myhvec3 specularnormal = normalize(diffusenormal + myhvec3(normalize(EyeVector)));\n"
+" color.rgb += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
"#endif\n"
"\n"
"#ifdef USECUBEFILTER\n"
" // apply light cubemap filter\n"
" //color.rgb *= normalize(CubeVector) * 0.5 + 0.5;//vec3(textureCube(Texture_Cube, CubeVector));\n"
-" color.rgb *= vec3(textureCube(Texture_Cube, CubeVector));\n"
+" color.rgb *= myhvec3(textureCube(Texture_Cube, CubeVector));\n"
"#endif\n"
"\n"
" // apply light color\n"
" //\n"
" // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
" // provide significant illumination, large = slow = pain.\n"
-" color.rgb *= max(1.0 - dot(CubeVector, CubeVector), 0.0);\n"
+" color.rgb *= myhalf(max(1.0 - dot(CubeVector, CubeVector), 0.0));\n"
"\n"
"\n"
"\n"
" // directional model lighting\n"
"\n"
" // get the surface normal and light normal\n"
-" vec3 surfacenormal = normalize(vec3(texture2D(Texture_Normal, TexCoord)) - 0.5);\n"
-" vec3 diffusenormal = vec3(normalize(LightVector));\n"
+" myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
+" myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
"\n"
" // calculate directional shading\n"
-" color.rgb *= AmbientColor + DiffuseColor * max(dot(surfacenormal, diffusenormal), 0.0);\n"
+" color.rgb *= AmbientColor + DiffuseColor * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
"#ifdef USESPECULAR\n"
-" vec3 specularnormal = vec3(normalize(diffusenormal + vec3(normalize(EyeVector))));\n"
-" color.rgb += vec3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower);\n"
+" myhvec3 specularnormal = normalize(diffusenormal + myhvec3(normalize(EyeVector)));\n"
+" color.rgb += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
"#endif\n"
"\n"
"\n"
"\n"
"\n"
-"#elif defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE)\n"
+"#elif defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
" // deluxemap lightmapping using light vectors in modelspace (evil q3map2)\n"
"\n"
" // get the surface normal and light normal\n"
-" vec3 surfacenormal = normalize(vec3(texture2D(Texture_Normal, TexCoord)) - 0.5);\n"
-" vec3 diffusenormal_modelspace = vec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - 0.5;\n"
-" vec3 diffusenormal = normalize(vec3(dot(diffusenormal_modelspace, VectorS), dot(diffusenormal_modelspace, VectorT), dot(diffusenormal_modelspace, VectorR)));\n"
+" myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
"\n"
-" // calculate directional shading\n"
-" vec3 tempcolor = color.rgb * (DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
-"#ifdef USESPECULAR\n"
-" vec3 specularnormal = vec3(normalize(diffusenormal + vec3(normalize(EyeVector))));\n"
-" tempcolor += vec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower);\n"
+"#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
+" myhvec3 diffusenormal_modelspace = myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhvec3(0.5);\n"
+" myhvec3 diffusenormal = normalize(myhvec3(dot(diffusenormal_modelspace, myhvec3(VectorS)), dot(diffusenormal_modelspace, myhvec3(VectorT)), dot(diffusenormal_modelspace, myhvec3(VectorR))));\n"
+"#else\n"
+" myhvec3 diffusenormal = normalize(myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhvec3(0.5));\n"
"#endif\n"
-"\n"
-" // apply lightmap color\n"
-" color.rgb = tempcolor * vec3(texture2D(Texture_Lightmap, TexCoordLightmap)) + color.rgb * vec3(AmbientScale);\n"
-"\n"
-"\n"
-"\n"
-"\n"
-"#elif defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
-" // deluxemap lightmapping using light vectors in tangentspace\n"
-"\n"
-" // get the surface normal and light normal\n"
-" vec3 surfacenormal = normalize(vec3(texture2D(Texture_Normal, TexCoord)) - 0.5);\n"
-" vec3 diffusenormal = normalize(vec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - 0.5);\n"
-"\n"
" // calculate directional shading\n"
-" vec3 tempcolor = color.rgb * (DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
+" myhvec3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0)));\n"
"#ifdef USESPECULAR\n"
-" vec3 specularnormal = vec3(normalize(diffusenormal + vec3(normalize(EyeVector))));\n"
-" tempcolor += vec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower);\n"
+" myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
+" tempcolor += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
"#endif\n"
"\n"
" // apply lightmap color\n"
-" color.rgb = tempcolor * vec3(texture2D(Texture_Lightmap, TexCoordLightmap)) + color.rgb * vec3(AmbientScale);\n"
-"\n"
-"\n"
+" color.rgb = tempcolor * myhvec3(texture2D(Texture_Lightmap, TexCoordLightmap)) + color.rgb * AmbientScale;\n"
"\n"
"\n"
"#else // MODE none (lightmap)\n"
" // apply lightmap color\n"
-" color.rgb *= vec3(texture2D(Texture_Lightmap, TexCoordLightmap)) * DiffuseScale + vec3(AmbientScale);\n"
+" color.rgb *= myhvec3(texture2D(Texture_Lightmap, TexCoordLightmap)) * DiffuseScale + myhvec3(AmbientScale);\n"
"#endif // MODE\n"
"\n"
-" color *= gl_Color;\n"
+" color *= myhvec4(gl_Color);\n"
"\n"
"#ifdef USEGLOW\n"
-" color.rgb += vec3(texture2D(Texture_Glow, TexCoord));\n"
+" color.rgb += myhvec3(texture2D(Texture_Glow, TexCoord)) * GlowScale;\n"
"#endif\n"
"\n"
"#ifdef USEFOG\n"
" // apply fog\n"
-" float fog = texture2D(Texture_FogMask, vec2(length(EyeVectorModelSpace)*FogRangeRecip, 0.0)).x;\n"
+" myhalf fog = myhalf(texture2D(Texture_FogMask, myhvec2(length(EyeVectorModelSpace)*FogRangeRecip, 0.0)).x);\n"
" color.rgb = color.rgb * fog + FogColor * (1.0 - fog);\n"
"#endif\n"
"\n"
-" gl_FragColor = color;\n"
+" color.rgb *= SceneBrightness;\n"
+"\n"
+" gl_FragColor = vec4(color);\n"
"}\n"
"\n"
"#endif // FRAGMENT_SHADER\n"
;
+// NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
+const char *permutationinfo[][2] =
+{
+ {"#define MODE_LIGHTSOURCE\n", " lightsource"},
+ {"#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
+ {"#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
+ {"#define MODE_LIGHTDIRECTION\n", " lightdirection"},
+ {"#define USEGLOW\n", " glow"},
+ {"#define USEFOG\n", " fog"},
+ {"#define USECOLORMAPPING\n", " colormapping"},
+ {"#define USESPECULAR\n", " specular"},
+ {"#define USECUBEFILTER\n", " cubefilter"},
+ {"#define USEOFFSETMAPPING\n", " offsetmapping"},
+ {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
+ {NULL, NULL}
+};
+
void R_GLSL_CompilePermutation(int permutation)
{
+ int i;
r_glsl_permutation_t *p = r_glsl_permutations + permutation;
int vertstrings_count;
int fragstrings_count;
vertstrings_count = 1;
fragstrings_count = 1;
permutationname[0] = 0;
- if (permutation & SHADERPERMUTATION_MODE_LIGHTSOURCE)
- {
- vertstrings_list[vertstrings_count++] = "#define MODE_LIGHTSOURCE\n";
- fragstrings_list[fragstrings_count++] = "#define MODE_LIGHTSOURCE\n";
- strlcat(permutationname, " lightsource", sizeof(permutationname));
- }
- if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE)
- {
- vertstrings_list[vertstrings_count++] = "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n";
- fragstrings_list[fragstrings_count++] = "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n";
- strlcat(permutationname, " lightdirectionmap_modelspace", sizeof(permutationname));
- }
- if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)
- {
- vertstrings_list[vertstrings_count++] = "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n";
- fragstrings_list[fragstrings_count++] = "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n";
- strlcat(permutationname, " lightdirectionmap_tangentspace", sizeof(permutationname));
- }
- if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTION)
- {
- vertstrings_list[vertstrings_count++] = "#define MODE_LIGHTDIRECTION\n";
- fragstrings_list[fragstrings_count++] = "#define MODE_LIGHTDIRECTION\n";
- strlcat(permutationname, " lightdirection", sizeof(permutationname));
- }
- if (permutation & SHADERPERMUTATION_GLOW)
- {
- vertstrings_list[vertstrings_count++] = "#define USEGLOW\n";
- fragstrings_list[fragstrings_count++] = "#define USEGLOW\n";
- strlcat(permutationname, " glow", sizeof(permutationname));
- }
- if (permutation & SHADERPERMUTATION_COLORMAPPING)
- {
- vertstrings_list[vertstrings_count++] = "#define USECOLORMAPPING\n";
- fragstrings_list[fragstrings_count++] = "#define USECOLORMAPPING\n";
- strlcat(permutationname, " colormapping", sizeof(permutationname));
- }
- if (permutation & SHADERPERMUTATION_SPECULAR)
+ for (i = 0;permutationinfo[i][0];i++)
{
- vertstrings_list[vertstrings_count++] = "#define USESPECULAR\n";
- fragstrings_list[fragstrings_count++] = "#define USESPECULAR\n";
- strlcat(permutationname, " specular", sizeof(permutationname));
- }
- if (permutation & SHADERPERMUTATION_FOG)
- {
- vertstrings_list[vertstrings_count++] = "#define USEFOG\n";
- fragstrings_list[fragstrings_count++] = "#define USEFOG\n";
- strlcat(permutationname, " fog", sizeof(permutationname));
- }
- if (permutation & SHADERPERMUTATION_CUBEFILTER)
- {
- vertstrings_list[vertstrings_count++] = "#define USECUBEFILTER\n";
- fragstrings_list[fragstrings_count++] = "#define USECUBEFILTER\n";
- strlcat(permutationname, " cubefilter", sizeof(permutationname));
- }
- if (permutation & SHADERPERMUTATION_OFFSETMAPPING)
- {
- vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING\n";
- fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING\n";
- strlcat(permutationname, " offsetmapping", sizeof(permutationname));
- }
- if (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING)
- {
- vertstrings_list[vertstrings_count++] = "#define USEOFFSETMAPPING_RELIEFMAPPING\n";
- fragstrings_list[fragstrings_count++] = "#define USEOFFSETMAPPING_RELIEFMAPPING\n";
- strlcat(permutationname, " OFFSETMAPPING_RELIEFMAPPING", sizeof(permutationname));
+ if (permutation & (1<<i))
+ {
+ vertstrings_list[vertstrings_count++] = permutationinfo[i][0];
+ fragstrings_list[fragstrings_count++] = permutationinfo[i][0];
+ strlcat(permutationname, permutationinfo[i][1], sizeof(permutationname));
+ }
+ else
+ {
+ // keep line numbers correct
+ vertstrings_list[vertstrings_count++] = "\n";
+ fragstrings_list[fragstrings_count++] = "\n";
+ }
}
shaderstring = (char *)FS_LoadFile("glsl/default.glsl", r_main_mempool, false, NULL);
if (shaderstring)
p->loc_DiffuseScale = qglGetUniformLocationARB(p->program, "DiffuseScale");
p->loc_SpecularPower = qglGetUniformLocationARB(p->program, "SpecularPower");
p->loc_SpecularScale = qglGetUniformLocationARB(p->program, "SpecularScale");
+ p->loc_GlowScale = qglGetUniformLocationARB(p->program, "GlowScale");
+ p->loc_SceneBrightness = qglGetUniformLocationARB(p->program, "SceneBrightness");
p->loc_OffsetMapping_Scale = qglGetUniformLocationARB(p->program, "OffsetMapping_Scale");
p->loc_AmbientColor = qglGetUniformLocationARB(p->program, "AmbientColor");
p->loc_DiffuseColor = qglGetUniformLocationARB(p->program, "DiffuseColor");
{
if (modellighting)
permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTION;
- else
+ else if (r_glsl_deluxemapping.integer >= 1 && rsurface_lightmaptexture)
{
- if (r_glsl_deluxemapping.integer >= 1 && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping && rsurface_lightmaptexture)
+ if (r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping)
{
if (r_refdef.worldmodel->brushq3.deluxemapping_modelspace)
permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE;
//if (r_glsl_permutation->loc_Texture_Lightmap >= 0) R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
//if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
if (r_glsl_permutation->loc_Texture_Glow >= 0) R_Mesh_TexBind(9, R_GetTexture(rsurface_texture->skin.glow));
+ if (r_glsl_permutation->loc_GlowScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_GlowScale, r_hdr_glowintensity.value);
+ if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_view.colorscale);
if (r_glsl_permutation->loc_FogColor >= 0)
{
// additive passes are only darkened by fog, not tinted
Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
Cvar_RegisterVariable(&r_showdisabledepthtest);
+ Cvar_RegisterVariable(&r_drawportals);
Cvar_RegisterVariable(&r_drawentities);
Cvar_RegisterVariable(&r_drawviewmodel);
Cvar_RegisterVariable(&r_speeds);
Cvar_RegisterVariable(&r_bloom_blur);
Cvar_RegisterVariable(&r_bloom_resolution);
Cvar_RegisterVariable(&r_bloom_power);
+ Cvar_RegisterVariable(&r_hdr);
+ Cvar_RegisterVariable(&r_hdr_scenebrightness);
+ Cvar_RegisterVariable(&r_hdr_bloomintensity);
+ Cvar_RegisterVariable(&r_hdr_glowintensity);
Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
Cvar_RegisterVariable(&developer_texturelogging);
Cvar_RegisterVariable(&gl_lightmaps);
extern void R_Shadow_Init(void);
extern void R_Sky_Init(void);
extern void GL_Surf_Init(void);
-extern void R_Crosshairs_Init(void);
extern void R_Light_Init(void);
extern void R_Particles_Init(void);
extern void R_Explosion_Init(void);
R_Shadow_Init();
R_Sky_Init();
GL_Surf_Init();
- R_Crosshairs_Init();
+ Sbar_Init();
R_Light_Init();
R_Particles_Init();
R_Explosion_Init();
- Sbar_Init();
R_LightningBeams_Init();
Mod_RenderInit();
}
void R_View_Update(void)
{
+ R_View_SetFrustum();
+ R_View_WorldVisibility();
+ R_View_UpdateEntityVisible();
+}
+
+void R_ResetViewRendering(void)
+{
+ if (gl_support_fragment_shader)
+ {
+ qglUseProgramObjectARB(0);CHECKGLERROR
+ }
+
// GL is weird because it's bottom to top, r_view.y is top to bottom
qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
+ GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
- R_View_SetFrustum();
- R_View_WorldVisibility();
- R_View_UpdateEntityVisible();
+ GL_ScissorTest(true);
+ GL_DepthMask(true);
+ GL_DepthTest(true);
+ R_Mesh_Matrix(&identitymatrix);
+ R_Mesh_ResetTextureState();
}
-static void R_BlendView(void)
+void R_RenderScene(void);
+
+void R_Bloom_MakeTexture(qboolean darken)
{
int screenwidth, screenheight;
- qboolean dobloom;
- qboolean doblend;
+ int screentexturewidth, screentextureheight;
+ int bloomtexturewidth, bloomtextureheight;
+ int bloomwidth, bloomheight, x, range;
+ float xoffset, yoffset, r;
float vertex3f[12];
float texcoord2f[3][8];
+ // set bloomwidth and bloomheight to the bloom resolution that will be
+ // used (often less than the screen resolution for faster rendering)
+ bloomwidth = bound(1, r_bloom_resolution.integer, r_view.width);
+ bloomheight = bound(1, bloomwidth * r_view.height / r_view.width, r_view.height);
+
// set the (poorly named) screenwidth and screenheight variables to
// a power of 2 at least as large as the screen, these will define the
// size of the texture to allocate
for (screenwidth = 1;screenwidth < vid.width;screenwidth *= 2);
for (screenheight = 1;screenheight < vid.height;screenheight *= 2);
- doblend = r_refdef.viewblend[3] >= 0.01f;
- dobloom = r_bloom.integer && screenwidth <= gl_max_texture_size && screenheight <= gl_max_texture_size && r_bloom_resolution.value >= 32 && r_bloom_power.integer >= 1 && r_bloom_power.integer < 100 && r_bloom_blur.value >= 0 && r_bloom_blur.value < 512;
+ r_refdef.stats.bloom++;
- if (!dobloom && !doblend)
- return;
+ // allocate textures as needed
+ // TODO: reallocate these when size settings change
+ if (!r_bloom_texture_screen)
+ r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+ if (!r_bloom_texture_bloom)
+ r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+
+ screentexturewidth = R_TextureWidth(r_bloom_texture_screen);
+ screentextureheight = R_TextureHeight(r_bloom_texture_screen);
+ bloomtexturewidth = R_TextureWidth(r_bloom_texture_bloom);
+ bloomtextureheight = R_TextureHeight(r_bloom_texture_bloom);
- GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
- GL_DepthMask(true);
- GL_DepthTest(false);
- R_Mesh_Matrix(&identitymatrix);
// vertex coordinates for a quad that covers the screen exactly
vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
+
+ // set up a texcoord array for the full resolution screen image
+ // (we have to keep this around to copy back during final render)
+ texcoord2f[0][0] = 0;
+ texcoord2f[0][1] = (float)r_view.height / (float)screentextureheight;
+ texcoord2f[0][2] = (float)r_view.width / (float)screentexturewidth;
+ texcoord2f[0][3] = (float)r_view.height / (float)screentextureheight;
+ texcoord2f[0][4] = (float)r_view.width / (float)screentexturewidth;
+ texcoord2f[0][5] = 0;
+ texcoord2f[0][6] = 0;
+ texcoord2f[0][7] = 0;
+
+ // set up a texcoord array for the reduced resolution bloom image
+ // (which will be additive blended over the screen image)
+ texcoord2f[1][0] = 0;
+ texcoord2f[1][1] = (float)bloomheight / (float)bloomtextureheight;
+ texcoord2f[1][2] = (float)bloomwidth / (float)bloomtexturewidth;
+ texcoord2f[1][3] = (float)bloomheight / (float)bloomtextureheight;
+ texcoord2f[1][4] = (float)bloomwidth / (float)bloomtexturewidth;
+ texcoord2f[1][5] = 0;
+ texcoord2f[1][6] = 0;
+ texcoord2f[1][7] = 0;
+
+ R_ResetViewRendering();
+ GL_DepthTest(false);
R_Mesh_VertexPointer(vertex3f);
R_Mesh_ColorPointer(NULL);
- R_Mesh_ResetTextureState();
- if (dobloom)
+
+ R_Mesh_TexCoordPointer(0, 2, texcoord2f[0]);
+ R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_screen));
+
+ // copy view into the screen texture
+ GL_ActiveTexture(0);
+ CHECKGLERROR
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
+ r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
+
+ // now scale it down to the bloom texture size
+ CHECKGLERROR
+ qglViewport(r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ GL_Color(1, 1, 1, 1);
+ // TODO: optimize with multitexture or GLSL
+ R_Mesh_Draw(0, 4, 2, polygonelements);
+ r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
+
+ if (darken)
{
- int bloomwidth, bloomheight, x, range;
- float xoffset, yoffset, r;
- r_refdef.stats.bloom++;
- // allocate textures as needed
- if (!r_bloom_texture_screen)
- r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
- if (!r_bloom_texture_bloom)
- r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
- // set bloomwidth and bloomheight to the bloom resolution that will be
- // used (often less than the screen resolution for faster rendering)
- bloomwidth = min(r_view.width, r_bloom_resolution.integer);
- bloomheight = min(r_view.height, bloomwidth * r_view.height / r_view.width);
- // set up a texcoord array for the full resolution screen image
- // (we have to keep this around to copy back during final render)
- texcoord2f[0][0] = 0;
- texcoord2f[0][1] = (float)r_view.height / (float)screenheight;
- texcoord2f[0][2] = (float)r_view.width / (float)screenwidth;
- texcoord2f[0][3] = (float)r_view.height / (float)screenheight;
- texcoord2f[0][4] = (float)r_view.width / (float)screenwidth;
- texcoord2f[0][5] = 0;
- texcoord2f[0][6] = 0;
- texcoord2f[0][7] = 0;
- // set up a texcoord array for the reduced resolution bloom image
- // (which will be additive blended over the screen image)
- texcoord2f[1][0] = 0;
- texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
- texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
- texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
- texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
- texcoord2f[1][5] = 0;
- texcoord2f[1][6] = 0;
- texcoord2f[1][7] = 0;
- R_Mesh_TexCoordPointer(0, 2, texcoord2f[0]);
- R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_screen));
- // copy view into the full resolution screen image texture
- GL_ActiveTexture(0);
- CHECKGLERROR
- qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
- r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
- // now scale it down to the bloom size and raise to a power of itself
- // to darken it (this leaves the really bright stuff bright, and
- // everything else becomes very dark)
- // TODO: optimize with multitexture or GLSL
- CHECKGLERROR
- qglViewport(r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
- GL_BlendFunc(GL_ONE, GL_ZERO);
- GL_Color(1, 1, 1, 1);
- R_Mesh_Draw(0, 4, 2, polygonelements);
- r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
+ // raise to a power of itself to darken it (this leaves the really
+ // bright stuff bright, and everything else becomes very dark)
// render multiple times with a multiply blendfunc to raise to a power
GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
for (x = 1;x < r_bloom_power.integer;x++)
R_Mesh_Draw(0, 4, 2, polygonelements);
r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
}
- // we now have a darkened bloom image in the framebuffer, copy it into
- // the bloom image texture for more processing
+ }
+
+ // we now have a darkened bloom image in the framebuffer
+ // copy it into the bloom image texture for more processing
+ R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_bloom));
+ R_Mesh_TexCoordPointer(0, 2, texcoord2f[2]);
+ GL_ActiveTexture(0);
+ CHECKGLERROR
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
+ r_refdef.stats.bloom_copypixels += bloomwidth * bloomheight;
+
+ // blend on at multiple vertical offsets to achieve a vertical blur
+ // TODO: do offset blends using GLSL
+ range = r_bloom_blur.integer * bloomwidth / 320;
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ for (x = -range;x <= range;x++)
+ {
+ xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
+ yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
+ // compute a texcoord array with the specified x and y offset
+ texcoord2f[2][0] = xoffset+0;
+ texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
+ texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
+ texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
+ texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
+ texcoord2f[2][5] = yoffset+0;
+ texcoord2f[2][6] = xoffset+0;
+ texcoord2f[2][7] = yoffset+0;
+ // this r value looks like a 'dot' particle, fading sharply to
+ // black at the edges
+ // (probably not realistic but looks good enough)
+ r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
+ if (r < 0.01f)
+ continue;
+ GL_Color(r, r, r, 1);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
+ r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
+ GL_BlendFunc(GL_ONE, GL_ONE);
+ }
+
+ // copy the vertically blurred bloom view to a texture
+ GL_ActiveTexture(0);
+ CHECKGLERROR
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
+ r_refdef.stats.bloom_copypixels += bloomwidth * bloomheight;
+
+ // blend the vertically blurred image at multiple offsets horizontally
+ // to finish the blur effect
+ // TODO: do offset blends using GLSL
+ range = r_bloom_blur.integer * bloomwidth / 320;
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ for (x = -range;x <= range;x++)
+ {
+ xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
+ yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
+ // compute a texcoord array with the specified x and y offset
+ texcoord2f[2][0] = xoffset+0;
+ texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
+ texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
+ texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
+ texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
+ texcoord2f[2][5] = yoffset+0;
+ texcoord2f[2][6] = xoffset+0;
+ texcoord2f[2][7] = yoffset+0;
+ // this r value looks like a 'dot' particle, fading sharply to
+ // black at the edges
+ // (probably not realistic but looks good enough)
+ r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
+ if (r < 0.01f)
+ continue;
+ GL_Color(r, r, r, 1);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
+ r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
+ GL_BlendFunc(GL_ONE, GL_ONE);
+ }
+
+ // copy the blurred bloom view to a texture
+ GL_ActiveTexture(0);
+ CHECKGLERROR
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
+ r_refdef.stats.bloom_copypixels += bloomwidth * bloomheight;
+}
+
+void R_HDR_RenderBloomTexture(void)
+{
+ int oldwidth, oldheight;
+
+ oldwidth = r_view.width;
+ oldheight = r_view.height;
+ r_view.width = bound(1, r_bloom_resolution.integer, min(r_view.width, gl_max_texture_size));
+ r_view.height = r_view.width * oldheight / oldwidth;
+
+ // TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer? it might improve SLI performance.
+ // FIXME: change global lightmapintensity and light intensity according to r_hdr_bloomintensity cvar
+ // FIXME: change global lightmapintensity and light intensity according to r_hdr_scenebrightness cvar
+ // TODO: add exposure compensation features
+
+ r_view.colorscale = r_hdr_bloomintensity.value * r_hdr_scenebrightness.value;
+ R_RenderScene();
+
+ R_ResetViewRendering();
+
+ R_Bloom_MakeTexture(false);
+
+ R_ClearScreen();
+ if (r_timereport_active)
+ R_TimeReport("clear");
+
+ // restore the view settings
+ r_view.width = oldwidth;
+ r_view.height = oldheight;
+
+ // go back to full view area
+ R_ResetViewRendering();
+}
+
+static void R_BlendView(void)
+{
+ int screenwidth, screenheight;
+ int bloomwidth, bloomheight;
+ qboolean dobloom;
+ qboolean dohdr;
+ qboolean doblend;
+ float vertex3f[12];
+ float texcoord2f[3][8];
+
+ // set the (poorly named) screenwidth and screenheight variables to
+ // a power of 2 at least as large as the screen, these will define the
+ // size of the texture to allocate
+ for (screenwidth = 1;screenwidth < vid.width;screenwidth *= 2);
+ for (screenheight = 1;screenheight < vid.height;screenheight *= 2);
+
+ doblend = r_refdef.viewblend[3] >= 0.01f;
+ dobloom = !r_hdr.integer && r_bloom.integer && screenwidth <= gl_max_texture_size && screenheight <= gl_max_texture_size && r_bloom_resolution.value >= 32 && r_bloom_power.integer >= 1 && r_bloom_power.integer < 100 && r_bloom_blur.value >= 0 && r_bloom_blur.value < 512;
+ dohdr = r_hdr.integer && screenwidth <= gl_max_texture_size && screenheight <= gl_max_texture_size && r_bloom_resolution.value >= 32 && r_bloom_power.integer >= 1 && r_bloom_power.integer < 100 && r_bloom_blur.value >= 0 && r_bloom_blur.value < 512;
+
+ if (!dobloom && !dohdr && !doblend)
+ return;
+
+ // vertex coordinates for a quad that covers the screen exactly
+ vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
+ vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
+ vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
+ vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
+
+ // set bloomwidth and bloomheight to the bloom resolution that will be
+ // used (often less than the screen resolution for faster rendering)
+ bloomwidth = min(r_view.width, r_bloom_resolution.integer);
+ bloomheight = min(r_view.height, bloomwidth * r_view.height / r_view.width);
+ // set up a texcoord array for the full resolution screen image
+ // (we have to keep this around to copy back during final render)
+ texcoord2f[0][0] = 0;
+ texcoord2f[0][1] = (float)r_view.height / (float)screenheight;
+ texcoord2f[0][2] = (float)r_view.width / (float)screenwidth;
+ texcoord2f[0][3] = (float)r_view.height / (float)screenheight;
+ texcoord2f[0][4] = (float)r_view.width / (float)screenwidth;
+ texcoord2f[0][5] = 0;
+ texcoord2f[0][6] = 0;
+ texcoord2f[0][7] = 0;
+ // set up a texcoord array for the reduced resolution bloom image
+ // (which will be additive blended over the screen image)
+ texcoord2f[1][0] = 0;
+ texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
+ texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
+ texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
+ texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
+ texcoord2f[1][5] = 0;
+ texcoord2f[1][6] = 0;
+ texcoord2f[1][7] = 0;
+
+ if (dohdr)
+ {
+ // render high dynamic range bloom effect
+ // the bloom texture was made earlier this render, so we just need to
+ // blend it onto the screen...
+ R_ResetViewRendering();
+ GL_DepthTest(false);
+ R_Mesh_VertexPointer(vertex3f);
+ R_Mesh_ColorPointer(NULL);
+ GL_Color(1, 1, 1, 1);
+ GL_BlendFunc(GL_ONE, GL_ONE);
R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_bloom));
- R_Mesh_TexCoordPointer(0, 2, texcoord2f[2]);
- GL_ActiveTexture(0);
- CHECKGLERROR
- qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
- r_refdef.stats.bloom_copypixels += bloomwidth * bloomheight;
- // blend on at multiple vertical offsets to achieve a vertical blur
- // TODO: do offset blends using GLSL
- range = r_bloom_blur.integer * bloomwidth / 320;
- GL_BlendFunc(GL_ONE, GL_ZERO);
- for (x = -range;x <= range;x++)
- {
- xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
- yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
- // compute a texcoord array with the specified x and y offset
- texcoord2f[2][0] = xoffset+0;
- texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
- texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
- texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
- texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
- texcoord2f[2][5] = yoffset+0;
- texcoord2f[2][6] = xoffset+0;
- texcoord2f[2][7] = yoffset+0;
- // this r value looks like a 'dot' particle, fading sharply to
- // black at the edges
- // (probably not realistic but looks good enough)
- r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
- if (r < 0.01f)
- continue;
- GL_Color(r, r, r, 1);
- R_Mesh_Draw(0, 4, 2, polygonelements);
- r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
- GL_BlendFunc(GL_ONE, GL_ONE);
- }
- // copy the vertically blurred bloom view to a texture
- GL_ActiveTexture(0);
- CHECKGLERROR
- qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
- r_refdef.stats.bloom_copypixels += bloomwidth * bloomheight;
- // blend the vertically blurred image at multiple offsets horizontally
- // to finish the blur effect
- // TODO: do offset blends using GLSL
- range = r_bloom_blur.integer * bloomwidth / 320;
- GL_BlendFunc(GL_ONE, GL_ZERO);
- for (x = -range;x <= range;x++)
- {
- xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
- yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
- // compute a texcoord array with the specified x and y offset
- texcoord2f[2][0] = xoffset+0;
- texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
- texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
- texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
- texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
- texcoord2f[2][5] = yoffset+0;
- texcoord2f[2][6] = xoffset+0;
- texcoord2f[2][7] = yoffset+0;
- // this r value looks like a 'dot' particle, fading sharply to
- // black at the edges
- // (probably not realistic but looks good enough)
- r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
- if (r < 0.01f)
- continue;
- GL_Color(r, r, r, 1);
- R_Mesh_Draw(0, 4, 2, polygonelements);
- r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
- GL_BlendFunc(GL_ONE, GL_ONE);
- }
- // copy the blurred bloom view to a texture
- GL_ActiveTexture(0);
- CHECKGLERROR
- qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
- r_refdef.stats.bloom_copypixels += bloomwidth * bloomheight;
- // go back to full view area
- qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
+ R_Mesh_TexCoordPointer(0, 2, texcoord2f[1]);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
+ r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
+ }
+ if (dobloom)
+ {
+ // render simple bloom effect
+ // make the bloom texture
+ R_Bloom_MakeTexture(true);
// put the original screen image back in place and blend the bloom
// texture on it
- GL_Color(1,1,1,1);
+ R_ResetViewRendering();
+ GL_DepthTest(false);
+ R_Mesh_VertexPointer(vertex3f);
+ R_Mesh_ColorPointer(NULL);
+ GL_Color(1, 1, 1, 1);
GL_BlendFunc(GL_ONE, GL_ZERO);
// do both in one pass if possible
R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_screen));
if (doblend)
{
// apply a color tint to the whole view
- R_Mesh_ResetTextureState();
+ R_ResetViewRendering();
+ GL_DepthTest(false);
+ R_Mesh_VertexPointer(vertex3f);
+ R_Mesh_ColorPointer(NULL);
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
R_Mesh_Draw(0, 4, 2, polygonelements);
return; //Host_Error ("R_RenderView: NULL worldmodel");
CHECKGLERROR
- GL_ScissorTest(true);
- GL_DepthMask(true);
if (r_timereport_active)
R_TimeReport("setup");
if (r_timereport_active)
R_TimeReport("visibility");
+ // GL is weird because it's bottom to top, r_view.y is top to bottom
+ R_ResetViewRendering();
+
R_ClearScreen();
if (r_timereport_active)
R_TimeReport("clear");
+ // this produces a bloom texture to be used in R_BlendView() later
+ if (r_hdr.integer)
+ R_HDR_RenderBloomTexture();
+
+ r_view.colorscale = r_hdr_scenebrightness.value;
R_RenderScene();
R_BlendView();
if (r_timereport_active)
R_TimeReport("visibility");
+ R_ResetViewRendering();
+
R_ClearScreen();
if (r_timereport_active)
R_TimeReport("clear");
//[515]: csqc
void CSQC_R_RenderScene (void)
{
+ R_ResetViewRendering();
+
+ R_ClearScreen();
+ if (r_timereport_active)
+ R_TimeReport("clear");
+
+ // this produces a bloom texture to be used in R_BlendView() later
+ if (r_hdr.integer)
+ R_HDR_RenderBloomTexture();
+
+ r_view.colorscale = r_hdr_scenebrightness.value;
R_RenderScene();
R_BlendView();
extern void R_DrawLightningBeams (void);
extern void VM_AddPolygonsToMeshQueue (void);
+extern void R_DrawPortals (void);
void R_RenderScene(void)
{
// don't let sound skip if going slow
qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
+ R_ResetViewRendering();
+
R_MeshQueue_BeginScene();
if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows)
}
VM_AddPolygonsToMeshQueue();
+ if (r_drawportals.integer)
+ {
+ R_DrawPortals();
+ if (r_timereport_active)
+ R_TimeReport("portals");
+ }
+
if (gl_support_fragment_shader)
{
qglUseProgramObjectARB(0);CHECKGLERROR
if (r_timereport_active)
R_TimeReport("coronas");
}
- if(cl.csqc_vidvars.drawcrosshair)
- {
- R_DrawWorldCrosshair();
- if (r_timereport_active)
- R_TimeReport("crosshair");
- }
// don't let sound skip if going slow
if (r_refdef.extraupdate)
R_Mesh_ResetTextureState();
R_Mesh_TexBind(0, R_GetTexture(texture));
R_Mesh_TexCoordPointer(0, 2, spritetexcoord2f);
- GL_Color(cr * ifog, cg * ifog, cb * ifog, ca);
+ // FIXME: fixed function path can't properly handle r_view.colorscale > 1
+ GL_Color(cr * ifog * r_view.colorscale, cg * ifog * r_view.colorscale, cb * ifog * r_view.colorscale, ca);
R_Mesh_Draw(0, 4, 2, polygonelements);
if (blendfunc2 == GL_ONE_MINUS_SRC_ALPHA)
{
R_Mesh_TexBind(0, R_GetTexture(fogtexture));
GL_BlendFunc(blendfunc1, GL_ONE);
- GL_Color(r_refdef.fogcolor[0] * fog, r_refdef.fogcolor[1] * fog, r_refdef.fogcolor[2] * fog, ca);
+ GL_Color(r_refdef.fogcolor[0] * fog * r_view.colorscale, r_refdef.fogcolor[1] * fog * r_view.colorscale, r_refdef.fogcolor[2] * fog * r_view.colorscale, ca);
R_Mesh_Draw(0, 4, 2, polygonelements);
}
}
int i;
R_Mesh_VertexPointer(brush->points->v);
i = (int)(((size_t)brush) / sizeof(colbrushf_t));
- GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f);
+ GL_Color((i & 31) * (1.0f / 32.0f) * r_view.colorscale, ((i >> 5) & 31) * (1.0f / 32.0f) * r_view.colorscale, ((i >> 10) & 31) * (1.0f / 32.0f) * r_view.colorscale, 0.2f);
GL_LockArrays(0, brush->numpoints);
R_Mesh_Draw(0, brush->numpoints, brush->numtriangles, brush->elements);
GL_LockArrays(0, 0);
return;
R_Mesh_VertexPointer(surface->data_collisionvertex3f);
i = (int)(((size_t)surface) / sizeof(msurface_t));
- GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f);
+ GL_Color((i & 31) * (1.0f / 32.0f) * r_view.colorscale, ((i >> 5) & 31) * (1.0f / 32.0f) * r_view.colorscale, ((i >> 10) & 31) * (1.0f / 32.0f) * r_view.colorscale, 0.2f);
GL_LockArrays(0, surface->num_collisionvertices);
R_Mesh_Draw(0, surface->num_collisionvertices, surface->num_collisiontriangles, surface->data_collisionelement3i);
GL_LockArrays(0, 0);
layer->blendfunc2 = blendfunc2;
layer->texture = texture;
layer->texmatrix = *matrix;
- layer->color[0] = r;
- layer->color[1] = g;
- layer->color[2] = b;
+ layer->color[0] = r * r_view.colorscale;
+ layer->color[1] = g * r_view.colorscale;
+ layer->color[2] = b * r_view.colorscale;
layer->color[3] = a;
}
if (s > 0)
t = t + s * model->num_surfaces;
if (t->animated)
- t = t->anim_frames[ent->frame != 0][(t->anim_total[ent->frame != 0] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[ent->frame != 0]) : 0];
+ {
+ // use an alternate animation if the entity's frame is not 0,
+ // and only if the texture has an alternate animation
+ if (ent->frame != 0 && t->anim_total[1])
+ t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[1]) : 0];
+ else
+ t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[0]) : 0];
+ }
texture->currentframe = t;
}
}
}
if (t->skin.glow != NULL)
- R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.glow, &t->currenttexmatrix, 1, 1, 1, t->currentalpha);
+ R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.glow, &t->currenttexmatrix, r_hdr_glowintensity.value, r_hdr_glowintensity.value, r_hdr_glowintensity.value, t->currentalpha);
if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
{
// if this is opaque use alpha blend which will darken the earlier
R_Mesh_ResizeArrays(rsurface_model->surfmesh.num_vertices);
R_Mesh_Matrix(&ent->matrix);
Matrix4x4_Transform(&ent->inversematrix, r_view.origin, rsurface_modelorg);
- if ((rsurface_entity->frameblend[0].lerp != 1 || rsurface_entity->frameblend[0].frame != 0) && (rsurface_model->surfmesh.data_morphvertex3f || rsurface_model->surfmesh.data_vertexweightindex4i))
+ if ((rsurface_entity->frameblend[0].lerp != 1 || rsurface_entity->frameblend[0].frame != 0) && rsurface_model->surfmesh.isanimated)
{
if (wanttangents)
{
for (i = 0;i < 4;i++)
Matrix4x4_Transform(&imatrix1, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, v[i]);
for (i = 0;i < 4;i++)
- VectorMAMAMAM(1, center, v[i][0], forward, v[i][1], right, v[i][2], up, rsurface_array_modelvertex3f + (surface->num_firstvertex+i+j) * 3);
+ VectorMAMAMAM(1, center, v[i][0], forward, v[i][1], right, v[i][2], up, rsurface_array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
}
Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_modelvertex3f, rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3, rsurface_array_deformednormal3f, r_smoothnormals_areaweighting.integer);
Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_modelvertex3f, rsurface_model->surfmesh.data_texcoordtexture2f, rsurface_array_deformednormal3f, rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3, rsurface_array_deformedsvector3f, rsurface_array_deformedtvector3f, r_smoothnormals_areaweighting.integer);
{
const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
int k = (int)(((size_t)surface) / sizeof(msurface_t));
- GL_Color((k & 15) * (1.0f / 16.0f), ((k >> 4) & 15) * (1.0f / 16.0f), ((k >> 8) & 15) * (1.0f / 16.0f), 0.2f);
+ GL_Color((k & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 4) & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 8) & 15) * (1.0f / 16.0f) * r_view.colorscale, 0.2f);
GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
}
// level, so don't use it then either.
if (rsurface_model->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_viewcache.world_novis)
{
- GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
+ GL_Color(r_refdef.fogcolor[0] * r_view.colorscale, r_refdef.fogcolor[1] * r_view.colorscale, r_refdef.fogcolor[2] * r_view.colorscale, 1);
R_Mesh_ColorPointer(NULL);
R_Mesh_ResetTextureState();
if (skyrendermasked)
if (r_showtris.integer)
{
if (!rsurface_texture->currentlayers->depthmask)
- GL_Color(r_showtris.value, 0, 0, 1);
+ GL_Color(r_showtris.value * r_view.colorscale, 0, 0, 1);
else if (ent == r_refdef.worldentity)
- GL_Color(r_showtris.value, r_showtris.value, r_showtris.value, 1);
+ GL_Color(r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, 1);
else
- GL_Color(0, r_showtris.value, 0, 1);
+ GL_Color(0, r_showtris.value * r_view.colorscale, 0, 1);
elements = (ent->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
CHECKGLERROR
qglBegin(GL_LINES);
}
if (r_shownormals.integer)
{
- GL_Color(r_shownormals.value, 0, 0, 1);
+ GL_Color(r_shownormals.value * r_view.colorscale, 0, 0, 1);
qglBegin(GL_LINES);
for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
{
}
qglEnd();
CHECKGLERROR
- GL_Color(0, 0, r_shownormals.value, 1);
+ GL_Color(0, 0, r_shownormals.value * r_view.colorscale, 1);
qglBegin(GL_LINES);
for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
{
}
qglEnd();
CHECKGLERROR
- GL_Color(0, r_shownormals.value, 0, 1);
+ GL_Color(0, r_shownormals.value * r_view.colorscale, 0, 1);
qglBegin(GL_LINES);
for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
{