X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=gl_rmain.c;h=b90a76a0d49e71bd94bed0241e3e5f0978719e65;hp=0cd996a46ed577e4f14b557cdaddf3d4c0d8aa3b;hb=837989dcaaf9e9382aad695c216bd07c4b8f3c66;hpb=bcb0a24c82db73c8b8203e1fd1f46ce1fb31e6a2 diff --git a/gl_rmain.c b/gl_rmain.c index 0cd996a4..b90a76a0 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -51,6 +51,8 @@ cvar_t r_fullbright = {0, "r_fullbright","0", "make everything bright cheat (not cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"}; cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"}; cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"}; +cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this)"}; +cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"}; cvar_t r_q1bsp_skymasking = {0, "r_qb1sp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"}; cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"}; @@ -74,10 +76,17 @@ cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smooth cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"}; cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"}; -cvar_t r_bloom_intensity = {CVAR_SAVE, "r_bloom_intensity", "1.5", "how bright the glow is"}; +cvar_t r_bloom_colorscale = {CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"}; +cvar_t r_bloom_brighten = {CVAR_SAVE, "r_bloom_brighten", "1", "how bright the glow is, after subtract/power"}; cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"}; 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_bloom_colorexponent = {CVAR_SAVE, "r_bloom_colorexponent", "1", "how exagerated the glow is"}; +cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0", "reduces bloom colors by a certain amount"}; + +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_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"}; +cvar_t r_hdr_range = {CVAR_SAVE, "r_hdr_range", "4", "how much dynamic range to render bloom with (equivilant to multiplying r_bloom_brighten by this value and dividing r_bloom_colorscale by this value)"}; 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"}; @@ -88,8 +97,35 @@ cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"}; // used for testing renderer code changes, otherwise does nothing cvar_t r_batchmode = {0, "r_batchmode", "1", "selects method of rendering multiple surfaces with one driver call (values are 0, 1, 2, etc...)"}; -rtexture_t *r_bloom_texture_screen; -rtexture_t *r_bloom_texture_bloom; +typedef struct r_glsl_bloomshader_s +{ + int program; + int loc_Texture_Bloom; +} +r_glsl_bloomshader_t; + +static struct r_bloomstate_s +{ + qboolean enabled; + qboolean hdr; + + int bloomwidth, bloomheight; + + int screentexturewidth, screentextureheight; + rtexture_t *texture_screen; + + int bloomtexturewidth, bloomtextureheight; + rtexture_t *texture_bloom; + + r_glsl_bloomshader_t *shader; + + // arrays for rendering the screen passes + float screentexcoord2f[8]; + float bloomtexcoord2f[8]; + float offsettexcoord2f[8]; +} +r_bloomstate; + rtexture_t *r_texture_blanknormalmap; rtexture_t *r_texture_white; rtexture_t *r_texture_black; @@ -107,6 +143,17 @@ r_glsl_permutation_t *r_glsl_permutation; // temporary variable used by a macro int fogtableindex; +// vertex coordinates for a quad that covers the screen exactly +const static float r_screenvertex3f[12] = +{ + 0, 0, 0, + 1, 0, 0, + 1, 1, 0, + 0, 1, 0 +}; + +extern void R_DrawModelShadows(void); + void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b) { int i; @@ -329,6 +376,18 @@ static const char *builtinshaderstring = "\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" @@ -423,22 +482,25 @@ static const char *builtinshaderstring = "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" @@ -453,7 +515,9 @@ static const char *builtinshaderstring = "\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" @@ -470,20 +534,54 @@ static const char *builtinshaderstring = " 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" @@ -493,20 +591,20 @@ static const char *builtinshaderstring = " // 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" @@ -520,7 +618,7 @@ static const char *builtinshaderstring = " //\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" @@ -529,183 +627,159 @@ static const char *builtinshaderstring = " // 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" ; -void R_GLSL_CompilePermutation(int permutation) +// 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(const char *filename, int permutation) { - r_glsl_permutation_t *p = r_glsl_permutations + permutation; + int i; + qboolean shaderfound; + r_glsl_permutation_t *p = r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK); int vertstrings_count; + int geomstrings_count; int fragstrings_count; char *shaderstring; const char *vertstrings_list[SHADERPERMUTATION_COUNT+1]; + const char *geomstrings_list[SHADERPERMUTATION_COUNT+1]; const char *fragstrings_list[SHADERPERMUTATION_COUNT+1]; char permutationname[256]; if (p->compiled) return; p->compiled = true; + p->program = 0; vertstrings_list[0] = "#define VERTEX_SHADER\n"; + geomstrings_list[0] = "#define GEOMETRY_SHADER\n"; fragstrings_list[0] = "#define FRAGMENT_SHADER\n"; vertstrings_count = 1; + geomstrings_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) - { - 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) + for (i = 0;permutationinfo[i][0];i++) { - 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<program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list); + shaderfound = true; + } + // clear any lists that are not needed by this shader + if (!(permutation & SHADERPERMUTATION_USES_VERTEXSHADER)) + vertstrings_count = 0; + if (!(permutation & SHADERPERMUTATION_USES_GEOMETRYSHADER)) + geomstrings_count = 0; + if (!(permutation & SHADERPERMUTATION_USES_FRAGMENTSHADER)) + fragstrings_count = 0; + // compile the shader program + if (shaderfound && vertstrings_count + geomstrings_count + fragstrings_count) + p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list); if (p->program) { CHECKGLERROR qglUseProgramObjectARB(p->program);CHECKGLERROR + // look up all the uniform variable names we care about, so we don't + // have to look them up every time we set them p->loc_Texture_Normal = qglGetUniformLocationARB(p->program, "Texture_Normal"); p->loc_Texture_Color = qglGetUniformLocationARB(p->program, "Texture_Color"); p->loc_Texture_Gloss = qglGetUniformLocationARB(p->program, "Texture_Gloss"); @@ -727,11 +801,14 @@ void R_GLSL_CompilePermutation(int permutation) 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"); p->loc_SpecularColor = qglGetUniformLocationARB(p->program, "SpecularColor"); p->loc_LightDir = qglGetUniformLocationARB(p->program, "LightDir"); + // initialize the samplers to refer to the texture units we use if (p->loc_Texture_Normal >= 0) qglUniform1iARB(p->loc_Texture_Normal, 0); if (p->loc_Texture_Color >= 0) qglUniform1iARB(p->loc_Texture_Color, 1); if (p->loc_Texture_Gloss >= 0) qglUniform1iARB(p->loc_Texture_Gloss, 2); @@ -766,55 +843,116 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting) // combination of texture, entity, light source, and fogging, only use the // minimum features necessary to avoid wasting rendering time in the // fragment shader on features that are not being used + const char *shaderfilename = NULL; int permutation = 0; float specularscale = rsurface_texture->specularscale; r_glsl_permutation = NULL; + // TODO: implement geometry-shader based shadow volumes someday if (r_shadow_rtlight) { - permutation |= SHADERPERMUTATION_MODE_LIGHTSOURCE; + // light source + shaderfilename = "glsl/default.glsl"; + permutation = SHADERPERMUTATION_MODE_LIGHTSOURCE | SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER; specularscale *= r_shadow_rtlight->specularscale; if (r_shadow_rtlight->currentcubemap != r_texture_whitecube) permutation |= SHADERPERMUTATION_CUBEFILTER; + if (specularscale > 0) + permutation |= SHADERPERMUTATION_SPECULAR; + if (r_refdef.fogenabled) + permutation |= SHADERPERMUTATION_FOG; + if (rsurface_texture->colormapping) + permutation |= SHADERPERMUTATION_COLORMAPPING; + if (r_glsl_offsetmapping.integer) + { + permutation |= SHADERPERMUTATION_OFFSETMAPPING; + if (r_glsl_offsetmapping_reliefmapping.integer) + permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING; + } } - else + else if (rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) { - if (!(rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) + // bright unshaded geometry + shaderfilename = "glsl/default.glsl"; + permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER; + if (rsurface_texture->currentskinframe->glow) + permutation |= SHADERPERMUTATION_GLOW; + if (r_refdef.fogenabled) + permutation |= SHADERPERMUTATION_FOG; + if (rsurface_texture->colormapping) + permutation |= SHADERPERMUTATION_COLORMAPPING; + if (r_glsl_offsetmapping.integer) { - if (modellighting) - permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTION; - else - { - if (r_glsl_deluxemapping.integer >= 1 && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping && rsurface_lightmaptexture) - { - if (r_refdef.worldmodel->brushq3.deluxemapping_modelspace) - permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE; - else - permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE; - } - else if (r_glsl_deluxemapping.integer >= 2) // fake mode - permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE; - } + permutation |= SHADERPERMUTATION_OFFSETMAPPING; + if (r_glsl_offsetmapping_reliefmapping.integer) + permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING; } - if (rsurface_texture->skin.glow) + } + else if (modellighting) + { + // directional model lighting + shaderfilename = "glsl/default.glsl"; + permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER; + permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTION; + if (rsurface_texture->currentskinframe->glow) permutation |= SHADERPERMUTATION_GLOW; + if (specularscale > 0) + permutation |= SHADERPERMUTATION_SPECULAR; + if (r_refdef.fogenabled) + permutation |= SHADERPERMUTATION_FOG; + if (rsurface_texture->colormapping) + permutation |= SHADERPERMUTATION_COLORMAPPING; + if (r_glsl_offsetmapping.integer) + { + permutation |= SHADERPERMUTATION_OFFSETMAPPING; + if (r_glsl_offsetmapping_reliefmapping.integer) + permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING; + } } - if (specularscale > 0) - permutation |= SHADERPERMUTATION_SPECULAR; - if (r_refdef.fogenabled) - permutation |= SHADERPERMUTATION_FOG; - if (rsurface_texture->colormapping) - permutation |= SHADERPERMUTATION_COLORMAPPING; - if (r_glsl_offsetmapping.integer) + else { - permutation |= SHADERPERMUTATION_OFFSETMAPPING; - if (r_glsl_offsetmapping_reliefmapping.integer) - permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING; + // lightmapped wall + shaderfilename = "glsl/default.glsl"; + permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER; + if (r_glsl_deluxemapping.integer >= 1 && rsurface_lightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping) + { + // deluxemapping (light direction texture) + if (rsurface_lightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping && r_refdef.worldmodel->brushq3.deluxemapping_modelspace) + permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE; + else + permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE; + if (specularscale > 0) + permutation |= SHADERPERMUTATION_SPECULAR; + } + else if (r_glsl_deluxemapping.integer >= 2) + { + // fake deluxemapping (uniform light direction in tangentspace) + permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE; + if (specularscale > 0) + permutation |= SHADERPERMUTATION_SPECULAR; + } + else + { + // ordinary lightmapping + permutation |= 0; + } + if (rsurface_texture->currentskinframe->glow) + permutation |= SHADERPERMUTATION_GLOW; + if (r_refdef.fogenabled) + permutation |= SHADERPERMUTATION_FOG; + if (rsurface_texture->colormapping) + permutation |= SHADERPERMUTATION_COLORMAPPING; + if (r_glsl_offsetmapping.integer) + { + permutation |= SHADERPERMUTATION_OFFSETMAPPING; + if (r_glsl_offsetmapping_reliefmapping.integer) + permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING; + } } - if (!r_glsl_permutations[permutation].program) + if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].program) { - if (!r_glsl_permutations[permutation].compiled) - R_GLSL_CompilePermutation(permutation); - if (!r_glsl_permutations[permutation].program) + if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].compiled) + R_GLSL_CompilePermutation(shaderfilename, permutation); + if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].program) { // remove features until we find a valid permutation int i; @@ -824,16 +962,16 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting) if (permutation < i) continue; permutation &= i; - if (!r_glsl_permutations[permutation].compiled) - R_GLSL_CompilePermutation(permutation); - if (r_glsl_permutations[permutation].program) + if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].compiled) + R_GLSL_CompilePermutation(shaderfilename, permutation); + if (r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].program) break; if (!i) return 0; // utterly failed } } } - r_glsl_permutation = r_glsl_permutations + permutation; + r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK); CHECKGLERROR qglUseProgramObjectARB(r_glsl_permutation->program);CHECKGLERROR R_Mesh_TexMatrix(0, &rsurface_texture->currenttexmatrix); @@ -863,16 +1001,18 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting) if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, r_refdef.lightmapintensity * 2.0f); if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_refdef.lightmapintensity * specularscale * 2.0f); } - if (r_glsl_permutation->loc_Texture_Normal >= 0) R_Mesh_TexBind(0, R_GetTexture(rsurface_texture->skin.nmap)); + if (r_glsl_permutation->loc_Texture_Normal >= 0) R_Mesh_TexBind(0, R_GetTexture(rsurface_texture->currentskinframe->nmap)); if (r_glsl_permutation->loc_Texture_Color >= 0) R_Mesh_TexBind(1, R_GetTexture(rsurface_texture->basetexture)); if (r_glsl_permutation->loc_Texture_Gloss >= 0) R_Mesh_TexBind(2, R_GetTexture(rsurface_texture->glosstexture)); //if (r_glsl_permutation->loc_Texture_Cube >= 0 && permutation & SHADERPERMUTATION_MODE_LIGHTSOURCE) R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); if (r_glsl_permutation->loc_Texture_FogMask >= 0) R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); - if (r_glsl_permutation->loc_Texture_Pants >= 0) R_Mesh_TexBind(5, R_GetTexture(rsurface_texture->skin.pants)); - if (r_glsl_permutation->loc_Texture_Shirt >= 0) R_Mesh_TexBind(6, R_GetTexture(rsurface_texture->skin.shirt)); + if (r_glsl_permutation->loc_Texture_Pants >= 0) R_Mesh_TexBind(5, R_GetTexture(rsurface_texture->currentskinframe->pants)); + if (r_glsl_permutation->loc_Texture_Shirt >= 0) R_Mesh_TexBind(6, R_GetTexture(rsurface_texture->currentskinframe->shirt)); //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_Texture_Glow >= 0) R_Mesh_TexBind(9, R_GetTexture(rsurface_texture->currentskinframe->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 @@ -884,14 +1024,14 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting) if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, rsurface_modelorg[0], rsurface_modelorg[1], rsurface_modelorg[2]); if (r_glsl_permutation->loc_Color_Pants >= 0) { - if (rsurface_texture->skin.pants) + if (rsurface_texture->currentskinframe->pants) qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, rsurface_entity->colormap_pantscolor[0], rsurface_entity->colormap_pantscolor[1], rsurface_entity->colormap_pantscolor[2]); else qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, 0, 0, 0); } if (r_glsl_permutation->loc_Color_Shirt >= 0) { - if (rsurface_texture->skin.shirt) + if (rsurface_texture->currentskinframe->shirt) qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, rsurface_entity->colormap_shirtcolor[0], rsurface_entity->colormap_shirtcolor[1], rsurface_entity->colormap_shirtcolor[2]); else qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0); @@ -905,9 +1045,9 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting) void R_SwitchSurfaceShader(int permutation) { - if (r_glsl_permutation != r_glsl_permutations + permutation) + if (r_glsl_permutation != r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK)) { - r_glsl_permutation = r_glsl_permutations + permutation; + r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK); CHECKGLERROR qglUseProgramObjectARB(r_glsl_permutation->program); CHECKGLERROR @@ -917,8 +1057,6 @@ void R_SwitchSurfaceShader(int permutation) void gl_main_start(void) { r_main_texturepool = R_AllocTexturePool(); - r_bloom_texture_screen = NULL; - r_bloom_texture_bloom = NULL; R_BuildBlankTextures(); R_BuildNoTexture(); if (gl_texturecubemap) @@ -927,19 +1065,19 @@ void gl_main_start(void) R_BuildNormalizationCube(); } R_BuildFogTexture(); + memset(&r_bloomstate, 0, sizeof(r_bloomstate)); memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations)); } void gl_main_shutdown(void) { R_FreeTexturePool(&r_main_texturepool); - r_bloom_texture_screen = NULL; - r_bloom_texture_bloom = NULL; r_texture_blanknormalmap = NULL; r_texture_white = NULL; r_texture_black = NULL; r_texture_whitecube = NULL; r_texture_normalizationcube = NULL; + memset(&r_bloomstate, 0, sizeof(r_bloomstate)); R_GLSL_Restart_f(); } @@ -955,7 +1093,7 @@ void gl_main_newmap(void) l = (int)strlen(entname) - 4; if (l >= 0 && !strcmp(entname + l, ".bsp")) { - strcpy(entname + l, ".ent"); + memcpy(entname + l, ".ent", 5); if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL))) { CL_ParseEntityLump(entities); @@ -992,6 +1130,8 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_wateralpha); Cvar_RegisterVariable(&r_dynamic); Cvar_RegisterVariable(&r_fullbright); + Cvar_RegisterVariable(&r_shadows); + Cvar_RegisterVariable(&r_shadows_throwdistance); Cvar_RegisterVariable(&r_q1bsp_skymasking); Cvar_RegisterVariable(&r_textureunits); Cvar_RegisterVariable(&r_glsl); @@ -1003,10 +1143,16 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_lerpmodels); Cvar_RegisterVariable(&r_waterscroll); Cvar_RegisterVariable(&r_bloom); - Cvar_RegisterVariable(&r_bloom_intensity); + Cvar_RegisterVariable(&r_bloom_colorscale); + Cvar_RegisterVariable(&r_bloom_brighten); Cvar_RegisterVariable(&r_bloom_blur); Cvar_RegisterVariable(&r_bloom_resolution); - Cvar_RegisterVariable(&r_bloom_power); + Cvar_RegisterVariable(&r_bloom_colorexponent); + Cvar_RegisterVariable(&r_bloom_colorsubtract); + Cvar_RegisterVariable(&r_hdr); + Cvar_RegisterVariable(&r_hdr_scenebrightness); + Cvar_RegisterVariable(&r_hdr_glowintensity); + Cvar_RegisterVariable(&r_hdr_range); Cvar_RegisterVariable(&r_smoothnormals_areaweighting); Cvar_RegisterVariable(&developer_texturelogging); Cvar_RegisterVariable(&gl_lightmaps); @@ -1119,15 +1265,25 @@ int R_CullBox(const vec3_t mins, const vec3_t maxs) static void R_UpdateEntityLighting(entity_render_t *ent) { vec3_t tempdiffusenormal; + + // fetch the lighting from the worldmodel data VectorSet(ent->modellight_ambient, r_ambient.value * (2.0f / 128.0f), r_ambient.value * (2.0f / 128.0f), r_ambient.value * (2.0f / 128.0f)); VectorClear(ent->modellight_diffuse); - VectorClear(ent->modellight_lightdir); + VectorClear(tempdiffusenormal); if ((ent->flags & RENDER_LIGHT) && r_refdef.worldmodel && r_refdef.worldmodel->brush.LightPoint) - r_refdef.worldmodel->brush.LightPoint(r_refdef.worldmodel, ent->origin, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal); + { + vec3_t org; + Matrix4x4_OriginFromMatrix(&ent->matrix, org); + r_refdef.worldmodel->brush.LightPoint(r_refdef.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal); + } else // highly rare VectorSet(ent->modellight_ambient, 1, 1, 1); + + // move the light direction into modelspace coordinates for lighting code Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir); VectorNormalize(ent->modellight_lightdir); + + // scale ambient and directional light contributions according to rendering variables ent->modellight_ambient[0] *= ent->colormod[0] * r_refdef.lightmapintensity; ent->modellight_ambient[1] *= ent->colormod[1] * r_refdef.lightmapintensity; ent->modellight_ambient[2] *= ent->colormod[2] * r_refdef.lightmapintensity; @@ -1160,9 +1316,13 @@ static void R_View_UpdateEntityVisible (void) for (i = 0;i < r_refdef.numentities;i++) { ent = r_refdef.entities[i]; - r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && (ent->effects & EF_NODEPTHTEST); + r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs); } } + + // update entity lighting (even on hidden entities for r_shadows) + for (i = 0;i < r_refdef.numentities;i++) + R_UpdateEntityLighting(r_refdef.entities[i]); } // only used if skyrendermasked, and normally returns false @@ -1332,194 +1492,472 @@ static void R_View_SetFrustum(void) void R_View_Update(void) { - // 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_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(); } -static void R_BlendView(void) +void R_SetupView(const matrix4x4_t *matrix) { - int screenwidth, screenheight; - qboolean dobloom; - qboolean doblend; - float vertex3f[12]; - float texcoord2f[3][8]; + if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows) + GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip); + else + GL_SetupView_Mode_Perspective(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip, r_refdef.farclip); - // 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); + GL_SetupView_Orientation_FromEntity(matrix); +} - 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; +void R_ResetViewRendering2D(void) +{ + if (gl_support_fragment_shader) + { + qglUseProgramObjectARB(0);CHECKGLERROR + } - if (!dobloom && !doblend) - return; + DrawQ_Finish(); + // 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_DepthMask(true); + GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height); + GL_Color(1, 1, 1, 1); + GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_AlphaTest(false); + GL_ScissorTest(false); + GL_DepthMask(false); 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; - R_Mesh_VertexPointer(vertex3f); - R_Mesh_ColorPointer(NULL); R_Mesh_ResetTextureState(); - if (dobloom) - { - 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); + qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR + qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR + qglDepthFunc(GL_LEQUAL);CHECKGLERROR + qglDisable(GL_STENCIL_TEST);CHECKGLERROR + qglStencilMask(~0);CHECKGLERROR + qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR + qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR + GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces +} + +void R_ResetViewRendering3D(void) +{ + if (gl_support_fragment_shader) + { + qglUseProgramObjectARB(0);CHECKGLERROR + } + + DrawQ_Finish(); + + // 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 + R_SetupView(&r_view.matrix); + GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height); + GL_Color(1, 1, 1, 1); + GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_AlphaTest(false); + GL_ScissorTest(true); + GL_DepthMask(true); + GL_DepthTest(true); + R_Mesh_Matrix(&identitymatrix); + R_Mesh_ResetTextureState(); + qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR + qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR + qglDepthFunc(GL_LEQUAL);CHECKGLERROR + qglDisable(GL_STENCIL_TEST);CHECKGLERROR + qglStencilMask(~0);CHECKGLERROR + qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR + qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR + GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces +} + +/* + R_Bloom_SetupShader( +"// bloom shader\n" +"// written by Forest 'LordHavoc' Hale\n" +"\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 ScreenTexCoord;\n" +"varying vec2 BloomTexCoord;\n" +"\n" +"\n" +"\n" +"\n" +"// vertex shader specific:\n" +"#ifdef VERTEX_SHADER\n" +"\n" +"void main(void)\n" +"{\n" +" ScreenTexCoord = vec2(gl_MultiTexCoord0);\n" +" BloomTexCoord = vec2(gl_MultiTexCoord1);\n" +" // transform vertex to camera space, using ftransform to match non-VS\n" +" // rendering\n" +" gl_Position = ftransform();\n" +"}\n" +"\n" +"#endif // VERTEX_SHADER\n" +"\n" +"\n" +"\n" +"\n" +"// fragment shader specific:\n" +"#ifdef FRAGMENT_SHADER\n" +"\n" +"void main(void)\n" +"{\n" +" int x, y; +" myhvec3 color = myhvec3(texture2D(Texture_Screen, ScreenTexCoord));\n" +" for (x = -BLUR_X;x <= BLUR_X;x++) +" color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n" +" color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n" +" color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n" +" color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n" + +" gl_FragColor = vec4(color);\n" +"}\n" +"\n" +"#endif // FRAGMENT_SHADER\n" +*/ + +void R_RenderScene(void); + +void R_Bloom_StartFrame(void) +{ + int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight; + + // set bloomwidth and bloomheight to the bloom resolution that will be + // used (often less than the screen resolution for faster rendering) + r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, r_view.width); + r_bloomstate.bloomheight = r_bloomstate.bloomwidth * r_view.height / r_view.width; + r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_view.height); + + // calculate desired texture sizes + if (gl_support_arb_texture_non_power_of_two) + { + screentexturewidth = r_view.width; + screentextureheight = r_view.height; + bloomtexturewidth = r_bloomstate.bloomwidth; + bloomtextureheight = r_bloomstate.bloomheight; + } + else + { + for (screentexturewidth = 1;screentexturewidth < vid.width ;screentexturewidth *= 2); + for (screentextureheight = 1;screentextureheight < vid.height ;screentextureheight *= 2); + for (bloomtexturewidth = 1;bloomtexturewidth < r_bloomstate.bloomwidth ;bloomtexturewidth *= 2); + for (bloomtextureheight = 1;bloomtextureheight < r_bloomstate.bloomheight;bloomtextureheight *= 2); + } + + if (r_hdr.integer) + { + screentexturewidth = screentextureheight = 0; + } + else if (r_bloom.integer) + { + } + else + { + screentexturewidth = screentextureheight = 0; + bloomtexturewidth = bloomtextureheight = 0; + } + + if ((!bloomtexturewidth && !bloomtextureheight) || r_bloom_resolution.integer < 4 || r_bloom_blur.value < 1 || r_bloom_blur.value >= 512 || screentexturewidth > gl_max_texture_size || screentextureheight > gl_max_texture_size || bloomtexturewidth > gl_max_texture_size || bloomtextureheight > gl_max_texture_size) + { + // can't use bloom if the parameters are too weird + // can't use bloom if the card does not support the texture size + if (r_bloomstate.texture_screen) + R_FreeTexture(r_bloomstate.texture_screen); + if (r_bloomstate.texture_bloom) + R_FreeTexture(r_bloomstate.texture_bloom); + memset(&r_bloomstate, 0, sizeof(r_bloomstate)); + return; + } + + r_bloomstate.enabled = true; + r_bloomstate.hdr = r_hdr.integer != 0; + + // allocate textures as needed + if (r_bloomstate.screentexturewidth != screentexturewidth || r_bloomstate.screentextureheight != screentextureheight) + { + if (r_bloomstate.texture_screen) + R_FreeTexture(r_bloomstate.texture_screen); + r_bloomstate.texture_screen = NULL; + r_bloomstate.screentexturewidth = screentexturewidth; + r_bloomstate.screentextureheight = screentextureheight; + if (r_bloomstate.screentexturewidth && r_bloomstate.screentextureheight) + r_bloomstate.texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL); + } + if (r_bloomstate.bloomtexturewidth != bloomtexturewidth || r_bloomstate.bloomtextureheight != bloomtextureheight) + { + if (r_bloomstate.texture_bloom) + R_FreeTexture(r_bloomstate.texture_bloom); + r_bloomstate.texture_bloom = NULL; + r_bloomstate.bloomtexturewidth = bloomtexturewidth; + r_bloomstate.bloomtextureheight = bloomtextureheight; + if (r_bloomstate.bloomtexturewidth && r_bloomstate.bloomtextureheight) + r_bloomstate.texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", r_bloomstate.bloomtexturewidth, r_bloomstate.bloomtextureheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL); + } + + // set up a texcoord array for the full resolution screen image + // (we have to keep this around to copy back during final render) + r_bloomstate.screentexcoord2f[0] = 0; + r_bloomstate.screentexcoord2f[1] = (float)r_view.height / (float)r_bloomstate.screentextureheight; + r_bloomstate.screentexcoord2f[2] = (float)r_view.width / (float)r_bloomstate.screentexturewidth; + r_bloomstate.screentexcoord2f[3] = (float)r_view.height / (float)r_bloomstate.screentextureheight; + r_bloomstate.screentexcoord2f[4] = (float)r_view.width / (float)r_bloomstate.screentexturewidth; + r_bloomstate.screentexcoord2f[5] = 0; + r_bloomstate.screentexcoord2f[6] = 0; + r_bloomstate.screentexcoord2f[7] = 0; + + // set up a texcoord array for the reduced resolution bloom image + // (which will be additive blended over the screen image) + r_bloomstate.bloomtexcoord2f[0] = 0; + r_bloomstate.bloomtexcoord2f[1] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight; + r_bloomstate.bloomtexcoord2f[2] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth; + r_bloomstate.bloomtexcoord2f[3] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight; + r_bloomstate.bloomtexcoord2f[4] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth; + r_bloomstate.bloomtexcoord2f[5] = 0; + r_bloomstate.bloomtexcoord2f[6] = 0; + r_bloomstate.bloomtexcoord2f[7] = 0; +} + +void R_Bloom_CopyScreenTexture(float colorscale) +{ + r_refdef.stats.bloom++; + + R_ResetViewRendering2D(); + R_Mesh_VertexPointer(r_screenvertex3f); + R_Mesh_ColorPointer(NULL); + R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f); + R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.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 + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_Color(colorscale, colorscale, colorscale, 1); + // TODO: optimize with multitexture or GLSL + R_Mesh_Draw(0, 4, 2, polygonelements); + r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight; + + // we now have a bloom image in the framebuffer + // copy it into the bloom image texture for later processing + R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom)); + GL_ActiveTexture(0); + CHECKGLERROR + qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR + r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight; +} + +void R_Bloom_CopyHDRTexture(void) +{ + R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom)); + 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; +} + +void R_Bloom_MakeTexture(void) +{ + int x, range, dir; + float xoffset, yoffset, r, brighten; + + r_refdef.stats.bloom++; + + R_ResetViewRendering2D(); + R_Mesh_VertexPointer(r_screenvertex3f); + R_Mesh_ColorPointer(NULL); + + // we have a bloom image in the framebuffer + CHECKGLERROR + qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR + + for (x = 1;x < r_bloom_colorexponent.value;) + { + x *= 2; + r = bound(0, r_bloom_colorexponent.value / x, 1); + GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); + GL_Color(r, r, r, 1); + R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom)); + R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f); R_Mesh_Draw(0, 4, 2, polygonelements); - r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight; - // 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 - R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_bloom)); - R_Mesh_TexCoordPointer(0, 2, texcoord2f[2]); + r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight; + + // 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; + qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR + r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight; + } + + range = r_bloom_blur.integer * r_bloomstate.bloomwidth / 320; + brighten = r_bloom_brighten.value; + if (r_hdr.integer) + brighten *= r_hdr_range.value; + R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom)); + R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f); + + for (dir = 0;dir < 2;dir++) + { // 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; + if (!dir){xoffset = 0;yoffset = x;} + else {xoffset = x;yoffset = 0;} + xoffset /= (float)r_bloomstate.bloomtexturewidth; + yoffset /= (float)r_bloomstate.bloomtextureheight; // 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; + r_bloomstate.offsettexcoord2f[0] = xoffset+0; + r_bloomstate.offsettexcoord2f[1] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight; + r_bloomstate.offsettexcoord2f[2] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth; + r_bloomstate.offsettexcoord2f[3] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight; + r_bloomstate.offsettexcoord2f[4] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth; + r_bloomstate.offsettexcoord2f[5] = yoffset+0; + r_bloomstate.offsettexcoord2f[6] = xoffset+0; + r_bloomstate.offsettexcoord2f[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; + //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1); + //r = (dir ? 1.0f : brighten)/(range*2+1); + r = (dir ? 1.0f : brighten)/(range*2+1)*(1 - x*x/(float)(range*range)); GL_Color(r, r, r, 1); R_Mesh_Draw(0, 4, 2, polygonelements); - r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight; + r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.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; + qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR + r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight; + } + + // apply subtract last + // (just like it would be in a GLSL shader) + if (r_bloom_colorsubtract.value > 0 && gl_support_ext_blend_subtract) + { 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 + R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom)); + R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f); + GL_Color(1, 1, 1, 1); + R_Mesh_Draw(0, 4, 2, polygonelements); + r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight; + + GL_BlendFunc(GL_ONE, GL_ONE); + qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT); + R_Mesh_TexBind(0, R_GetTexture(r_texture_white)); + R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f); + GL_Color(r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 1); + R_Mesh_Draw(0, 4, 2, polygonelements); + r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight; + qglBlendEquationEXT(GL_FUNC_ADD_EXT); + + // copy the darkened bloom view to a texture + R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom)); 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 + qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR + r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight; + } +} + +void R_HDR_RenderBloomTexture(void) +{ + int oldwidth, oldheight; + + oldwidth = r_view.width; + oldheight = r_view.height; + r_view.width = r_bloomstate.bloomwidth; + r_view.height = r_bloomstate.bloomheight; + + // TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer? it might improve SLI performance. + // TODO: add exposure compensation features + // TODO: add fp16 framebuffer support + + r_view.colorscale = r_bloom_colorscale.value * r_hdr_scenebrightness.value; + if (r_hdr.integer) + r_view.colorscale /= r_hdr_range.value; + R_RenderScene(); + + R_ResetViewRendering2D(); + + R_Bloom_CopyHDRTexture(); + R_Bloom_MakeTexture(); + + R_ResetViewRendering3D(); + + R_ClearScreen(); + if (r_timereport_active) + R_TimeReport("clear"); + + + // restore the view settings + r_view.width = oldwidth; + r_view.height = oldheight; +} + +static void R_BlendView(void) +{ + if (r_bloomstate.enabled && r_bloomstate.hdr) + { + // render high dynamic range bloom effect + // the bloom texture was made earlier this render, so we just need to + // blend it onto the screen... + R_ResetViewRendering2D(); + R_Mesh_VertexPointer(r_screenvertex3f); + R_Mesh_ColorPointer(NULL); + GL_Color(1, 1, 1, 1); + GL_BlendFunc(GL_ONE, GL_ONE); + R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom)); + R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f); + R_Mesh_Draw(0, 4, 2, polygonelements); + r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height; + } + else if (r_bloomstate.enabled) + { + // render simple bloom effect + // copy the screen and shrink it and darken it for the bloom process + R_Bloom_CopyScreenTexture(r_bloom_colorscale.value); + // make the bloom texture + R_Bloom_MakeTexture(); // put the original screen image back in place and blend the bloom // texture on it - GL_Color(1,1,1,1); + R_ResetViewRendering2D(); + R_Mesh_VertexPointer(r_screenvertex3f); + 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)); - R_Mesh_TexCoordPointer(0, 2, texcoord2f[0]); + R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom)); + R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f); if (r_textureunits.integer >= 2 && gl_combine.integer) { R_Mesh_TexCombine(1, GL_ADD, GL_ADD, 1, 1); - R_Mesh_TexBind(1, R_GetTexture(r_bloom_texture_bloom)); - R_Mesh_TexCoordPointer(1, 2, texcoord2f[1]); + R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_screen)); + R_Mesh_TexCoordPointer(1, 2, r_bloomstate.screentexcoord2f); } else { @@ -1527,16 +1965,18 @@ static void R_BlendView(void) r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height; // now blend on the bloom texture GL_BlendFunc(GL_ONE, GL_ONE); - R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_bloom)); - R_Mesh_TexCoordPointer(0, 2, texcoord2f[1]); + R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen)); + R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f); } R_Mesh_Draw(0, 4, 2, polygonelements); r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height; } - if (doblend) + if (r_refdef.viewblend[3] >= (1.0f / 256.0f)) { // apply a color tint to the whole view - R_Mesh_ResetTextureState(); + R_ResetViewRendering2D(); + R_Mesh_VertexPointer(r_screenvertex3f); + 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); @@ -1549,8 +1989,6 @@ matrix4x4_t r_waterscrollmatrix; void R_UpdateVariables(void) { - int i; - R_Textures_Frame(); r_refdef.farclip = 4096; @@ -1615,17 +2053,6 @@ void R_UpdateVariables(void) } else r_refdef.fogenabled = false; - - // update some cached entity properties... - for (i = 0;i < r_refdef.numentities;i++) - { - entity_render_t *ent = r_refdef.entities[i]; - // some of the renderer still relies on origin... - Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin); - // some of the renderer still relies on scale... - ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix); - R_UpdateEntityLighting(ent); - } } /* @@ -1638,9 +2065,9 @@ void R_RenderView(void) if (!r_refdef.entities/* || !r_refdef.worldmodel*/) return; //Host_Error ("R_RenderView: NULL worldmodel"); + R_Shadow_UpdateWorldLightSelection(); + CHECKGLERROR - GL_ScissorTest(true); - GL_DepthMask(true); if (r_timereport_active) R_TimeReport("setup"); @@ -1648,46 +2075,19 @@ void R_RenderView(void) if (r_timereport_active) R_TimeReport("visibility"); + R_ResetViewRendering3D(); + R_ClearScreen(); if (r_timereport_active) R_TimeReport("clear"); - R_RenderScene(); - - R_BlendView(); - if (r_timereport_active) - R_TimeReport("blendview"); - - GL_Scissor(0, 0, vid.width, vid.height); - GL_ScissorTest(false); - CHECKGLERROR -} - -//[515]: csqc -void CSQC_R_ClearScreen (void) -{ - if (!r_refdef.entities/* || !r_refdef.worldmodel*/) - return; //Host_Error ("R_RenderView: NULL worldmodel"); - - CHECKGLERROR - GL_ScissorTest(true); - GL_DepthMask(true); - if (r_timereport_active) - R_TimeReport("setup"); + R_Bloom_StartFrame(); - R_View_Update(); - if (r_timereport_active) - R_TimeReport("visibility"); + // this produces a bloom texture to be used in R_BlendView() later + if (r_hdr.integer) + R_HDR_RenderBloomTexture(); - R_ClearScreen(); - if (r_timereport_active) - R_TimeReport("clear"); - CHECKGLERROR -} - -//[515]: csqc -void CSQC_R_RenderScene (void) -{ + r_view.colorscale = r_hdr_scenebrightness.value; R_RenderScene(); R_BlendView(); @@ -1708,26 +2108,10 @@ void R_RenderScene(void) if (r_refdef.extraupdate) S_ExtraUpdate (); - CHECKGLERROR - if (gl_support_fragment_shader) - { - qglUseProgramObjectARB(0);CHECKGLERROR - } - qglDepthFunc(GL_LEQUAL);CHECKGLERROR - qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR - qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR + R_ResetViewRendering3D(); R_MeshQueue_BeginScene(); - if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows) - GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip); - else - GL_SetupView_Mode_Perspective(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip, r_refdef.farclip); - - GL_SetupView_Orientation_FromEntity(&r_view.matrix); - - R_Shadow_UpdateWorldLightSelection(); - R_SkyStartFrame(); Matrix4x4_CreateTranslate(&r_waterscrollmatrix, sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0); @@ -1768,6 +2152,17 @@ void R_RenderScene(void) if (r_refdef.extraupdate) S_ExtraUpdate (); + if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0) + { + R_DrawModelShadows(); + + R_ResetViewRendering3D(); + + // don't let sound skip if going slow + if (r_refdef.extraupdate) + S_ExtraUpdate (); + } + R_ShadowVolumeLighting(false); if (r_timereport_active) R_TimeReport("rtlights"); @@ -1828,13 +2223,7 @@ void R_RenderScene(void) if (r_refdef.extraupdate) S_ExtraUpdate (); - CHECKGLERROR - if (gl_support_fragment_shader) - { - qglUseProgramObjectARB(0);CHECKGLERROR - } - qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR - qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR + R_ResetViewRendering2D(); } /* @@ -1931,12 +2320,15 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight GL_DepthMask(true); } GL_DepthTest(!(ent->effects & EF_NODEPTHTEST)); + GL_CullFace((ent->flags & RENDER_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces R_Mesh_VertexPointer(nomodelvertex3f); if (r_refdef.fogenabled) { + vec3_t org; memcpy(color4f, nomodelcolor4f, sizeof(float[6*4])); R_Mesh_ColorPointer(color4f); - f2 = VERTEXFOGTABLE(VectorDistance(ent->origin, r_view.origin)); + Matrix4x4_OriginFromMatrix(&ent->matrix, org); + f2 = VERTEXFOGTABLE(VectorDistance(org, r_view.origin)); f1 = 1 - f2; for (i = 0, c = color4f;i < 6;i++, c += 4) { @@ -1961,8 +2353,10 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight void R_DrawNoModel(entity_render_t *ent) { + vec3_t org; + Matrix4x4_OriginFromMatrix(&ent->matrix, org); //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1)) - R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_view.origin : ent->origin, R_DrawNoModel_TransparentCallback, ent, 0, r_shadow_rtlight); + R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_view.origin : org, R_DrawNoModel_TransparentCallback, ent, 0, r_shadow_rtlight); //else // R_DrawNoModelCallback(ent, 0); } @@ -2031,22 +2425,25 @@ void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, rtexture_ 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 R_Mesh_AddVertex3f(rmesh_t *mesh, const float *v) +int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z) { int i; float *vertex3f; + float v[3]; + VectorSet(v, x, y, z); for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3) if (VectorDistance2(v, vertex3f) < mesh->epsilon2) break; @@ -2067,12 +2464,12 @@ void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f) { int i; int *e, element[3]; - element[0] = R_Mesh_AddVertex3f(mesh, vertex3f);vertex3f += 3; - element[1] = R_Mesh_AddVertex3f(mesh, vertex3f);vertex3f += 3; + element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3; + element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3; e = mesh->element3i + mesh->numtriangles * 3; for (i = 0;i < numvertices - 2;i++, vertex3f += 3) { - element[2] = R_Mesh_AddVertex3f(mesh, vertex3f); + element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]); if (mesh->numtriangles < mesh->maxtriangles) { *e++ = element[0]; @@ -2084,29 +2481,58 @@ void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f) } } +void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d) +{ + int i; + int *e, element[3]; + element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3; + element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3; + e = mesh->element3i + mesh->numtriangles * 3; + for (i = 0;i < numvertices - 2;i++, vertex3d += 3) + { + element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]); + if (mesh->numtriangles < mesh->maxtriangles) + { + *e++ = element[0]; + *e++ = element[1]; + *e++ = element[2]; + mesh->numtriangles++; + } + element[1] = element[2]; + } +} + +#define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0) void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes) { int planenum, planenum2; int w; int tempnumpoints; mplane_t *plane, *plane2; - float temppoints[2][256*3]; + double maxdist; + double temppoints[2][256*3]; + // figure out how large a bounding box we need to properly compute this brush + maxdist = 0; + for (w = 0;w < numplanes;w++) + maxdist = max(maxdist, planes[w].dist); + // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024 + maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0; for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++) { w = 0; tempnumpoints = 4; - PolygonF_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->normal[3], 1024.0*1024.0*1024.0); + PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist); for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++) { if (planenum2 == planenum) continue; - PolygonF_Divide(tempnumpoints, temppoints[w], plane2->normal[0], plane2->normal[1], plane2->normal[2], plane2->dist, 1.0/32.0, 0, NULL, NULL, 256, temppoints[!w], &tempnumpoints, NULL); + PolygonD_Divide(tempnumpoints, temppoints[w], plane2->normal[0], plane2->normal[1], plane2->normal[2], plane2->dist, R_MESH_PLANE_DIST_EPSILON, 0, NULL, NULL, 256, temppoints[!w], &tempnumpoints, NULL); w = !w; } if (tempnumpoints < 3) continue; // generate elements forming a triangle fan for this polygon - R_Mesh_AddPolygon3f(mesh, tempnumpoints, temppoints[w]); + R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]); } } @@ -2115,7 +2541,7 @@ static void R_DrawCollisionBrush(const colbrushf_t *brush) 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); @@ -2128,7 +2554,7 @@ static void R_DrawCollisionSurface(const entity_render_t *ent, const msurface_t 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); @@ -2144,20 +2570,22 @@ static void R_Texture_AddLayer(texture_t *t, qboolean depthmask, int blendfunc1, 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; } void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) { + model_t *model = ent->model; + // FIXME: identify models using a better check than ent->model->brush.shadowmesh //int lightmode = ((ent->effects & EF_FULLBRIGHT) || ent->model->brush.shadowmesh) ? 0 : 2; + // switch to an alternate material if this is a q1bsp animated material { texture_t *texture = t; - model_t *model = ent->model; int s = ent->skinnum; if ((unsigned int)s >= (unsigned int)model->numskins) s = 0; @@ -2182,9 +2610,13 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) texture->currentframe = t; } + // pick a new currentskinframe if the material is animated + if (t->numskinframes >= 2) + t->currentskinframe = t->skinframes + ((int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes); + t->currentmaterialflags = t->basematerialflags; t->currentalpha = ent->alpha; - if (t->basematerialflags & MATERIALFLAG_WATERALPHA) + if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer)) t->currentalpha *= r_wateralpha.value; if (!(ent->flags & RENDER_LIGHT)) t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT; @@ -2200,17 +2632,17 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) t->currenttexmatrix = identitymatrix; t->colormapping = VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f); - t->basetexture = (!t->colormapping && t->skin.merged) ? t->skin.merged : t->skin.base; + t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base; t->glosstexture = r_texture_white; - t->specularpower = 8; + t->specularpower = r_shadow_glossexponent.value; t->specularscale = 0; if (r_shadow_gloss.integer > 0) { - if (t->skin.gloss) + if (t->currentskinframe->gloss) { if (r_shadow_glossintensity.value > 0) { - t->glosstexture = t->skin.gloss; + t->glosstexture = t->currentskinframe->gloss; t->specularscale = r_shadow_glossintensity.value; } } @@ -2253,15 +2685,15 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) int layerflags = 0; if (r_refdef.fogenabled && (t->currentmaterialflags & MATERIALFLAG_BLENDED)) layerflags |= TEXTURELAYERFLAG_FOGDARKEN; - currentbasetexture = (VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) < (1.0f / 1048576.0f) && t->skin.merged) ? t->skin.merged : t->skin.base; + currentbasetexture = (VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) < (1.0f / 1048576.0f) && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base; if (t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) { // fullbright is not affected by r_refdef.lightmapintensity R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_TEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0], ent->colormod[1], ent->colormod[2], t->currentalpha); - if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->skin.pants) - R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * ent->colormod[0], ent->colormap_pantscolor[1] * ent->colormod[1], ent->colormap_pantscolor[2] * ent->colormod[2], t->currentalpha); - if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->skin.shirt) - R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * ent->colormod[0], ent->colormap_shirtcolor[1] * ent->colormod[1], ent->colormap_shirtcolor[2] * ent->colormod[2], t->currentalpha); + if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants) + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * ent->colormod[0], ent->colormap_pantscolor[1] * ent->colormod[1], ent->colormap_pantscolor[2] * ent->colormod[2], t->currentalpha); + if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt) + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * ent->colormod[0], ent->colormap_shirtcolor[1] * ent->colormod[1], ent->colormap_shirtcolor[2] * ent->colormod[2], t->currentalpha); } else { @@ -2276,21 +2708,21 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * colorscale, ent->colormod[1] * colorscale, ent->colormod[2] * colorscale, t->currentalpha); if (r_ambient.value >= (1.0f/64.0f)) R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * r_ambient.value * (1.0f / 64.0f), ent->colormod[1] * r_ambient.value * (1.0f / 64.0f), ent->colormod[2] * r_ambient.value * (1.0f / 64.0f), t->currentalpha); - if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->skin.pants) + if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants) { - R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->skin.pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * ent->colormod[0] * colorscale, ent->colormap_pantscolor[1] * ent->colormod[1] * colorscale, ent->colormap_pantscolor[2] * ent->colormod[2] * colorscale, t->currentalpha); + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * ent->colormod[0] * colorscale, ent->colormap_pantscolor[1] * ent->colormod[1] * colorscale, ent->colormap_pantscolor[2] * ent->colormod[2] * colorscale, t->currentalpha); if (r_ambient.value >= (1.0f/64.0f)) - R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * ent->colormod[0] * r_ambient.value * (1.0f / 64.0f), ent->colormap_pantscolor[1] * ent->colormod[1] * r_ambient.value * (1.0f / 64.0f), ent->colormap_pantscolor[2] * ent->colormod[2] * r_ambient.value * (1.0f / 64.0f), t->currentalpha); + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * ent->colormod[0] * r_ambient.value * (1.0f / 64.0f), ent->colormap_pantscolor[1] * ent->colormod[1] * r_ambient.value * (1.0f / 64.0f), ent->colormap_pantscolor[2] * ent->colormod[2] * r_ambient.value * (1.0f / 64.0f), t->currentalpha); } - if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->skin.shirt) + if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt) { - R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->skin.shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * ent->colormod[0] * colorscale, ent->colormap_shirtcolor[1] * ent->colormod[1] * colorscale, ent->colormap_shirtcolor[2] * ent->colormod[2] * colorscale, t->currentalpha); + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * ent->colormod[0] * colorscale, ent->colormap_shirtcolor[1] * ent->colormod[1] * colorscale, ent->colormap_shirtcolor[2] * ent->colormod[2] * colorscale, t->currentalpha); if (r_ambient.value >= (1.0f/64.0f)) - R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->skin.shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * ent->colormod[0] * r_ambient.value * (1.0f / 64.0f), ent->colormap_shirtcolor[1] * ent->colormod[1] * r_ambient.value * (1.0f / 64.0f), ent->colormap_shirtcolor[2] * ent->colormod[2] * r_ambient.value * (1.0f / 64.0f), t->currentalpha); + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * ent->colormod[0] * r_ambient.value * (1.0f / 64.0f), ent->colormap_shirtcolor[1] * ent->colormod[1] * r_ambient.value * (1.0f / 64.0f), ent->colormap_shirtcolor[2] * ent->colormod[2] * r_ambient.value * (1.0f / 64.0f), t->currentalpha); } } - 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); + if (t->currentskinframe->glow != NULL) + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->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 @@ -2304,7 +2736,7 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) // were darkened by fog already, and we should not add fog color // (because the background was not darkened, there is no fog color // that was lost behind it). - R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_BLENDED) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->skin.fog, &identitymatrix, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], t->currentalpha); + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_BLENDED) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->currentskinframe->fog, &identitymatrix, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], t->currentalpha); } } } @@ -2371,8 +2803,24 @@ rsurfmode_t rsurface_mode; texture_t *rsurface_glsl_texture; qboolean rsurface_glsl_uselightmap; +void RSurf_CleanUp(void) +{ + CHECKGLERROR + if (rsurface_mode == RSURFMODE_GLSL) + { + qglUseProgramObjectARB(0);CHECKGLERROR + } + GL_AlphaTest(false); + rsurface_mode = RSURFMODE_NONE; + rsurface_lightmaptexture = NULL; + rsurface_texture = NULL; + rsurface_glsl_texture = NULL; + rsurface_glsl_uselightmap = false; +} + void RSurf_ActiveEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents) { + RSurf_CleanUp(); Matrix4x4_Transform(&ent->inversematrix, r_view.origin, rsurface_modelorg); rsurface_entity = ent; rsurface_model = ent->model; @@ -2420,30 +2868,11 @@ void RSurf_ActiveEntity(const entity_render_t *ent, qboolean wantnormals, qboole rsurface_svector3f = rsurface_modelsvector3f; rsurface_tvector3f = rsurface_modeltvector3f; rsurface_normal3f = rsurface_modelnormal3f; - rsurface_mode = RSURFMODE_NONE; - rsurface_lightmaptexture = NULL; - rsurface_texture = NULL; - rsurface_glsl_texture = NULL; - rsurface_glsl_uselightmap = false; -} - -void RSurf_CleanUp(void) -{ - CHECKGLERROR - if (rsurface_mode == RSURFMODE_GLSL) - { - qglUseProgramObjectARB(0);CHECKGLERROR - } - GL_AlphaTest(false); - rsurface_mode = RSURFMODE_NONE; - rsurface_lightmaptexture = NULL; - rsurface_texture = NULL; - rsurface_glsl_texture = NULL; - rsurface_glsl_uselightmap = false; } void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, msurface_t **texturesurfacelist) { + // if vertices are dynamic (animated models), generate them into the temporary rsurface_array_model* arrays and point rsurface_model* at them instead of the static data from the model itself if (rsurface_generatedvertex) { if (rsurface_texture->textureflags & (Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2)) @@ -2462,6 +2891,7 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta Mod_BuildTextureVectorsFromNormals(0, rsurface_model->surfmesh.num_vertices, rsurface_model->surfmesh.num_triangles, rsurface_modelvertex3f, rsurface_model->surfmesh.data_texcoordtexture2f, rsurface_modelnormal3f, rsurface_model->surfmesh.data_element3i, rsurface_array_modelsvector3f, rsurface_array_modeltvector3f, r_smoothnormals_areaweighting.integer); } } + // if vertices are deformed (sprite flares and things in maps, possibly water waves, bulges and other deformations), generate them into rsurface_deform* arrays from whatever the rsurface_model* array pointers point to (may be static model data or generated data for an animated model) if (rsurface_texture->textureflags & (Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2)) { int texturesurfaceindex; @@ -2470,7 +2900,7 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta Matrix4x4_Transform(&rsurface_entity->inversematrix, r_view.forward, forward); Matrix4x4_Transform(&rsurface_entity->inversematrix, r_view.right, right); Matrix4x4_Transform(&rsurface_entity->inversematrix, r_view.up, up); - // make deformed versions of only the vertices used by the specified surfaces + // make deformed versions of only the model vertices used by the specified surfaces for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) { int i, j; @@ -2480,7 +2910,7 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta { VectorClear(center); for (i = 0;i < 4;i++) - VectorAdd(center, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center); + VectorAdd(center, (rsurface_modelvertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center); VectorScale(center, 0.25f, center); if (rsurface_texture->textureflags & Q3TEXTUREFLAG_AUTOSPRITE2) { @@ -2494,12 +2924,12 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta VectorSet(up, 0, 0, 1); } // FIXME: calculate vectors from triangle edges instead of using texture vectors as an easy way out? - Matrix4x4_FromVectors(&matrix1, (rsurface_normal3f + 3 * surface->num_firstvertex) + j*3, (rsurface_svector3f + 3 * surface->num_firstvertex) + j*3, (rsurface_tvector3f + 3 * surface->num_firstvertex) + j*3, center); + Matrix4x4_FromVectors(&matrix1, (rsurface_modelnormal3f + 3 * surface->num_firstvertex) + j*3, (rsurface_modelsvector3f + 3 * surface->num_firstvertex) + j*3, (rsurface_modeltvector3f + 3 * surface->num_firstvertex) + j*3, center); Matrix4x4_Invert_Simple(&imatrix1, &matrix1); for (i = 0;i < 4;i++) - Matrix4x4_Transform(&imatrix1, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, v[i]); + Matrix4x4_Transform(&imatrix1, (rsurface_modelvertex3f + 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); @@ -2509,6 +2939,13 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta rsurface_tvector3f = rsurface_array_deformedtvector3f; rsurface_normal3f = rsurface_array_deformednormal3f; } + else + { + rsurface_vertex3f = rsurface_modelvertex3f; + rsurface_svector3f = rsurface_modelsvector3f; + rsurface_tvector3f = rsurface_modeltvector3f; + rsurface_normal3f = rsurface_modelnormal3f; + } R_Mesh_VertexPointer(rsurface_vertex3f); } @@ -2603,7 +3040,7 @@ static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, msurface_t **te { 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)); } @@ -2812,7 +3249,7 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, msurface_t **te // 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) @@ -3136,10 +3573,7 @@ static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **textur r_refdef.stats.entities_surfaces += texturenumsurfaces; CHECKGLERROR GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST)); - if ((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) - { - qglDisable(GL_CULL_FACE);CHECKGLERROR - } + GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces if (r_showsurfaces.integer) R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist); else if (rsurface_texture->currentmaterialflags & MATERIALFLAG_SKY) @@ -3155,10 +3589,6 @@ static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **textur } CHECKGLERROR GL_LockArrays(0, 0); - if ((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) - { - qglEnable(GL_CULL_FACE);CHECKGLERROR - } } #define BATCHSIZE 256 @@ -3184,20 +3614,20 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const if (t != surface->texture || rsurface_lightmaptexture != surface->lightmaptexture) { if (batchcount > 0) - R_DrawTextureSurfaceList(batchcount, texturesurfacelist); + if (!(rsurface_texture->currentmaterialflags & MATERIALFLAG_SKY)) // transparent sky is too difficult + R_DrawTextureSurfaceList(batchcount, texturesurfacelist); batchcount = 0; t = surface->texture; rsurface_lightmaptexture = surface->lightmaptexture; R_UpdateTextureInfo(ent, t); rsurface_texture = t->currentframe; } - if (rsurface_texture->currentmaterialflags & MATERIALFLAG_SKY) - continue; // transparent sky is too difficult texturesurfacelist[batchcount++] = surface; } if (batchcount > 0) - R_DrawTextureSurfaceList(batchcount, texturesurfacelist); + if (!(rsurface_texture->currentmaterialflags & MATERIALFLAG_SKY)) // transparent sky is too difficult + R_DrawTextureSurfaceList(batchcount, texturesurfacelist); RSurf_CleanUp(); } @@ -3371,12 +3801,8 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) const int *elements; vec3_t v; CHECKGLERROR - GL_DepthTest(true); + GL_DepthTest(!r_showdisabledepthtest.integer); GL_DepthMask(true); - if (r_showdisabledepthtest.integer) - { - qglDepthFunc(GL_ALWAYS);CHECKGLERROR - } GL_BlendFunc(GL_ONE, GL_ZERO); R_Mesh_ColorPointer(NULL); R_Mesh_ResetTextureState(); @@ -3391,11 +3817,11 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) 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); @@ -3410,7 +3836,7 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) } 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++) { @@ -3421,7 +3847,7 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) } 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++) { @@ -3432,7 +3858,7 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) } 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++) { @@ -3447,10 +3873,5 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) } } rsurface_texture = NULL; - if (r_showdisabledepthtest.integer) - { - qglDepthFunc(GL_LEQUAL);CHECKGLERROR - } } } -