X-Git-Url: http://git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=gl_rmain.c;h=6463c80599199826f3f7f4d6c84fa74e9ad2f227;hp=5aa039e08de154240f9ca3dad4a3c301a5f66319;hb=1fd37f5239fe019e4d53c3e19b6fa9ff67da12e1;hpb=2edc84fdae77f0542fd0ff540a9ee57574af21cf diff --git a/gl_rmain.c b/gl_rmain.c index 5aa039e0..6463c805 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -28,11 +28,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. mempool_t *r_main_mempool; rtexturepool_t *r_main_texturepool; +static int r_frame = 0; ///< used only by R_GetCurrentTexture + // // screen size info // r_refdef_t r_refdef; +cvar_t r_motionblur = {CVAR_SAVE, "r_motionblur", "0", "motionblur value scale - 0.5 recommended"}; +cvar_t r_damageblur = {CVAR_SAVE, "r_damageblur", "0", "motionblur based on damage"}; +cvar_t r_motionblur_vmin = {CVAR_SAVE, "r_motionblur_vmin", "300", "minimum influence from velocity"}; +cvar_t r_motionblur_vmax = {CVAR_SAVE, "r_motionblur_vmax", "600", "maximum influence from velocity"}; +cvar_t r_motionblur_bmin = {CVAR_SAVE, "r_motionblur_bmin", "0.5", "velocity at which there is no blur yet (may be negative to always have some blur)"}; +cvar_t r_motionblur_vcoeff = {CVAR_SAVE, "r_motionblur_vcoeff", "0.05", "sliding average reaction time for velocity"}; +cvar_t r_motionblur_maxblur = {CVAR_SAVE, "r_motionblur_maxblur", "0.88", "cap for motionblur alpha value"}; +cvar_t r_motionblur_randomize = {CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"}; + +cvar_t r_animcache = {CVAR_SAVE, "r_animcache", "1", "cache animation frames to save CPU usage, primarily optimizes shadows and reflections"}; + cvar_t r_depthfirst = {CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"}; cvar_t r_useinfinitefarclip = {CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"}; cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip plane" }; @@ -96,7 +109,7 @@ cvar_t r_water_resolutionmultiplier = {CVAR_SAVE, "r_water_resolutionmultiplier" cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"}; cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"}; -cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1", "enables animation smoothing on sprites (requires r_lerpmodels 1)"}; +cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1", "enables animation smoothing on sprites"}; cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"}; cvar_t r_lerplightstyles = {CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"}; cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"}; @@ -126,6 +139,7 @@ cvar_t r_track_sprites = {CVAR_SAVE, "r_track_sprites", "1", "track SPR_LABEL* s cvar_t r_track_sprites_flags = {CVAR_SAVE, "r_track_sprites_flags", "1", "1: Rotate sprites accodringly, 2: Make it a continuous rotation"}; cvar_t r_track_sprites_scalew = {CVAR_SAVE, "r_track_sprites_scalew", "1", "width scaling of tracked sprites"}; cvar_t r_track_sprites_scaleh = {CVAR_SAVE, "r_track_sprites_scaleh", "1", "height scaling of tracked sprites"}; +cvar_t r_glsl_saturation = {CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"}; extern cvar_t v_glslgamma; @@ -139,7 +153,7 @@ static struct r_bloomstate_s int bloomwidth, bloomheight; int screentexturewidth, screentextureheight; - rtexture_t *texture_screen; + rtexture_t *texture_screen; /// \note also used for motion blur if enabled! int bloomtexturewidth, bloomtextureheight; rtexture_t *texture_bloom; @@ -153,7 +167,7 @@ r_bloomstate; r_waterstate_t r_waterstate; -// shadow volume bsp struct with automatically growing nodes buffer +/// shadow volume bsp struct with automatically growing nodes buffer svbsp_t r_svbsp; rtexture_t *r_texture_blanknormalmap; @@ -168,10 +182,14 @@ rtexture_t *r_texture_gammaramps; unsigned int r_texture_gammaramps_serial; //rtexture_t *r_texture_fogintensity; +unsigned int r_queries[R_MAX_OCCLUSION_QUERIES]; +unsigned int r_numqueries; +unsigned int r_maxqueries; + char r_qwskincache[MAX_SCOREBOARD][MAX_QPATH]; skinframe_t *r_qwskincache_skinframe[MAX_SCOREBOARD]; -// vertex coordinates for a quad that covers the screen exactly +/// vertex coordinates for a quad that covers the screen exactly const static float r_screenvertex3f[12] = { 0, 0, 0, @@ -471,6 +489,9 @@ static const char *builtinshaderstring = "#ifdef USEGAMMARAMPS\n" "uniform sampler2D Texture_GammaRamps;\n" "#endif\n" +"#ifdef USESATURATION\n" +"uniform float Saturation;\n" +"#endif\n" "#ifdef USEVERTEXTEXTUREBLEND\n" "uniform vec4 TintColor;\n" "#endif\n" @@ -478,12 +499,12 @@ static const char *builtinshaderstring = "uniform vec3 Gamma;\n" "#endif\n" "//uncomment these if you want to use them:\n" -"// uniform vec4 UserVec1;\n" +"uniform vec4 UserVec1;\n" "// uniform vec4 UserVec2;\n" "// uniform vec4 UserVec3;\n" "// uniform vec4 UserVec4;\n" "// uniform float ClientTime;\n" -"// uniform vec2 PixelSize;\n" +"uniform vec2 PixelSize;\n" "void main(void)\n" "{\n" " gl_FragColor = texture2D(Texture_First, gl_TexCoord[0].xy);\n" @@ -495,7 +516,21 @@ static const char *builtinshaderstring = "#endif\n" "\n" "#ifdef USEPOSTPROCESSING\n" -"// add your own postprocessing here or make your own ifdef for it\n" +"// do r_glsl_dumpshader, edit glsl/default.glsl, and replace this by your own postprocessing if you want\n" +"// this code does a blur with the radius specified in the first component of r_glsl_postprocess_uservec1 and blends it using the second component\n" +" gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.987688, -0.156434)) * UserVec1.y;\n" +" gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.156434, -0.891007)) * UserVec1.y;\n" +" gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2( 0.891007, -0.453990)) * UserVec1.y;\n" +" gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2( 0.707107, 0.707107)) * UserVec1.y;\n" +" gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.453990, 0.891007)) * UserVec1.y;\n" +" gl_FragColor /= (1 + 5 * UserVec1.y);\n" +"#endif\n" +"\n" +"#ifdef USESATURATION\n" +" //apply saturation BEFORE gamma ramps, so v_glslgamma value does not matter\n" +" myhalf y = dot(gl_FragColor.rgb, vec3(0.299, 0.587, 0.114));\n" +" //gl_FragColor = vec3(y) + (gl_FragColor.rgb - vec3(y)) * Saturation;\n" +" gl_FragColor.rgb = mix(vec3(y), gl_FragColor.rgb, Saturation);\n" // TODO: test this on ATI "#endif\n" "\n" "#ifdef USEGAMMARAMPS\n" @@ -556,6 +591,9 @@ static const char *builtinshaderstring = "#else // !MODE_GENERIC\n" "\n" "varying vec2 TexCoord;\n" +"#ifdef USEVERTEXTEXTUREBLEND\n" +"varying vec2 TexCoord2;\n" +"#endif\n" "varying vec2 TexCoordLightmap;\n" "\n" "#ifdef MODE_LIGHTSOURCE\n" @@ -606,6 +644,9 @@ static const char *builtinshaderstring = " gl_FrontColor = gl_Color;\n" " // copy the surface texcoord\n" " TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n" +"#ifdef USEVERTEXTEXTUREBLEND\n" +" TexCoord2 = vec2(gl_TextureMatrix[1] * gl_MultiTexCoord0);\n" +"#endif\n" "#ifndef MODE_LIGHTSOURCE\n" "# ifndef MODE_LIGHTDIRECTION\n" " TexCoordLightmap = vec2(gl_MultiTexCoord4);\n" @@ -847,7 +888,7 @@ static const char *builtinshaderstring = " myhalf terrainblend = clamp(myhalf(gl_Color.a) * color.a * 2.0 - 0.5, myhalf(0.0), myhalf(1.0));\n" " //myhalf terrainblend = min(myhalf(gl_Color.a) * color.a * 2.0, myhalf(1.0));\n" " //myhalf terrainblend = myhalf(gl_Color.a) * color.a > 0.5;\n" -" color.rgb = mix(myhalf3(texture2D(Texture_SecondaryColor, TexCoord)), color.rgb, terrainblend);\n" +" color.rgb = mix(myhalf3(texture2D(Texture_SecondaryColor, TexCoord2)), color.rgb, terrainblend);\n" " color.a = 1.0;\n" " //color = mix(myhalf4(1, 0, 0, 1), color, terrainblend);\n" "#endif\n" @@ -855,9 +896,9 @@ static const char *builtinshaderstring = "#ifdef USEDIFFUSE\n" " // get the surface normal and the gloss color\n" "# ifdef USEVERTEXTEXTUREBLEND\n" -" myhalf3 surfacenormal = normalize(mix(myhalf3(texture2D(Texture_SecondaryNormal, TexCoord)), myhalf3(texture2D(Texture_Normal, TexCoord)), terrainblend) - myhalf3(0.5, 0.5, 0.5));\n" +" myhalf3 surfacenormal = normalize(mix(myhalf3(texture2D(Texture_SecondaryNormal, TexCoord2)), myhalf3(texture2D(Texture_Normal, TexCoord)), terrainblend) - myhalf3(0.5, 0.5, 0.5));\n" "# ifdef USESPECULAR\n" -" myhalf3 glosscolor = mix(myhalf3(texture2D(Texture_SecondaryGloss, TexCoord)), myhalf3(texture2D(Texture_Gloss, TexCoord)), terrainblend);\n" +" myhalf3 glosscolor = mix(myhalf3(texture2D(Texture_SecondaryGloss, TexCoord2)), myhalf3(texture2D(Texture_Gloss, TexCoord)), terrainblend);\n" "# endif\n" "# else\n" " myhalf3 surfacenormal = normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5, 0.5, 0.5));\n" @@ -962,7 +1003,7 @@ static const char *builtinshaderstring = " // 0.25 supports up to 75.5 degrees normal/deluxe angle\n" "# ifdef USESPECULAR\n" "# ifdef USEEXACTSPECULARMATH\n" -" tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(reflect(diffusenormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n" +" tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(reflect(normalize(diffusenormal), surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n" "# else\n" " myhalf3 specularnormal = myhalf3(normalize(diffusenormal + myhalf3(normalize(EyeVector))));\n" " tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n" @@ -1027,8 +1068,12 @@ static const char *builtinshaderstring = " color *= TintColor;\n" "\n" "#ifdef USEGLOW\n" +"#ifdef USEVERTEXTEXTUREBLEND\n" +" color.rgb += mix(myhalf3(texture2D(Texture_SecondaryGlow, TexCoord2)), myhalf3(texture2D(Texture_Glow, TexCoord)), terrainblend);\n" +"#else\n" " color.rgb += myhalf3(texture2D(Texture_Glow, TexCoord)) * GlowScale;\n" "#endif\n" +"#endif\n" "\n" "#ifdef USECONTRASTBOOST\n" " color.rgb = color.rgb / (ContrastBoostCoeff * color.rgb + myhalf3(1, 1, 1));\n" @@ -1080,22 +1125,23 @@ shadermodeinfo_t; typedef enum shaderpermutation_e { - SHADERPERMUTATION_DIFFUSE = 1<<0, // (lightsource) whether to use directional shading - SHADERPERMUTATION_VERTEXTEXTUREBLEND = 1<<1, // indicates this is a two-layer material blend based on vertex alpha (q3bsp) - SHADERPERMUTATION_COLORMAPPING = 1<<2, // indicates this is a colormapped skin - SHADERPERMUTATION_CONTRASTBOOST = 1<<3, // r_glsl_contrastboost boosts the contrast at low color levels (similar to gamma) - SHADERPERMUTATION_FOG = 1<<4, // tint the color by fog color or black if using additive blend mode - SHADERPERMUTATION_CUBEFILTER = 1<<5, // (lightsource) use cubemap light filter - SHADERPERMUTATION_GLOW = 1<<6, // (lightmap) blend in an additive glow texture - SHADERPERMUTATION_SPECULAR = 1<<7, // (lightsource or deluxemapping) render specular effects - SHADERPERMUTATION_EXACTSPECULARMATH = 1<<8, // (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation - SHADERPERMUTATION_REFLECTION = 1<<9, // normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface - SHADERPERMUTATION_OFFSETMAPPING = 1<<10, // adjust texcoords to roughly simulate a displacement mapped surface - SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<11, // adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!) - SHADERPERMUTATION_GAMMARAMPS = 1<<12, // gamma (postprocessing only) - SHADERPERMUTATION_POSTPROCESSING = 1<<13, // user defined postprocessing - SHADERPERMUTATION_LIMIT = 1<<14, // size of permutations array - SHADERPERMUTATION_COUNT = 14 // size of shaderpermutationinfo array + SHADERPERMUTATION_DIFFUSE = 1<<0, ///< (lightsource) whether to use directional shading + SHADERPERMUTATION_VERTEXTEXTUREBLEND = 1<<1, ///< indicates this is a two-layer material blend based on vertex alpha (q3bsp) + SHADERPERMUTATION_COLORMAPPING = 1<<2, ///< indicates this is a colormapped skin + SHADERPERMUTATION_CONTRASTBOOST = 1<<3, ///< r_glsl_contrastboost boosts the contrast at low color levels (similar to gamma) + SHADERPERMUTATION_FOG = 1<<4, ///< tint the color by fog color or black if using additive blend mode + SHADERPERMUTATION_CUBEFILTER = 1<<5, ///< (lightsource) use cubemap light filter + SHADERPERMUTATION_GLOW = 1<<6, ///< (lightmap) blend in an additive glow texture + SHADERPERMUTATION_SPECULAR = 1<<7, ///< (lightsource or deluxemapping) render specular effects + SHADERPERMUTATION_EXACTSPECULARMATH = 1<<8, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation + SHADERPERMUTATION_REFLECTION = 1<<9, ///< normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface + SHADERPERMUTATION_OFFSETMAPPING = 1<<10, ///< adjust texcoords to roughly simulate a displacement mapped surface + SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<11, ///< adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!) + SHADERPERMUTATION_GAMMARAMPS = 1<<12, ///< gamma (postprocessing only) + SHADERPERMUTATION_POSTPROCESSING = 1<<13, ///< user defined postprocessing + SHADERPERMUTATION_SATURATION = 1<<14, ///< user defined postprocessing + SHADERPERMUTATION_LIMIT = 1<<15, ///< size of permutations array + SHADERPERMUTATION_COUNT = 15 ///< size of shaderpermutationinfo array } shaderpermutation_t; @@ -1116,23 +1162,24 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] = {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"}, {"#define USEGAMMARAMPS\n", " gammaramps"}, {"#define USEPOSTPROCESSING\n", " postprocessing"}, + {"#define USESATURATION\n", " saturation"}, }; -// this enum is multiplied by SHADERPERMUTATION_MODEBASE +/// this enum is multiplied by SHADERPERMUTATION_MODEBASE typedef enum shadermode_e { - SHADERMODE_GENERIC, // (particles/HUD/etc) vertex color, optionally multiplied by one texture - SHADERMODE_POSTPROCESS, // postprocessing shader (r_glsl_postprocess) - SHADERMODE_DEPTH_OR_SHADOW, // (depthfirst/shadows) vertex shader only - SHADERMODE_FLATCOLOR, // (lightmap) modulate texture by uniform color (q1bsp, q3bsp) - SHADERMODE_VERTEXCOLOR, // (lightmap) modulate texture by vertex colors (q3bsp) - SHADERMODE_LIGHTMAP, // (lightmap) modulate texture by lightmap texture (q1bsp, q3bsp) - SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE, // (lightmap) use directional pixel shading from texture containing modelspace light directions (q3bsp deluxemap) - SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE, // (lightmap) use directional pixel shading from texture containing tangentspace light directions (q1bsp deluxemap) - SHADERMODE_LIGHTDIRECTION, // (lightmap) use directional pixel shading from fixed light direction (q3bsp) - SHADERMODE_LIGHTSOURCE, // (lightsource) use directional pixel shading from light source (rtlight) - SHADERMODE_REFRACTION, // refract background (the material is rendered normally after this pass) - SHADERMODE_WATER, // refract background and reflection (the material is rendered normally after this pass) + SHADERMODE_GENERIC, ///< (particles/HUD/etc) vertex color, optionally multiplied by one texture + SHADERMODE_POSTPROCESS, ///< postprocessing shader (r_glsl_postprocess) + SHADERMODE_DEPTH_OR_SHADOW, ///< (depthfirst/shadows) vertex shader only + SHADERMODE_FLATCOLOR, ///< (lightmap) modulate texture by uniform color (q1bsp, q3bsp) + SHADERMODE_VERTEXCOLOR, ///< (lightmap) modulate texture by vertex colors (q3bsp) + SHADERMODE_LIGHTMAP, ///< (lightmap) modulate texture by lightmap texture (q1bsp, q3bsp) + SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE, ///< (lightmap) use directional pixel shading from texture containing modelspace light directions (q3bsp deluxemap) + SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE, ///< (lightmap) use directional pixel shading from texture containing tangentspace light directions (q1bsp deluxemap) + SHADERMODE_LIGHTDIRECTION, ///< (lightmap) use directional pixel shading from fixed light direction (q3bsp) + SHADERMODE_LIGHTSOURCE, ///< (lightsource) use directional pixel shading from light source (rtlight) + SHADERMODE_REFRACTION, ///< refract background (the material is rendered normally after this pass) + SHADERMODE_WATER, ///< refract background and reflection (the material is rendered normally after this pass) SHADERMODE_COUNT } shadermode_t; @@ -1156,11 +1203,11 @@ shadermodeinfo_t shadermodeinfo[SHADERMODE_COUNT] = typedef struct r_glsl_permutation_s { - // indicates if we have tried compiling this permutation already + /// indicates if we have tried compiling this permutation already qboolean compiled; - // 0 if compilation failed + /// 0 if compilation failed int program; - // locations of detected uniforms in program object, or -1 if not found + /// locations of detected uniforms in program object, or -1 if not found int loc_Texture_First; int loc_Texture_Second; int loc_Texture_GammaRamps; @@ -1199,8 +1246,8 @@ typedef struct r_glsl_permutation_s int loc_DiffuseColor; int loc_SpecularColor; int loc_LightDir; - int loc_ContrastBoostCoeff; // 1 - 1/ContrastBoost - int loc_GammaCoeff; // 1 / gamma + int loc_ContrastBoostCoeff; ///< 1 - 1/ContrastBoost + int loc_GammaCoeff; ///< 1 / gamma int loc_DistortScaleRefractReflect; int loc_ScreenScaleRefractReflect; int loc_ScreenCenterRefractReflect; @@ -1214,12 +1261,13 @@ typedef struct r_glsl_permutation_s int loc_UserVec4; int loc_ClientTime; int loc_PixelSize; + int loc_Saturation; } r_glsl_permutation_t; -// information about each possible shader permutation +/// information about each possible shader permutation r_glsl_permutation_t r_glsl_permutations[SHADERMODE_COUNT][SHADERPERMUTATION_LIMIT]; -// currently selected permutation +/// currently selected permutation r_glsl_permutation_t *r_glsl_permutation; static char *R_GLSL_GetText(const char *filename, qboolean printfromdisknotice) @@ -1236,13 +1284,13 @@ static char *R_GLSL_GetText(const char *filename, qboolean printfromdisknotice) } else if (!strcmp(filename, "glsl/default.glsl")) { - shaderstring = Mem_Alloc(r_main_mempool, strlen(builtinshaderstring) + 1); + shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(builtinshaderstring) + 1); memcpy(shaderstring, builtinshaderstring, strlen(builtinshaderstring) + 1); } return shaderstring; } -static void R_GLSL_CompilePermutation(shadermode_t mode, shaderpermutation_t permutation) +static void R_GLSL_CompilePermutation(unsigned int mode, unsigned int permutation) { int i; shadermodeinfo_t *modeinfo = shadermodeinfo + mode; @@ -1374,6 +1422,7 @@ static void R_GLSL_CompilePermutation(shadermode_t mode, shaderpermutation_t per p->loc_UserVec4 = qglGetUniformLocationARB(p->program, "UserVec4"); p->loc_ClientTime = qglGetUniformLocationARB(p->program, "ClientTime"); p->loc_PixelSize = qglGetUniformLocationARB(p->program, "PixelSize"); + p->loc_Saturation = qglGetUniformLocationARB(p->program, "Saturation"); // initialize the samplers to refer to the texture units we use if (p->loc_Texture_First >= 0) qglUniform1iARB(p->loc_Texture_First , GL20TU_FIRST); if (p->loc_Texture_Second >= 0) qglUniform1iARB(p->loc_Texture_Second , GL20TU_SECOND); @@ -1413,8 +1462,8 @@ static void R_GLSL_CompilePermutation(shadermode_t mode, shaderpermutation_t per void R_GLSL_Restart_f(void) { - shadermode_t mode; - shaderpermutation_t permutation; + unsigned int mode; + unsigned int permutation; for (mode = 0;mode < SHADERMODE_COUNT;mode++) for (permutation = 0;permutation < SHADERPERMUTATION_LIMIT;permutation++) if (r_glsl_permutations[mode][permutation].program) @@ -1446,7 +1495,7 @@ void R_GLSL_DumpShader_f(void) Con_Printf("glsl/default.glsl written\n"); } -void R_SetupShader_SetPermutation(shadermode_t mode, unsigned int permutation) +void R_SetupShader_SetPermutation(unsigned int mode, unsigned int permutation) { r_glsl_permutation_t *perm = &r_glsl_permutations[mode][permutation]; if (r_glsl_permutation != perm) @@ -1545,7 +1594,7 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f // minimum features necessary to avoid wasting rendering time in the // fragment shader on features that are not being used unsigned int permutation = 0; - shadermode_t mode = 0; + unsigned int mode = 0; // TODO: implement geometry-shader based shadow volumes someday if (r_glsl_offsetmapping.integer) { @@ -1727,7 +1776,7 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_refdef.lightmapintensity * specularscale); } if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2], rsurface.texture->lightmapcolor[3]); - if (r_glsl_permutation->loc_GlowScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_GlowScale, r_hdr_glowintensity.value); + if (r_glsl_permutation->loc_GlowScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_GlowScale, r_hdr_glowintensity.value); // additive passes are only darkened by fog, not tinted if (r_glsl_permutation->loc_FogColor >= 0) { @@ -1787,13 +1836,14 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f #define SKINFRAME_HASH 1024 -struct +typedef struct { int loadsequence; // incremented each level change memexpandablearray_t array; skinframe_t *hash[SKINFRAME_HASH]; } -r_skinframe; +r_skinframe_t; +r_skinframe_t r_skinframe; void R_SkinFrame_PrepareForPurge(void) { @@ -2217,7 +2267,7 @@ skinframe_t *R_SkinFrame_LoadMissing(void) if (cls.state == ca_dedicated) return NULL; - skinframe = R_SkinFrame_Find("missing", TEXF_PRECACHE, 0, 0, 0, true); + skinframe = R_SkinFrame_Find("missing", TEXF_PRECACHE | TEXF_FORCENEAREST, 0, 0, 0, true); skinframe->stain = NULL; skinframe->merged = NULL; skinframe->base = r_texture_notexture; @@ -2238,6 +2288,10 @@ skinframe_t *R_SkinFrame_LoadMissing(void) void gl_main_start(void) { + r_numqueries = 0; + r_maxqueries = 0; + memset(r_queries, 0, sizeof(r_queries)); + memset(r_qwskincache, 0, sizeof(r_qwskincache)); memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe)); @@ -2265,8 +2319,16 @@ void gl_main_start(void) r_refdef.fogmasktable_density = 0; } +extern rtexture_t *loadingscreentexture; void gl_main_shutdown(void) { + if (r_maxqueries) + qglDeleteQueriesARB(r_maxqueries, r_queries); + + r_numqueries = 0; + r_maxqueries = 0; + memset(r_queries, 0, sizeof(r_queries)); + memset(r_qwskincache, 0, sizeof(r_qwskincache)); memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe)); @@ -2278,6 +2340,7 @@ void gl_main_shutdown(void) Mem_Free(r_svbsp.nodes); memset(&r_svbsp, 0, sizeof (r_svbsp)); R_FreeTexturePool(&r_main_texturepool); + loadingscreentexture = NULL; r_texture_blanknormalmap = NULL; r_texture_white = NULL; r_texture_grey128 = NULL; @@ -2335,6 +2398,15 @@ void GL_Main_Init(void) Cvar_RegisterVariable (&gl_fogend); Cvar_RegisterVariable (&gl_skyclip); } + Cvar_RegisterVariable(&r_motionblur); + Cvar_RegisterVariable(&r_motionblur_maxblur); + Cvar_RegisterVariable(&r_motionblur_bmin); + Cvar_RegisterVariable(&r_motionblur_vmin); + Cvar_RegisterVariable(&r_motionblur_vmax); + Cvar_RegisterVariable(&r_motionblur_vcoeff); + Cvar_RegisterVariable(&r_motionblur_randomize); + Cvar_RegisterVariable(&r_damageblur); + Cvar_RegisterVariable(&r_animcache); Cvar_RegisterVariable(&r_depthfirst); Cvar_RegisterVariable(&r_useinfinitefarclip); Cvar_RegisterVariable(&r_nearclip); @@ -2405,6 +2477,7 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&gl_lightmaps); Cvar_RegisterVariable(&r_test); Cvar_RegisterVariable(&r_batchmode); + Cvar_RegisterVariable(&r_glsl_saturation); if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE) Cvar_SetValue("r_fullbrights", 0); R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap); @@ -2465,8 +2538,8 @@ void GL_Init (void) Con_Printf("GL_VENDOR: %s\n", gl_vendor); Con_Printf("GL_RENDERER: %s\n", gl_renderer); Con_Printf("GL_VERSION: %s\n", gl_version); - Con_Printf("GL_EXTENSIONS: %s\n", gl_extensions); - Con_Printf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions); + Con_DPrintf("GL_EXTENSIONS: %s\n", gl_extensions); + Con_DPrintf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions); VID_CheckExtensions(); @@ -2578,6 +2651,197 @@ int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, c //================================================================================== +// LordHavoc: animcache written by Echon, refactored and reformatted by me + +/** + * Animation cache helps save re-animating a player mesh if it's re-rendered again in a given frame + * (reflections, lighting, etc). All animation cache becomes invalid on the next frame and is flushed + * (well, over-wrote). The memory for each cache is kept around to save on allocation thrashing. + */ + +typedef struct r_animcache_entity_s +{ + float *vertex3f; + float *normal3f; + float *svector3f; + float *tvector3f; + int maxvertices; + qboolean wantnormals; + qboolean wanttangents; +} +r_animcache_entity_t; + +typedef struct r_animcache_s +{ + r_animcache_entity_t entity[MAX_EDICTS*2]; + int maxindex; + int currentindex; +} +r_animcache_t; + +static r_animcache_t r_animcachestate; + +void R_AnimCache_Free(void) +{ + int idx; + for (idx=0 ; idxmaxvertices >= numvertices) + return; + + // Release existing memory + if (cache->vertex3f) + Mem_Free(cache->vertex3f); + + // Pad by 1024 verts + cache->maxvertices = (numvertices + 1023) & ~1023; + arraySize = cache->maxvertices * 3; + + // Allocate, even if we don't need this memory in this instance it will get ignored and potentially used later + base = (float *)Mem_Alloc(r_main_mempool, arraySize * sizeof(float) * 4); + r_animcachestate.entity[cacheIdx].vertex3f = base; + r_animcachestate.entity[cacheIdx].normal3f = base + arraySize; + r_animcachestate.entity[cacheIdx].svector3f = base + arraySize*2; + r_animcachestate.entity[cacheIdx].tvector3f = base + arraySize*3; + +// Con_Printf("allocated cache for %i (%f KB)\n", cacheIdx, (arraySize*sizeof(float)*4)/1024.0f); +} + +void R_AnimCache_NewFrame(void) +{ + int i; + + if (r_animcache.integer && r_drawentities.integer) + r_animcachestate.maxindex = sizeof(r_animcachestate.entity) / sizeof(r_animcachestate.entity[0]); + else if (r_animcachestate.maxindex) + R_AnimCache_Free(); + + r_animcachestate.currentindex = 0; + + for (i = 0;i < r_refdef.scene.numentities;i++) + r_refdef.scene.entities[i]->animcacheindex = -1; +} + +qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents) +{ + dp_model_t *model = ent->model; + r_animcache_entity_t *c; + // see if it's already cached this frame + if (ent->animcacheindex >= 0) + { + // add normals/tangents if needed + c = r_animcachestate.entity + ent->animcacheindex; + if (c->wantnormals) + wantnormals = false; + if (c->wanttangents) + wanttangents = false; + if (wantnormals || wanttangents) + model->AnimateVertices(model, ent->frameblend, NULL, wantnormals ? c->normal3f : NULL, wanttangents ? c->svector3f : NULL, wanttangents ? c->tvector3f : NULL); + } + else + { + // see if this ent is worth caching + if (r_animcachestate.maxindex <= r_animcachestate.currentindex) + return false; + if (!model || !model->Draw || !model->surfmesh.isanimated || !model->AnimateVertices || (ent->frameblend[0].lerp == 1 && ent->frameblend[0].subframe == 0)) + return false; + // assign it a cache entry and make sure the arrays are big enough + R_AnimCache_ResizeEntityCache(r_animcachestate.currentindex, model->surfmesh.num_vertices); + ent->animcacheindex = r_animcachestate.currentindex++; + c = r_animcachestate.entity + ent->animcacheindex; + c->wantnormals = wantnormals; + c->wanttangents = wanttangents; + model->AnimateVertices(model, ent->frameblend, c->vertex3f, wantnormals ? c->normal3f : NULL, wanttangents ? c->svector3f : NULL, wanttangents ? c->tvector3f : NULL); + } + return true; +} + +void R_AnimCache_CacheVisibleEntities(void) +{ + int i; + qboolean wantnormals; + qboolean wanttangents; + + if (!r_animcachestate.maxindex) + return; + + wantnormals = !r_showsurfaces.integer; + wanttangents = !r_showsurfaces.integer && (r_glsl.integer || r_refdef.scene.rtworld || r_refdef.scene.rtdlight); + + // TODO: thread this? + + for (i = 0;i < r_refdef.scene.numentities;i++) + { + if (!r_refdef.viewcache.entityvisible[i]) + continue; + R_AnimCache_GetEntity(r_refdef.scene.entities[i], wantnormals, wanttangents); + } +} + +//================================================================================== + +static void R_View_UpdateEntityLighting (void) +{ + int i; + entity_render_t *ent; + vec3_t tempdiffusenormal; + + for (i = 0;i < r_refdef.scene.numentities;i++) + { + ent = r_refdef.scene.entities[i]; + + // skip unseen models + if (!r_refdef.viewcache.entityvisible[i] && r_shadows.integer != 1) + continue; + + // skip bsp models + if (ent->model && ent->model->brush.num_leafs) + { + // TODO: use modellight for r_ambient settings on world? + VectorSet(ent->modellight_ambient, 0, 0, 0); + VectorSet(ent->modellight_diffuse, 0, 0, 0); + VectorSet(ent->modellight_lightdir, 0, 0, 1); + continue; + } + + // fetch the lighting from the worldmodel data + VectorSet(ent->modellight_ambient, r_refdef.scene.ambient * (2.0f / 128.0f), r_refdef.scene.ambient * (2.0f / 128.0f), r_refdef.scene.ambient * (2.0f / 128.0f)); + VectorClear(ent->modellight_diffuse); + VectorClear(tempdiffusenormal); + if ((ent->flags & RENDER_LIGHT) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint) + { + vec3_t org; + Matrix4x4_OriginFromMatrix(&ent->matrix, org); + r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal); + } + 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); + if(VectorLength2(ent->modellight_lightdir) == 0) + VectorSet(ent->modellight_lightdir, 0, 0, 1); // have to set SOME valid vector here + VectorNormalize(ent->modellight_lightdir); + } +} + static void R_View_UpdateEntityVisible (void) { int i, renderimask; @@ -2625,7 +2889,7 @@ static void R_View_UpdateEntityVisible (void) } } -// only used if skyrendermasked, and normally returns false +/// only used if skyrendermasked, and normally returns false int R_DrawBrushModelsSky (void) { int i, sky; @@ -2884,6 +3148,7 @@ void R_View_Update(void) R_View_SetFrustum(); R_View_WorldVisibility(r_refdef.view.useclipplane); R_View_UpdateEntityVisible(); + R_View_UpdateEntityLighting(); } void R_SetupView(qboolean allowwaterclippingplane) @@ -2966,7 +3231,8 @@ void R_ResetViewRendering3D(void) R_SetupGenericShader(true); } -void R_RenderScene(qboolean addwaterplanes); +void R_RenderScene(void); +void R_RenderWaterPlanes(void); static void R_Water_StartFrame(void) { @@ -3029,7 +3295,7 @@ static void R_Water_StartFrame(void) r_waterstate.numwaterplanes = 0; } -static void R_Water_AddWaterPlane(msurface_t *surface) +void R_Water_AddWaterPlane(msurface_t *surface) { int triangleindex, planeindex; const int *e; @@ -3038,6 +3304,7 @@ static void R_Water_AddWaterPlane(msurface_t *surface) vec3_t center; mplane_t plane; r_waterstate_waterplane_t *p; + texture_t *t = R_GetCurrentTexture(surface->texture); // just use the first triangle with a valid normal for any decisions VectorClear(normal); for (triangleindex = 0, e = rsurface.modelelement3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3) @@ -3057,7 +3324,7 @@ static void R_Water_AddWaterPlane(msurface_t *surface) if (PlaneDiff(r_refdef.view.origin, &plane) < 0) { // skip backfaces (except if nocullface is set) - if (!(surface->texture->currentframe->currentmaterialflags & MATERIALFLAG_NOCULLFACE)) + if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE)) return; VectorNegate(plane.normal, plane.normal); plane.dist *= -1; @@ -3083,7 +3350,7 @@ static void R_Water_AddWaterPlane(msurface_t *surface) p->pvsvalid = false; } // merge this surface's materialflags into the waterplane - p->materialflags |= surface->texture->currentframe->currentmaterialflags; + p->materialflags |= t->currentmaterialflags; // merge this surface's PVS into the waterplane VectorMAM(0.5f, surface->mins, 0.5f, surface->maxs, center); if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS @@ -3097,6 +3364,7 @@ static void R_Water_AddWaterPlane(msurface_t *surface) static void R_Water_ProcessPlanes(void) { r_refdef_view_t originalview; + r_refdef_view_t myview; int planeindex; r_waterstate_waterplane_t *p; @@ -3123,24 +3391,29 @@ static void R_Water_ProcessPlanes(void) } // render views + r_refdef.view = originalview; + r_refdef.view.showdebug = false; + r_refdef.view.width = r_waterstate.waterwidth; + r_refdef.view.height = r_waterstate.waterheight; + r_refdef.view.useclipplane = true; + myview = r_refdef.view; + r_waterstate.renderingscene = true; for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++) { - r_refdef.view.showdebug = false; - r_refdef.view.width = r_waterstate.waterwidth; - r_refdef.view.height = r_waterstate.waterheight; - r_refdef.view.useclipplane = true; - r_waterstate.renderingscene = true; - // render the normal view scene and copy into texture // (except that a clipping plane should be used to hide everything on one side of the water, and the viewer's weapon model should be omitted) if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION)) { + r_refdef.view = myview; r_refdef.view.clipplane = p->plane; VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal); r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist; PlaneClassify(&r_refdef.view.clipplane); - R_RenderScene(false); + R_ResetViewRendering3D(); + R_ClearScreen(r_refdef.fogenabled); + R_View_Update(); + R_RenderScene(); // copy view into the screen texture R_Mesh_TexBind(0, R_GetTexture(p->texture_refraction)); @@ -3151,6 +3424,7 @@ static void R_Water_ProcessPlanes(void) if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)) { + r_refdef.view = myview; // render reflected scene and copy into texture Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2); // update the r_refdef.view.origin because otherwise the sky renders at the wrong location (amongst other problems) @@ -3170,26 +3444,20 @@ static void R_Water_ProcessPlanes(void) R_ResetViewRendering3D(); R_ClearScreen(r_refdef.fogenabled); - if (r_timereport_active) - R_TimeReport("viewclear"); - - R_RenderScene(false); + R_View_Update(); + R_RenderScene(); R_Mesh_TexBind(0, R_GetTexture(p->texture_reflection)); GL_ActiveTexture(0); CHECKGLERROR qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR - - R_ResetViewRendering3D(); - R_ClearScreen(r_refdef.fogenabled); - if (r_timereport_active) - R_TimeReport("viewclear"); } - - r_refdef.view = originalview; - r_refdef.view.clear = true; - r_waterstate.renderingscene = false; } + r_waterstate.renderingscene = false; + r_refdef.view = originalview; + R_ResetViewRendering3D(); + R_ClearScreen(r_refdef.fogenabled); + R_View_Update(); return; error: r_refdef.view = originalview; @@ -3227,13 +3495,15 @@ void R_Bloom_StartFrame(void) for (bloomtextureheight = 1;bloomtextureheight < r_bloomstate.bloomheight;bloomtextureheight *= 2); } - if ((r_hdr.integer || r_bloom.integer) && ((r_bloom_resolution.integer < 4 || r_bloom_blur.value < 1 || r_bloom_blur.value >= 512) || r_refdef.view.width > gl_max_texture_size || r_refdef.view.height > gl_max_texture_size)) + if ((r_hdr.integer || r_bloom.integer || (!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))) && ((r_bloom_resolution.integer < 4 || r_bloom_blur.value < 1 || r_bloom_blur.value >= 512) || r_refdef.view.width > gl_max_texture_size || r_refdef.view.height > gl_max_texture_size)) { Cvar_SetValueQuick(&r_hdr, 0); Cvar_SetValueQuick(&r_bloom, 0); + Cvar_SetValueQuick(&r_motionblur, 0); + Cvar_SetValueQuick(&r_damageblur, 0); } - if (!(r_glsl.integer && (r_glsl_postprocess.integer || (v_glslgamma.integer && !vid_gammatables_trivial) || r_bloom.integer || r_hdr.integer)) && !r_bloom.integer) + if (!(r_glsl.integer && (r_glsl_postprocess.integer || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial))) && !r_bloom.integer && !r_hdr.integer && (R_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0))) screentexturewidth = screentextureheight = 0; if (!r_hdr.integer && !r_bloom.integer) bloomtexturewidth = bloomtextureheight = 0; @@ -3445,18 +3715,28 @@ void R_HDR_RenderBloomTexture(void) // 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 + // TODO: add fp16 framebuffer support (using GL_EXT_framebuffer_object) r_refdef.view.showdebug = false; r_refdef.view.colorscale *= r_bloom_colorscale.value / bound(1, r_hdr_range.value, 16); + R_ResetViewRendering3D(); + R_ClearScreen(r_refdef.fogenabled); if (r_timereport_active) R_TimeReport("HDRclear"); + R_View_Update(); + if (r_timereport_active) + R_TimeReport("visibility"); + r_waterstate.numwaterplanes = 0; - R_RenderScene(r_waterstate.enabled); + if (r_waterstate.enabled) + R_RenderWaterPlanes(); + r_refdef.view.showdebug = true; + R_RenderScene(); + r_waterstate.numwaterplanes = 0; R_ResetViewRendering2D(); @@ -3479,12 +3759,57 @@ static void R_BlendView(void) { if (r_bloomstate.texture_screen) { - // copy view into the screen texture + // make sure the buffer is available + if (r_bloom_blur.value < 1) { Cvar_SetValueQuick(&r_bloom_blur, 1); } + R_ResetViewRendering2D(); R_Mesh_VertexPointer(r_screenvertex3f, 0, 0); R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen)); GL_ActiveTexture(0);CHECKGLERROR + + if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0)) + { + // declare variables + float speed; + static float avgspeed; + + speed = VectorLength(cl.movement_velocity); + + cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_vcoeff.value), 1); + avgspeed = avgspeed * (1 - cl.motionbluralpha) + speed * cl.motionbluralpha; + + speed = (avgspeed - r_motionblur_vmin.value) / max(1, r_motionblur_vmax.value - r_motionblur_vmin.value); + speed = bound(0, speed, 1); + speed = speed * (1 - r_motionblur_bmin.value) + r_motionblur_bmin.value; + + // calculate values into a standard alpha + cl.motionbluralpha = 1 - exp(- + ( + (r_motionblur.value * speed / 80) + + + (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600)) + ) + / + max(0.0001, cl.time - cl.oldtime) // fps independent + ); + + cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value); + cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value); + // apply the blur + if (cl.motionbluralpha > 0) + { + R_SetupGenericShader(true); + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GL_Color(1, 1, 1, cl.motionbluralpha); + R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen)); + R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0); + R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0); + r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height; + } + } + + // copy view into the screen texture qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR r_refdef.stats.bloom_copypixels += r_refdef.view.width * r_refdef.view.height; } @@ -3495,7 +3820,8 @@ static void R_BlendView(void) (r_bloomstate.texture_bloom ? SHADERPERMUTATION_GLOW : 0) | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0) | ((v_glslgamma.value && !vid_gammatables_trivial) ? SHADERPERMUTATION_GAMMARAMPS : 0) - | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0); + | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0) + | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0); if (r_bloomstate.texture_bloom && !r_bloomstate.hdr) { @@ -3551,6 +3877,8 @@ static void R_BlendView(void) sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &a, &b, &c, &d); qglUniform4fARB(r_glsl_permutation->loc_UserVec4, a, b, c, d); } + if (r_glsl_permutation->loc_Saturation >= 0) + qglUniform1fARB(r_glsl_permutation->loc_Saturation, r_glsl_saturation.value); R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0); r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height; return; @@ -3623,8 +3951,6 @@ static void R_BlendView(void) } } -void R_RenderScene(qboolean addwaterplanes); - matrix4x4_t r_waterscrollmatrix; void R_UpdateFogColor(void) // needs to be called before HDR subrender too, as that changes colorscale! @@ -3672,7 +3998,7 @@ void R_UpdateVariables(void) r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1); r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1); - r_refdef.scene.rtworld = r_shadow_realtime_world.integer; + r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0; r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil; r_refdef.scene.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer && r_dynamic.integer; r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && gl_stencil; @@ -3746,7 +4072,7 @@ void R_UpdateVariables(void) // build GLSL gamma texture #define RAMPWIDTH 256 unsigned short ramp[RAMPWIDTH * 3]; - unsigned char ramprgb[RAMPWIDTH][4]; + unsigned char rampbgr[RAMPWIDTH][4]; int i; r_texture_gammaramps_serial = vid_gammatables_serial; @@ -3754,18 +4080,18 @@ void R_UpdateVariables(void) VID_BuildGammaTables(&ramp[0], RAMPWIDTH); for(i = 0; i < RAMPWIDTH; ++i) { - ramprgb[i][0] = ramp[i] >> 8; - ramprgb[i][1] = ramp[i + RAMPWIDTH] >> 8; - ramprgb[i][2] = ramp[i + 2 * RAMPWIDTH] >> 8; - ramprgb[i][3] = 0; + rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5); + rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5); + rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5); + rampbgr[i][3] = 0; } if (r_texture_gammaramps) { - R_UpdateTexture(r_texture_gammaramps, &ramprgb[0][0], 0, 0, RAMPWIDTH, 1); + R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, RAMPWIDTH, 1); } else { - r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &ramprgb[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, NULL); + r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, NULL); } } } @@ -3814,6 +4140,11 @@ R_RenderView */ void R_RenderView(void) { + r_frame++; // used only by R_GetCurrentTexture + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity + + R_AnimCache_NewFrame(); + if (r_refdef.view.isoverlay) { // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas] @@ -3825,7 +4156,7 @@ void R_RenderView(void) r_waterstate.enabled = false; r_waterstate.numwaterplanes = 0; - R_RenderScene(false); + R_RenderScene(); CHECKGLERROR return; @@ -3863,14 +4194,22 @@ void R_RenderView(void) } r_refdef.view.clear = true; - r_refdef.view.showdebug = true; - // this produces a bloom texture to be used in R_BlendView() later if (r_hdr.integer) R_HDR_RenderBloomTexture(); + r_refdef.view.showdebug = true; + + R_View_Update(); + if (r_timereport_active) + R_TimeReport("visibility"); + + r_waterstate.numwaterplanes = 0; + if (r_waterstate.enabled) + R_RenderWaterPlanes(); + + R_RenderScene(); r_waterstate.numwaterplanes = 0; - R_RenderScene(r_waterstate.enabled); R_BlendView(); if (r_timereport_active) @@ -3881,47 +4220,42 @@ void R_RenderView(void) CHECKGLERROR } -extern void R_DrawLightningBeams (void); -extern void VM_CL_AddPolygonsToMeshQueue (void); -extern void R_DrawPortals (void); -extern cvar_t cl_locs_show; -static void R_DrawLocs(void); -static void R_DrawEntityBBoxes(void); -void R_RenderScene(qboolean addwaterplanes) +void R_RenderWaterPlanes(void) { - r_refdef.stats.renders++; - - R_UpdateFogColor(); - - if (addwaterplanes) + if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes) { - R_ResetViewRendering3D(); - - R_View_Update(); + r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity); if (r_timereport_active) - R_TimeReport("watervis"); - - if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes) - { - r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity); - if (r_timereport_active) - R_TimeReport("waterworld"); - } + R_TimeReport("waterworld"); + } - // don't let sound skip if going slow - if (r_refdef.scene.extraupdate) - S_ExtraUpdate (); + // don't let sound skip if going slow + if (r_refdef.scene.extraupdate) + S_ExtraUpdate (); - R_DrawModelsAddWaterPlanes(); - if (r_timereport_active) - R_TimeReport("watermodels"); + R_DrawModelsAddWaterPlanes(); + if (r_timereport_active) + R_TimeReport("watermodels"); + if (r_waterstate.numwaterplanes) + { R_Water_ProcessPlanes(); if (r_timereport_active) R_TimeReport("waterscenes"); } +} - R_ResetViewRendering3D(); +extern void R_DrawLightningBeams (void); +extern void VM_CL_AddPolygonsToMeshQueue (void); +extern void R_DrawPortals (void); +extern cvar_t cl_locs_show; +static void R_DrawLocs(void); +static void R_DrawEntityBBoxes(void); +void R_RenderScene(void) +{ + r_refdef.stats.renders++; + + R_UpdateFogColor(); // don't let sound skip if going slow if (r_refdef.scene.extraupdate) @@ -3931,10 +4265,6 @@ void R_RenderScene(qboolean addwaterplanes) R_SkyStartFrame(); - R_View_Update(); - if (r_timereport_active) - R_TimeReport("visibility"); - Matrix4x4_CreateTranslate(&r_waterscrollmatrix, sin(r_refdef.scene.time) * 0.025 * r_waterscroll.value, sin(r_refdef.scene.time * 0.8f) * 0.025 * r_waterscroll.value, 0); if (cl.csqc_vidvars.drawworld) @@ -3954,6 +4284,8 @@ void R_RenderScene(qboolean addwaterplanes) R_TimeReport("bmodelsky"); } + R_AnimCache_CacheVisibleEntities(); + if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth) { r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity); @@ -4058,7 +4390,7 @@ void R_RenderScene(qboolean addwaterplanes) R_SetupGenericShader(true); - if (r_refdef.view.showdebug && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDebug && (r_showtris.value > 0 || r_shownormals.value > 0 || r_showcollisionbrushes.value > 0)) + if (r_refdef.view.showdebug && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDebug && (r_showtris.value > 0 || r_shownormals.value != 0 || r_showcollisionbrushes.value > 0)) { r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity); if (r_timereport_active) @@ -4335,6 +4667,7 @@ float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1}; void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, rtexture_t *fogtexture, qboolean depthdisable, qboolean depthshort, const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2, float cr, float cg, float cb, float ca) { + // NOTE: this must not call qglDepthFunc (see r_shadow.c, R_BeginCoronaQuery) thanks to ATI float fog = 1.0f; float vertex3f[12]; @@ -4344,14 +4677,6 @@ void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, rtexture_ R_Mesh_Matrix(&identitymatrix); GL_BlendFunc(blendfunc1, blendfunc2); - if(v_flipped_state) - { - scalex1 = -scalex1; - scalex2 = -scalex2; - GL_CullFace(r_refdef.view.cullface_front); - } - else - GL_CullFace(r_refdef.view.cullface_back); GL_CullFace(GL_NONE); GL_DepthMask(false); @@ -4539,20 +4864,76 @@ static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms) return (float)(parms[0] + parms[1] * f); } -void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) +void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags) { int w, h, idx; - int i; - dp_model_t *model = ent->model; float f; float tcmat[12]; - q3shaderinfo_layer_tcmod_t *tcmod; - - if (t->basematerialflags & MATERIALFLAG_NODRAW) + matrix4x4_t matrix, temp; + switch(tcmod->tcmod) { - t->currentmaterialflags = MATERIALFLAG_NODRAW; - return; + case Q3TCMOD_COUNT: + case Q3TCMOD_NONE: + if (currentmaterialflags & MATERIALFLAG_WATERSCROLL) + matrix = r_waterscrollmatrix; + else + matrix = identitymatrix; + break; + case Q3TCMOD_ENTITYTRANSLATE: + // this is used in Q3 to allow the gamecode to control texcoord + // scrolling on the entity, which is not supported in darkplaces yet. + Matrix4x4_CreateTranslate(&matrix, 0, 0, 0); + break; + case Q3TCMOD_ROTATE: + Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0); + Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * r_refdef.scene.time, 0, 0, 1); + Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0); + break; + case Q3TCMOD_SCALE: + Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1); + break; + case Q3TCMOD_SCROLL: + Matrix4x4_CreateTranslate(&matrix, tcmod->parms[0] * r_refdef.scene.time, tcmod->parms[1] * r_refdef.scene.time, 0); + break; + case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures) + w = (int) tcmod->parms[0]; + h = (int) tcmod->parms[1]; + f = r_refdef.scene.time / (tcmod->parms[2] * w * h); + f = f - floor(f); + idx = (int) floor(f * w * h); + Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0); + break; + case Q3TCMOD_STRETCH: + f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms); + Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f); + break; + case Q3TCMOD_TRANSFORM: + VectorSet(tcmat + 0, tcmod->parms[0], tcmod->parms[1], 0); + VectorSet(tcmat + 3, tcmod->parms[2], tcmod->parms[3], 0); + VectorSet(tcmat + 6, 0 , 0 , 1); + VectorSet(tcmat + 9, tcmod->parms[4], tcmod->parms[5], 0); + Matrix4x4_FromArray12FloatGL(&matrix, tcmat); + break; + case Q3TCMOD_TURBULENT: + // this is handled in the RSurf_PrepareVertices function + matrix = identitymatrix; + break; } + temp = *texmatrix; + Matrix4x4_Concat(texmatrix, &matrix, &temp); +} + +texture_t *R_GetCurrentTexture(texture_t *t) +{ + int i; + const entity_render_t *ent = rsurface.entity; + dp_model_t *model = ent->model; + q3shaderinfo_layer_tcmod_t *tcmod; + + if (t->update_lastrenderframe == r_frame && t->update_lastrenderentity == (void *)ent) + return t->currentframe; + t->update_lastrenderframe = r_frame; + t->update_lastrenderentity = (void *)ent; // switch to an alternate material if this is a q1bsp animated material { @@ -4573,7 +4954,7 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) { // use an alternate animation if the entity's frame is not 0, // and only if the texture has an alternate animation - if (ent->frame2 != 0 && t->anim_total[1]) + if (ent->framegroupblend[0].frame != 0 && t->anim_total[1]) t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(r_refdef.scene.time * 5.0f) % t->anim_total[1]) : 0]; else t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(r_refdef.scene.time * 5.0f) % t->anim_total[0]) : 0]; @@ -4593,12 +4974,12 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) } t->currentskinframe = r_qwskincache_skinframe[i]; if (t->currentskinframe == NULL) - t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes]; + t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->shadertime)) % t->numskinframes]; } else if (t->numskinframes >= 2) - t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes]; + t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->shadertime)) % t->numskinframes]; if (t->backgroundnumskinframes >= 2) - t->backgroundcurrentskinframe = t->backgroundskinframes[(int)(t->backgroundskinframerate * (cl.time - ent->frame2time)) % t->backgroundnumskinframes]; + t->backgroundcurrentskinframe = t->backgroundskinframes[(int)(t->backgroundskinframerate * (cl.time - ent->shadertime)) % t->backgroundnumskinframes]; t->currentmaterialflags = t->basematerialflags; t->currentalpha = ent->alpha; @@ -4640,70 +5021,21 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) // there is no tcmod if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL) + { t->currenttexmatrix = r_waterscrollmatrix; - - for (i = 0, tcmod = t->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++) + t->currentbackgroundtexmatrix = r_waterscrollmatrix; + } + else { - matrix4x4_t matrix; - switch(tcmod->tcmod) - { - case Q3TCMOD_COUNT: - case Q3TCMOD_NONE: - if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL) - matrix = r_waterscrollmatrix; - else - matrix = identitymatrix; - break; - case Q3TCMOD_ENTITYTRANSLATE: - // this is used in Q3 to allow the gamecode to control texcoord - // scrolling on the entity, which is not supported in darkplaces yet. - Matrix4x4_CreateTranslate(&matrix, 0, 0, 0); - break; - case Q3TCMOD_ROTATE: - Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0); - Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * r_refdef.scene.time, 0, 0, 1); - Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0); - break; - case Q3TCMOD_SCALE: - Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1); - break; - case Q3TCMOD_SCROLL: - Matrix4x4_CreateTranslate(&matrix, tcmod->parms[0] * r_refdef.scene.time, tcmod->parms[1] * r_refdef.scene.time, 0); - break; - case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures) - w = tcmod->parms[0]; - h = tcmod->parms[1]; - f = r_refdef.scene.time / (tcmod->parms[2] * w * h); - f = f - floor(f); - idx = floor(f * w * h); - Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0); - break; - case Q3TCMOD_STRETCH: - f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms); - Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f); - break; - case Q3TCMOD_TRANSFORM: - VectorSet(tcmat + 0, tcmod->parms[0], tcmod->parms[1], 0); - VectorSet(tcmat + 3, tcmod->parms[2], tcmod->parms[3], 0); - VectorSet(tcmat + 6, 0 , 0 , 1); - VectorSet(tcmat + 9, tcmod->parms[4], tcmod->parms[5], 0); - Matrix4x4_FromArray12FloatGL(&matrix, tcmat); - break; - case Q3TCMOD_TURBULENT: - // this is handled in the RSurf_PrepareVertices function - matrix = identitymatrix; - break; - } - // either replace or concatenate the transformation - if (i < 1) - t->currenttexmatrix = matrix; - else - { - matrix4x4_t temp = t->currenttexmatrix; - Matrix4x4_Concat(&t->currenttexmatrix, &matrix, &temp); - } + Matrix4x4_CreateIdentity(&t->currenttexmatrix); + Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix); } + for (i = 0, tcmod = t->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++) + R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags); + for (i = 0, tcmod = t->backgroundtcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++) + R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags); + t->colormapping = VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f); t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base; t->glosstexture = r_texture_black; @@ -4748,7 +5080,8 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) if (t->currentmaterialflags & MATERIALFLAG_WALL) { int layerflags = 0; - int blendfunc1, blendfunc2, depthmask; + int blendfunc1, blendfunc2; + qboolean depthmask; if (t->currentmaterialflags & MATERIALFLAG_ADD) { blendfunc1 = GL_SRC_ALPHA; @@ -4832,14 +5165,8 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) 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.view.colorscale, r_refdef.fogcolor[1] / r_refdef.view.colorscale, r_refdef.fogcolor[2] / r_refdef.view.colorscale, t->lightmapcolor[3]); } } -} -void R_UpdateAllTextureInfo(entity_render_t *ent) -{ - int i; - if (ent->model) - for (i = 0;i < ent->model->num_texturesperskin;i++) - R_UpdateTextureInfo(ent, ent->model->data_textures + i); + return t->currentframe; } rsurfacestate_t rsurface; @@ -4869,6 +5196,9 @@ void R_Mesh_ResizeArrays(int newvertices) void RSurf_ActiveWorldEntity(void) { dp_model_t *model = r_refdef.scene.worldmodel; + //if (rsurface.entity == r_refdef.scene.worldentity) + // return; + rsurface.entity = r_refdef.scene.worldentity; if (rsurface.array_size < model->surfmesh.num_vertices) R_Mesh_ResizeArrays(model->surfmesh.num_vertices); rsurface.matrix = identitymatrix; @@ -4880,14 +5210,8 @@ void RSurf_ActiveWorldEntity(void) VectorSet(rsurface.modellight_lightdir, 0, 0, 1); VectorSet(rsurface.colormap_pantscolor, 0, 0, 0); VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0); - rsurface.frameblend[0].frame = 0; + memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend)); rsurface.frameblend[0].lerp = 1; - rsurface.frameblend[1].frame = 0; - rsurface.frameblend[1].lerp = 0; - rsurface.frameblend[2].frame = 0; - rsurface.frameblend[2].lerp = 0; - rsurface.frameblend[3].frame = 0; - rsurface.frameblend[3].lerp = 0; rsurface.basepolygonfactor = r_refdef.polygonfactor; rsurface.basepolygonoffset = r_refdef.polygonoffset; rsurface.modelvertex3f = model->surfmesh.data_vertex3f; @@ -4938,6 +5262,9 @@ void RSurf_ActiveWorldEntity(void) void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents) { dp_model_t *model = ent->model; + //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents))) + // return; + rsurface.entity = (entity_render_t *)ent; if (rsurface.array_size < model->surfmesh.num_vertices) R_Mesh_ResizeArrays(model->surfmesh.num_vertices); rsurface.matrix = ent->matrix; @@ -4954,10 +5281,7 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q VectorCopy(ent->modellight_lightdir, rsurface.modellight_lightdir); VectorCopy(ent->colormap_pantscolor, rsurface.colormap_pantscolor); VectorCopy(ent->colormap_shirtcolor, rsurface.colormap_shirtcolor); - rsurface.frameblend[0] = ent->frameblend[0]; - rsurface.frameblend[1] = ent->frameblend[1]; - rsurface.frameblend[2] = ent->frameblend[2]; - rsurface.frameblend[3] = ent->frameblend[3]; + memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend)); rsurface.basepolygonfactor = r_refdef.polygonfactor; rsurface.basepolygonoffset = r_refdef.polygonoffset; if (ent->model->brush.submodel) @@ -4965,9 +5289,16 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value; rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value; } - if (model->surfmesh.isanimated && model->AnimateVertices && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].frame != 0)) + if (model->surfmesh.isanimated && model->AnimateVertices && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].subframe != 0)) { - if (wanttangents) + if (R_AnimCache_GetEntity((entity_render_t *)ent, wantnormals, wanttangents)) + { + rsurface.modelvertex3f = r_animcachestate.entity[ent->animcacheindex].vertex3f; + rsurface.modelsvector3f = wanttangents ? r_animcachestate.entity[ent->animcacheindex].svector3f : NULL; + rsurface.modeltvector3f = wanttangents ? r_animcachestate.entity[ent->animcacheindex].tvector3f : NULL; + rsurface.modelnormal3f = wantnormals ? r_animcachestate.entity[ent->animcacheindex].normal3f : NULL; + } + else if (wanttangents) { rsurface.modelvertex3f = rsurface.array_modelvertex3f; rsurface.modelsvector3f = rsurface.array_modelsvector3f; @@ -5083,7 +5414,7 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta rsurface.normal3f = rsurface.modelnormal3f = rsurface.array_modelnormal3f; rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject = 0; rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset = 0; - Mod_BuildNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer); + Mod_BuildNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer != 0); } if (generatetangents && !rsurface.modelsvector3f) { @@ -5093,7 +5424,7 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta rsurface.tvector3f = rsurface.modeltvector3f = rsurface.array_modeltvector3f; rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject = 0; rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset = 0; - Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f, r_smoothnormals_areaweighting.integer); + Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f, r_smoothnormals_areaweighting.integer != 0); } } rsurface.vertex3f = rsurface.modelvertex3f; @@ -5156,8 +5487,8 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3); } } - Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer); - Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer); + Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer != 0); + Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0); } rsurface.vertex3f = rsurface.array_deformedvertex3f; rsurface.vertex3f_bufferobject = 0; @@ -5248,8 +5579,8 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta VectorSubtract(end, start, up); VectorNormalize(up); // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector) - //VectorSubtract(rsurface.modelorg, center, forward); - Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward); + VectorSubtract(rsurface.modelorg, center, forward); + //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward); VectorNegate(forward, forward); VectorReflect(forward, 0, up, forward); VectorNormalize(forward); @@ -5287,8 +5618,8 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta VectorMAMAM(1, v1, -f, right, f, newright, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3); } } - Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer); - Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer); + Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer != 0); + Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0); } rsurface.vertex3f = rsurface.array_deformedvertex3f; rsurface.vertex3f_bufferobject = 0; @@ -5319,7 +5650,7 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta normal[2] += deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]); VectorNormalize(normal); } - Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer); + Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0); } rsurface.svector3f = rsurface.array_deformedsvector3f; rsurface.svector3f_bufferobject = 0; @@ -5429,12 +5760,28 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta float *out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex; for (j = 0;j < surface->num_vertices;j++, vertex += 3, normal += 3, out_tc += 2) { - float l, d, eyedir[3]; - VectorSubtract(rsurface.modelorg, vertex, eyedir); - l = 0.5f / VectorLength(eyedir); - d = DotProduct(normal, eyedir)*2; - out_tc[0] = 0.5f + (normal[1]*d - eyedir[1])*l; - out_tc[1] = 0.5f - (normal[2]*d - eyedir[2])*l; + // identical to Q3A's method, but executed in worldspace so + // carried models can be shiny too + + float viewer[3], d, reflected[3], worldreflected[3]; + + VectorSubtract(rsurface.modelorg, vertex, viewer); + // VectorNormalize(viewer); + + d = DotProduct(normal, viewer); + + reflected[0] = normal[0]*2*d - viewer[0]; + reflected[1] = normal[1]*2*d - viewer[1]; + reflected[2] = normal[2]*2*d - viewer[2]; + // note: this is proportinal to viewer, so we can normalize later + + Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected); + VectorNormalize(worldreflected); + + // note: this sphere map only uses world x and z! + // so positive and negative y will LOOK THE SAME. + out_tc[0] = 0.5 + 0.5 * worldreflected[1]; + out_tc[1] = 0.5 - 0.5 * worldreflected[2]; } } rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f; @@ -6096,6 +6443,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **t return; R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix); + R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix); R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap)); R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture)); R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture)); @@ -6128,7 +6476,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **t GL_Color(1, 1, 1, 1); R_Mesh_ColorPointer(NULL, 0, 0); - R_SetupSurfaceShader(vec3_origin, rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND); + R_SetupSurfaceShader(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND); if (r_glsl_permutation) { RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist); @@ -6151,7 +6499,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **t R_Mesh_TexBind(GL20TU_REFLECTION, R_GetTexture(r_texture_white)); // changed per surface } - R_SetupSurfaceShader(vec3_origin, rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE); + R_SetupSurfaceShader(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE); if (!r_glsl_permutation) return; @@ -6453,7 +6801,10 @@ static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, msurf R_SetupGenericShader(false); if(rsurface.texture && rsurface.texture->currentskinframe) + { memcpy(c, rsurface.texture->currentskinframe->avgcolor, sizeof(c)); + c[3] *= rsurface.texture->currentalpha; + } else { c[0] = 1; @@ -6545,7 +6896,22 @@ static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, msurf RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); } -static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth) +static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth) +{ + CHECKGLERROR + RSurf_SetupDepthAndCulling(); + if (r_showsurfaces.integer == 3) + R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth); + else if (r_glsl.integer && gl_support_fragment_shader) + R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth); + else if (gl_combine.integer && r_textureunits.integer >= 2) + R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist, writedepth); + else + R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist, writedepth); + CHECKGLERROR +} + +static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth) { CHECKGLERROR RSurf_SetupDepthAndCulling(); @@ -6573,7 +6939,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const // to a model, knowing that they are meaningless otherwise if (ent == r_refdef.scene.worldentity) RSurf_ActiveWorldEntity(); - else if ((ent->effects & EF_FULLBRIGHT) || (r_showsurfaces.integer && r_showsurfaces.integer != 3) || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f)) + else if (r_showsurfaces.integer && r_showsurfaces.integer != 3) RSurf_ActiveModelEntity(ent, false, false); else RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader); @@ -6583,8 +6949,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const j = i + 1; surface = rsurface.modelsurfaces + surfacelist[i]; texture = surface->texture; - R_UpdateTextureInfo(ent, texture); - rsurface.texture = texture->currentframe; + rsurface.texture = R_GetCurrentTexture(texture); rsurface.uselightmaptexture = surface->lightmaptexture != NULL; // scan ahead until we find a different texture endsurface = min(i + 1024, numsurfaces); @@ -6598,13 +6963,18 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const texturesurfacelist[texturenumsurfaces++] = surface; } // render the range of surfaces - R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false); + if (ent == r_refdef.scene.worldentity) + R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false); + else + R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false); } + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity GL_AlphaTest(false); } -static void R_ProcessTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity) +static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly) { + const entity_render_t *queueentity = r_refdef.scene.worldentity; CHECKGLERROR if (depthonly) { @@ -6666,23 +7036,113 @@ static void R_ProcessTextureSurfaceList(int texturenumsurfaces, msurface_t **tex else { // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier - R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)); + R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)); } CHECKGLERROR } -void R_QueueSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes) +void R_QueueWorldSurfaceList(int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly) { int i, j; texture_t *texture; - // if we're rendering water textures (extra scene renders), use a separate loop to avoid burdening the main one - if (addwaterplanes) + // break the surface list down into batches by texture and use of lightmapping + for (i = 0;i < numsurfaces;i = j) { - for (i = 0;i < numsurfaces;i++) - if (surfacelist[i]->texture->currentframe->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION)) - R_Water_AddWaterPlane(surfacelist[i]); + j = i + 1; + // texture is the base texture pointer, rsurface.texture is the + // current frame/skin the texture is directing us to use (for example + // if a model has 2 skins and it is on skin 1, then skin 0 tells us to + // use skin 1 instead) + texture = surfacelist[i]->texture; + rsurface.texture = R_GetCurrentTexture(texture); + rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL; + if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW)) + { + // if this texture is not the kind we want, skip ahead to the next one + for (;j < numsurfaces && texture == surfacelist[j]->texture;j++) + ; + continue; + } + // simply scan ahead until we find a different texture or lightmap state + for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++) + ; + // render the range of surfaces + R_ProcessWorldTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly); + } +} + +static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity) +{ + CHECKGLERROR + if (depthonly) + { + if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST))) + return; + if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))) + return; + RSurf_SetupDepthAndCulling(); + RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); + RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + } + else if (r_showsurfaces.integer && !r_refdef.view.showdebug) + { + RSurf_SetupDepthAndCulling(); + GL_AlphaTest(false); + R_Mesh_ColorPointer(NULL, 0, 0); + R_Mesh_ResetTextureState(); + R_SetupGenericShader(false); + RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); + GL_DepthMask(true); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_Color(0, 0, 0, 1); + GL_DepthTest(writedepth); + RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + } + else if (r_showsurfaces.integer && r_showsurfaces.integer != 3) + { + RSurf_SetupDepthAndCulling(); + GL_AlphaTest(false); + R_Mesh_ColorPointer(NULL, 0, 0); + R_Mesh_ResetTextureState(); + R_SetupGenericShader(false); + RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); + GL_DepthMask(true); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_DepthTest(true); + RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist); + } + else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) + R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist); + else if (!rsurface.texture->currentnumlayers) return; + else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))) && queueentity) + { + // transparent surfaces get pushed off into the transparent queue + int surfacelistindex; + const msurface_t *surface; + vec3_t tempcenter, center; + for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++) + { + surface = texturesurfacelist[surfacelistindex]; + tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f; + tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f; + tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f; + Matrix4x4_Transform(&rsurface.matrix, tempcenter, center); + R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_refdef.view.origin : center, R_DrawSurface_TransparentCallback, queueentity, surface - rsurface.modelsurfaces, rsurface.rtlight); + } } + else + { + // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier + R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)); + } + CHECKGLERROR +} + +void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly) +{ + int i, j; + texture_t *texture; // break the surface list down into batches by texture and use of lightmapping for (i = 0;i < numsurfaces;i = j) { @@ -6692,7 +7152,7 @@ void R_QueueSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surf // if a model has 2 skins and it is on skin 1, then skin 0 tells us to // use skin 1 instead) texture = surfacelist[i]->texture; - rsurface.texture = texture->currentframe; + rsurface.texture = R_GetCurrentTexture(texture); rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL; if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW)) { @@ -6705,7 +7165,7 @@ void R_QueueSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surf for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++) ; // render the range of surfaces - R_ProcessTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent); + R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent); } } @@ -6846,7 +7306,7 @@ void R_DrawDebugModel(entity_render_t *ent) { if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j]) continue; - rsurface.texture = surface->texture->currentframe; + rsurface.texture = R_GetCurrentTexture(surface->texture); if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles) { RSurf_PrepareVerticesForBatch(true, true, 1, &surface); @@ -6859,14 +7319,26 @@ void R_DrawDebugModel(entity_render_t *ent) else GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value); elements = (ent->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle); + R_Mesh_VertexPointer(rsurface.vertex3f, 0, 0); + R_Mesh_ColorPointer(NULL, 0, 0); + R_Mesh_TexCoordPointer(0, 0, NULL, 0, 0); + qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + //R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, ent->model->surfmesh.data_element3i, NULL, 0, 0); + R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject); + qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); CHECKGLERROR + } + if (r_shownormals.value < 0) + { qglBegin(GL_LINES); - for (k = 0;k < surface->num_triangles;k++, elements += 3) + for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++) { -#define GLVERTEXELEMENT(n) qglVertex3f(rsurface.vertex3f[elements[n]*3+0], rsurface.vertex3f[elements[n]*3+1], rsurface.vertex3f[elements[n]*3+2]) - GLVERTEXELEMENT(0);GLVERTEXELEMENT(1); - GLVERTEXELEMENT(1);GLVERTEXELEMENT(2); - GLVERTEXELEMENT(2);GLVERTEXELEMENT(0); + VectorCopy(rsurface.vertex3f + l * 3, v); + GL_Color(r_refdef.view.colorscale, 0, 0, 1); + qglVertex3f(v[0], v[1], v[2]); + VectorMA(v, -r_shownormals.value, rsurface.svector3f + l * 3, v); + GL_Color(r_refdef.view.colorscale, 1, 1, 1); + qglVertex3f(v[0], v[1], v[2]); } qglEnd(); CHECKGLERROR @@ -6919,7 +7391,7 @@ void R_DrawDebugModel(entity_render_t *ent) extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface); int r_maxsurfacelist = 0; msurface_t **r_surfacelist = NULL; -void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes, qboolean debug) +void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug) { int i, j, endj, f, flagsmask; texture_t *t; @@ -6935,7 +7407,7 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep r_maxsurfacelist = model->num_surfaces; if (r_surfacelist) Mem_Free(r_surfacelist); - r_surfacelist = Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist)); + r_surfacelist = (msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist)); } RSurf_ActiveWorldEntity(); @@ -6944,7 +7416,7 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep update = model->brushq1.lightmapupdateflags; // update light styles on this submodel - if (!skysurfaces && !depthonly && !addwaterplanes && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0) + if (!skysurfaces && !depthonly && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0) { model_brush_lightstyleinfo_t *style; for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++) @@ -6959,12 +7431,12 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep } } - R_UpdateAllTextureInfo(r_refdef.scene.worldentity); - flagsmask = addwaterplanes ? (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) : (skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL); + flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL; if (debug) { R_DrawDebugModel(r_refdef.scene.worldentity); + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity return; } @@ -6975,41 +7447,38 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep rsurface.rtlight = NULL; numsurfacelist = 0; // add visible surfaces to draw list - j = model->firstmodelsurface; - endj = j + model->nummodelsurfaces; - if (update) + for (i = 0;i < model->nummodelsurfaces;i++) { - for (;j < endj;j++) - { + j = model->sortedmodelsurfaces[i]; + if (r_refdef.viewcache.world_surfacevisible[j]) + r_surfacelist[numsurfacelist++] = surfaces + j; + } + // update lightmaps if needed + if (update) + for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++) if (r_refdef.viewcache.world_surfacevisible[j]) - { - r_surfacelist[numsurfacelist++] = surfaces + j; - // update lightmap if needed if (update[j]) R_BuildLightMap(r_refdef.scene.worldentity, surfaces + j); - } - } - } - else - for (;j < endj;j++) - if (r_refdef.viewcache.world_surfacevisible[j]) - r_surfacelist[numsurfacelist++] = surfaces + j; // don't do anything if there were no surfaces if (!numsurfacelist) + { + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity return; - R_QueueSurfaceList(r_refdef.scene.worldentity, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, addwaterplanes); + } + R_QueueWorldSurfaceList(numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly); GL_AlphaTest(false); // add to stats if desired - if (r_speeds.integer && !skysurfaces && !depthonly && !addwaterplanes) + if (r_speeds.integer && !skysurfaces && !depthonly) { r_refdef.stats.world_surfaces += numsurfacelist; for (j = 0;j < numsurfacelist;j++) r_refdef.stats.world_triangles += r_surfacelist[j]->num_triangles; } + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity } -void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes, qboolean debug) +void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug) { int i, j, endj, f, flagsmask; texture_t *t; @@ -7025,7 +7494,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr r_maxsurfacelist = model->num_surfaces; if (r_surfacelist) Mem_Free(r_surfacelist); - r_surfacelist = Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist)); + r_surfacelist = (msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist)); } // if the model is static it doesn't matter what value we give for @@ -7033,7 +7502,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr // to a model, knowing that they are meaningless otherwise if (ent == r_refdef.scene.worldentity) RSurf_ActiveWorldEntity(); - else if ((ent->effects & EF_FULLBRIGHT) || (r_showsurfaces.integer && r_showsurfaces.integer != 3) || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f)) + else if (r_showsurfaces.integer && r_showsurfaces.integer != 3) RSurf_ActiveModelEntity(ent, false, false); else RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader && !depthonly); @@ -7042,7 +7511,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr update = model->brushq1.lightmapupdateflags; // update light styles - if (!skysurfaces && !depthonly && !addwaterplanes && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0) + if (!skysurfaces && !depthonly && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0) { model_brush_lightstyleinfo_t *style; for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++) @@ -7057,12 +7526,12 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr } } - R_UpdateAllTextureInfo(ent); - flagsmask = addwaterplanes ? (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) : (skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL); + flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL; if (debug) { R_DrawDebugModel(ent); + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity return; } @@ -7073,27 +7542,28 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr rsurface.rtlight = NULL; numsurfacelist = 0; // add visible surfaces to draw list - j = model->firstmodelsurface; - endj = j + model->nummodelsurfaces; - for (;j < endj;j++) - r_surfacelist[numsurfacelist++] = surfaces + j; + for (i = 0;i < model->nummodelsurfaces;i++) + r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i]; // don't do anything if there were no surfaces if (!numsurfacelist) + { + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity return; + } // update lightmaps if needed if (update) - for (j = model->firstmodelsurface;j < endj;j++) + for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++) if (update[j]) R_BuildLightMap(ent, surfaces + j); - R_QueueSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, addwaterplanes); + R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly); GL_AlphaTest(false); // add to stats if desired - if (r_speeds.integer && !skysurfaces && !depthonly && !addwaterplanes) + if (r_speeds.integer && !skysurfaces && !depthonly) { - r_refdef.stats.entities++; r_refdef.stats.entities_surfaces += numsurfacelist; for (j = 0;j < numsurfacelist;j++) r_refdef.stats.entities_triangles += r_surfacelist[j]->num_triangles; } + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity }