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 frame-by-frame alpha control {0 to 1} - 0.7 recommended"};
+cvar_t r_damageblur = {CVAR_SAVE, "r_damageblur", "0", "motionblur based on damage; requires r_motionblur to have a value"};
+cvar_t r_motionblur_vmin = {CVAR_SAVE, "r_motionblur_vmin", "300", "velocity at which there is minimum blur"};
+cvar_t r_motionblur_vmax = {CVAR_SAVE, "r_motionblur_vmax", "600", "velocity at which there is full blur"};
+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 the alpha level of the motion blur variable"};
+cvar_t r_motionblur_randomize = {CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to fix ghosting"};
+cvar_t r_motionblur_debug = {0, "r_motionblur_debug", "0", "outputs current motionblur alpha value"};
+
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" };
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 = {CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows DOWN, otherwise use the model lighting"};
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_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
cvar_t r_polygonoffset_submodel_factor = {0, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
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"};
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;
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;
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;
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,
"#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"
"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"
"#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"
"#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"
" 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"
" 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"
"#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"
" // 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"
" 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"
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;
{"#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;
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;
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;
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)
}
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;
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);
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)
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)
// 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)
{
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)
{
#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)
{
return item;
}
+#define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
+ { \
+ unsigned long long avgcolor[5], wsum; \
+ int pix, comp, w; \
+ avgcolor[0] = 0; \
+ avgcolor[1] = 0; \
+ avgcolor[2] = 0; \
+ avgcolor[3] = 0; \
+ avgcolor[4] = 0; \
+ wsum = 0; \
+ for(pix = 0; pix < cnt; ++pix) \
+ { \
+ w = 0; \
+ for(comp = 0; comp < 3; ++comp) \
+ w += getpixel; \
+ if(w) /* ignore perfectly black pixels because that is better for model skins */ \
+ { \
+ ++wsum; \
+ /* comp = 3; -- not needed, comp is always 3 when we get here */ \
+ w = getpixel; \
+ for(comp = 0; comp < 3; ++comp) \
+ avgcolor[comp] += getpixel * w; \
+ avgcolor[3] += w; \
+ } \
+ /* comp = 3; -- not needed, comp is always 3 when we get here */ \
+ avgcolor[4] += getpixel; \
+ } \
+ if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
+ avgcolor[3] = 1; \
+ skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
+ skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
+ skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
+ skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
+ }
+
skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int textureflags, qboolean complain, qboolean *has_alpha)
{
// FIXME: it should be possible to disable loading various layers using
}
}
+ R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
+ //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
+
// _norm is the name used by tenebrae and has been adopted as standard
if (loadnormalmap)
{
}
}
+ R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
+ //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
+
return skinframe;
}
{
int i;
unsigned char *temp1, *temp2;
+ unsigned int *palette;
skinframe_t *skinframe;
if (cls.state == ca_dedicated)
if (skinframe && skinframe->base)
return skinframe;
+ palette = (loadglowtexture ? palette_bgra_nofullbrights : ((skinframe->textureflags & TEXF_ALPHA) ? palette_bgra_transparent : palette_bgra_complete));
+
skinframe->stain = NULL;
skinframe->merged = NULL;
skinframe->base = r_texture_notexture;
Mem_Free(temp1);
}
// use either a custom palette, or the quake palette
- skinframe->base = skinframe->merged = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_merged", skinframe->basename), (loadglowtexture ? palette_bgra_nofullbrights : ((skinframe->textureflags & TEXF_ALPHA) ? palette_bgra_transparent : palette_bgra_complete)), skinframe->textureflags, true); // all
+ skinframe->base = skinframe->merged = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_merged", skinframe->basename), palette, skinframe->textureflags, true); // all
if (loadglowtexture)
skinframe->glow = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_glow", skinframe->basename), palette_bgra_onlyfullbrights, skinframe->textureflags, false); // glow
if (loadpantsandshirt)
skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), palette_bgra_alpha, skinframe->textureflags, true); // fog mask
}
+ R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
+ //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
+
return skinframe;
}
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;
skinframe->glow = NULL;
skinframe->fog = NULL;
+ skinframe->avgcolor[0] = rand() / RAND_MAX;
+ skinframe->avgcolor[1] = rand() / RAND_MAX;
+ skinframe->avgcolor[2] = rand() / RAND_MAX;
+ skinframe->avgcolor[3] = 1;
+
return skinframe;
}
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));
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));
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;
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_motionblur_debug);
Cvar_RegisterVariable(&r_depthfirst);
Cvar_RegisterVariable(&r_useinfinitefarclip);
Cvar_RegisterVariable(&r_nearclip);
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);
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();
//==================================================================================
+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;
}
}
-// only used if skyrendermasked, and normally returns false
+/// only used if skyrendermasked, and normally returns false
int R_DrawBrushModelsSky (void)
{
int i, sky;
R_View_SetFrustum();
R_View_WorldVisibility(r_refdef.view.useclipplane);
R_View_UpdateEntityVisible();
+ R_View_UpdateEntityLighting();
}
void R_SetupView(qboolean allowwaterclippingplane)
R_SetupGenericShader(true);
}
-void R_RenderScene(qboolean addwaterplanes);
+void R_RenderScene(void);
+void R_RenderWaterPlanes(void);
static void R_Water_StartFrame(void)
{
// calculate desired texture sizes
// can't use water if the card does not support the texture size
- if (!r_water.integer || !r_glsl.integer || !gl_support_fragment_shader || waterwidth > gl_max_texture_size || waterheight > gl_max_texture_size)
+ if (!r_water.integer || !r_glsl.integer || !gl_support_fragment_shader || waterwidth > gl_max_texture_size || waterheight > gl_max_texture_size || r_showsurfaces.integer)
texturewidth = textureheight = waterwidth = waterheight = 0;
else if (gl_support_arb_texture_non_power_of_two)
{
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;
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)
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;
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
static void R_Water_ProcessPlanes(void)
{
r_refdef_view_t originalview;
+ r_refdef_view_t myview;
int planeindex;
r_waterstate_waterplane_t *p;
}
// 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));
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)
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;
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_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_glsl_saturation.value != 1 || (v_glslgamma.integer && !vid_gammatables_trivial))) && !r_bloom.integer && !r_hdr.integer && r_motionblur.value <= 0 && r_damageblur.value <= 0)
screentexturewidth = screentextureheight = 0;
if (!r_hdr.integer && !r_bloom.integer)
bloomtexturewidth = bloomtextureheight = 0;
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();
{
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_motionblur.value > 0 || r_damageblur.value > 0)
+ {
+ // declare alpha variable
+ float a;
+ float speed;
+ static float avgspeed;
+
+ speed = VectorLength(cl.movement_velocity);
+
+ a = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_vcoeff.value), 1);
+ avgspeed = avgspeed * (1 - a) + speed * a;
+
+ 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
+ a = 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
+ );
+
+ a *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
+ a = bound(0, a, r_motionblur_maxblur.value);
+
+ // developer debug of current value
+ if (r_motionblur_debug.value) { Con_Printf("blur alpha = %f\n", a); }
+
+ // apply the blur
+ if (a > 0)
+ {
+ R_SetupGenericShader(true);
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GL_Color(1, 1, 1, a); // to do: add color changing support for damage blur
+ 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;
}
(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_glsl_saturation.value != 1 ? SHADERPERMUTATION_SATURATION : 0);
if (r_bloomstate.texture_bloom && !r_bloomstate.hdr)
{
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;
}
}
-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!
// 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;
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);
}
}
}
*/
void R_RenderView(void)
{
+ r_frame++; // used only by R_GetCurrentTexture
+ rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
+
if (r_refdef.view.isoverlay)
{
// TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
r_waterstate.enabled = false;
r_waterstate.numwaterplanes = 0;
- R_RenderScene(false);
+ R_RenderScene();
CHECKGLERROR
return;
}
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)
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)
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)
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)
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];
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);
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
{
{
// 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];
}
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;
// 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;
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;
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;
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;
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;
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)
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)
{
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);
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;
}
}
-static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, msurface_t **texturesurfacelist)
+static void RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(int texturenumsurfaces, msurface_t **texturesurfacelist)
{
int texturesurfaceindex;
int i;
- float f;
- float *v, *c, *c2;
+ float *v, *c2;
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+ for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c2 += 4)
+ {
+ c2[0] = 0.5;
+ c2[1] = 0.5;
+ c2[2] = 0.5;
+ c2[3] = 1;
+ }
+ }
+ rsurface.lightmapcolor4f = rsurface.array_color4f;
+ rsurface.lightmapcolor4f_bufferobject = 0;
+ rsurface.lightmapcolor4f_bufferoffset = 0;
+}
+
+static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, msurface_t **texturesurfacelist)
+{
+ int texturesurfaceindex;
+ int i;
+ float f;
+ float *v, *c, *c2;
if (rsurface.lightmapcolor4f)
{
// generate color arrays for the surfaces in this list
rsurface.lightmapcolor4f_bufferoffset = 0;
}
+static void RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(int texturenumsurfaces, msurface_t **texturesurfacelist)
+{
+ int texturesurfaceindex;
+ int i;
+ float f;
+ float *v, *c, *c2;
+ if (!rsurface.lightmapcolor4f)
+ return;
+ // generate color arrays for the surfaces in this list
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+ for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4)
+ {
+ f = FogPoint_Model(v);
+ c2[0] = c[0] * f + r_refdef.fogcolor[0] * (1 - f);
+ c2[1] = c[1] * f + r_refdef.fogcolor[1] * (1 - f);
+ c2[2] = c[2] * f + r_refdef.fogcolor[2] * (1 - f);
+ c2[3] = c[3];
+ }
+ }
+ rsurface.lightmapcolor4f = rsurface.array_color4f;
+ rsurface.lightmapcolor4f_bufferobject = 0;
+ rsurface.lightmapcolor4f_bufferoffset = 0;
+}
+
static void RSurf_DrawBatch_GL11_ApplyColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a)
{
int texturesurfaceindex;
rsurface.lightmapcolor4f_bufferoffset = 0;
}
+static void RSurf_DrawBatch_GL11_ApplyAmbient(int texturenumsurfaces, msurface_t **texturesurfacelist)
+{
+ int texturesurfaceindex;
+ int i;
+ float *c, *c2;
+ if (!rsurface.lightmapcolor4f)
+ return;
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+ for (i = 0, c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, c += 4, c2 += 4)
+ {
+ c2[0] = c[0] + r_refdef.scene.ambient / 128.0;
+ c2[1] = c[1] + r_refdef.scene.ambient / 128.0;
+ c2[2] = c[2] + r_refdef.scene.ambient / 128.0;
+ c2[3] = c[3];
+ }
+ }
+ rsurface.lightmapcolor4f = rsurface.array_color4f;
+ rsurface.lightmapcolor4f_bufferobject = 0;
+ rsurface.lightmapcolor4f_bufferoffset = 0;
+}
+
static void RSurf_DrawBatch_GL11_Lightmap(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
{
// TODO: optimize
RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
}
-static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
+static void RSurf_DrawBatch_GL11_ApplyVertexShade(int texturenumsurfaces, msurface_t **texturesurfacelist, float *r, float *g, float *b, float *a, qboolean *applycolor)
{
int texturesurfaceindex;
int i;
float f;
- float *v, *c, *c2;
+ float *v, *c, *c2, alpha;
vec3_t ambientcolor;
vec3_t diffusecolor;
vec3_t lightdir;
// model lighting
VectorCopy(rsurface.modellight_lightdir, lightdir);
f = 0.5f * r_refdef.lightmapintensity;
- ambientcolor[0] = rsurface.modellight_ambient[0] * r * f;
- ambientcolor[1] = rsurface.modellight_ambient[1] * g * f;
- ambientcolor[2] = rsurface.modellight_ambient[2] * b * f;
- diffusecolor[0] = rsurface.modellight_diffuse[0] * r * f;
- diffusecolor[1] = rsurface.modellight_diffuse[1] * g * f;
- diffusecolor[2] = rsurface.modellight_diffuse[2] * b * f;
- if (VectorLength2(diffusecolor) > 0)
+ ambientcolor[0] = rsurface.modellight_ambient[0] * *r * f;
+ ambientcolor[1] = rsurface.modellight_ambient[1] * *g * f;
+ ambientcolor[2] = rsurface.modellight_ambient[2] * *b * f;
+ diffusecolor[0] = rsurface.modellight_diffuse[0] * *r * f;
+ diffusecolor[1] = rsurface.modellight_diffuse[1] * *g * f;
+ diffusecolor[2] = rsurface.modellight_diffuse[2] * *b * f;
+ alpha = *a;
+ if (VectorLength2(diffusecolor) > 0 && rsurface.normal3f)
{
// generate color arrays for the surfaces in this list
for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
VectorMA(ambientcolor, f, diffusecolor, c);
else
VectorCopy(ambientcolor, c);
- c[3] = a;
+ c[3] = alpha;
}
}
- r = 1;
- g = 1;
- b = 1;
- a = 1;
- applycolor = false;
+ *r = 1;
+ *g = 1;
+ *b = 1;
+ *a = 1;
rsurface.lightmapcolor4f = rsurface.array_color4f;
rsurface.lightmapcolor4f_bufferobject = 0;
rsurface.lightmapcolor4f_bufferoffset = 0;
+ *applycolor = false;
}
else
{
- r = ambientcolor[0];
- g = ambientcolor[1];
- b = ambientcolor[2];
+ *r = ambientcolor[0];
+ *g = ambientcolor[1];
+ *b = ambientcolor[2];
rsurface.lightmapcolor4f = NULL;
rsurface.lightmapcolor4f_bufferobject = 0;
rsurface.lightmapcolor4f_bufferoffset = 0;
}
+}
+
+static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
+{
+ RSurf_DrawBatch_GL11_ApplyVertexShade(texturenumsurfaces, texturesurfacelist, &r, &g, &b, &a, &applycolor);
if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
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));
}
}
-static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth)
+static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth)
+{
+ float c[4];
+
+ GL_AlphaTest(false);
+ R_Mesh_ColorPointer(NULL, 0, 0);
+ R_Mesh_ResetTextureState();
+ 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;
+ c[1] = 0;
+ c[2] = 1;
+ c[3] = 1;
+ }
+
+ if (rsurface.texture->currentskinframe->pants || rsurface.texture->currentskinframe->shirt)
+ {
+ c[0] = 0.5 * (rsurface.colormap_pantscolor[0] * 0.3 + rsurface.colormap_shirtcolor[0] * 0.7);
+ c[1] = 0.5 * (rsurface.colormap_pantscolor[1] * 0.3 + rsurface.colormap_shirtcolor[1] * 0.7);
+ c[2] = 0.5 * (rsurface.colormap_pantscolor[2] * 0.3 + rsurface.colormap_shirtcolor[2] * 0.7);
+ }
+
+ // brighten it up (as texture value 127 means "unlit")
+ c[0] *= 2 * r_refdef.view.colorscale;
+ c[1] *= 2 * r_refdef.view.colorscale;
+ c[2] *= 2 * r_refdef.view.colorscale;
+
+ if(rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERALPHA)
+ c[3] *= r_wateralpha.value;
+
+ if(rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHA && c[3] != 1)
+ {
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GL_DepthMask(false);
+ }
+ else if(rsurface.texture->currentmaterialflags & MATERIALFLAG_ADD)
+ {
+ GL_BlendFunc(GL_ONE, GL_ONE);
+ GL_DepthMask(false);
+ }
+ else if(rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
+ {
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // can't do alpha test without texture, so let's blend instead
+ GL_DepthMask(false);
+ }
+ else if(rsurface.texture->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
+ {
+ GL_BlendFunc(rsurface.texture->customblendfunc[0], rsurface.texture->customblendfunc[1]);
+ GL_DepthMask(false);
+ }
+ else
+ {
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ GL_DepthMask(writedepth);
+ }
+
+ rsurface.lightmapcolor4f = NULL;
+
+ if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
+ {
+ RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
+
+ rsurface.lightmapcolor4f = NULL;
+ rsurface.lightmapcolor4f_bufferobject = 0;
+ rsurface.lightmapcolor4f_bufferoffset = 0;
+ }
+ else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
+ {
+ qboolean applycolor = true;
+ float one = 1.0;
+
+ RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
+
+ r_refdef.lightmapintensity = 1;
+ RSurf_DrawBatch_GL11_ApplyVertexShade(texturenumsurfaces, texturesurfacelist, &one, &one, &one, &one, &applycolor);
+ r_refdef.lightmapintensity = 0; // we're in showsurfaces, after all
+ }
+ else
+ {
+ RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
+
+ rsurface.lightmapcolor4f = rsurface.modellightmapcolor4f;
+ rsurface.lightmapcolor4f_bufferobject = rsurface.modellightmapcolor4f_bufferobject;
+ rsurface.lightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset;
+ }
+
+ if(!rsurface.lightmapcolor4f)
+ RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(texturenumsurfaces, texturesurfacelist);
+
+ RSurf_DrawBatch_GL11_ApplyAmbient(texturenumsurfaces, texturesurfacelist);
+ RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, c[0], c[1], c[2], c[3]);
+ if(r_refdef.fogenabled)
+ RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(texturenumsurfaces, texturesurfacelist);
+
+ R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
+ RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
+}
+
+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();
- if (r_glsl.integer && gl_support_fragment_shader)
+ 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);
// 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 || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
+ else if ((ent->effects & EF_FULLBRIGHT) || (r_showsurfaces.integer && r_showsurfaces.integer != 3) || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
RSurf_ActiveModelEntity(ent, false, false);
else
RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
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);
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)
{
RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
}
- else if (r_showsurfaces.integer)
+ else if (r_showsurfaces.integer && !r_refdef.view.showdebug)
{
RSurf_SetupDepthAndCulling();
- GL_DepthTest(true);
- GL_BlendFunc(GL_ONE, GL_ZERO);
+ 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);
- if (!r_refdef.view.showdebug)
- {
- GL_Color(0, 0, 0, 1);
- RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
- }
- else
- RSurf_DrawBatch_ShowSurfaces(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) && queueentity)
+ 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;
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)
+ {
+ 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)
{
- for (i = 0;i < numsurfaces;i++)
- if (surfacelist[i]->texture->currentframe->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION))
- R_Water_AddWaterPlane(surfacelist[i]);
+ 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)
{
// 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))
{
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);
}
}
{
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);
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
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;
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();
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++)
}
}
- 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;
}
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;
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
// 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 || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
+ else if ((ent->effects & EF_FULLBRIGHT) || (r_showsurfaces.integer && r_showsurfaces.integer != 3) || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
RSurf_ActiveModelEntity(ent, false, false);
else
RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader && !depthonly);
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++)
}
}
- 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;
}
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
}