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" };
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); when set to 2, always cast the shadows DOWN, otherwise use the model lighting"};
+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 in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
+cvar_t r_shadows_darken = {CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
+cvar_t r_shadows_throwdirection = {CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
+cvar_t r_shadows_drawafterrtlightning = {CVAR_SAVE, "r_shadows_drawafterrtlightning", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
+cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
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_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "2", "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
int basepixels_width;
int basepixels_height;
skinframe_t *skinframe;
- double avgcolor[5], w, wsum;
*has_alpha = false;
}
}
- avgcolor[0] = 0;
- avgcolor[1] = 0;
- avgcolor[2] = 0;
- avgcolor[3] = 0;
- avgcolor[4] = 0;
- wsum = 0;
- for(j = 0; j < basepixels_width * basepixels_height * 4; j += 4)
- {
- w = (int)basepixels[j + 0] + (int)basepixels[j + 1] + (int)basepixels[j + 2]; // use this weight, so black pixels don't contribute (needed for model skins)
- avgcolor[2] += basepixels[j + 0] * w;
- avgcolor[1] += basepixels[j + 1] * w;
- avgcolor[0] += basepixels[j + 2] * w;
- avgcolor[3] += basepixels[j + 3] * w;
- avgcolor[4] += basepixels[j + 3];
- wsum += w;
- }
- if(avgcolor[3] == 0) // just fully transparent pixels seen? bad luck...
- avgcolor[3] = 255.0 * wsum;
- if(avgcolor[3] == 0) // no pixels seen? even worse
- avgcolor[3] = 1;
- avgcolor[0] /= avgcolor[3];
- avgcolor[1] /= avgcolor[3];
- avgcolor[2] /= avgcolor[3];
- avgcolor[3] /= 255.0 * wsum; // to 0..1 range
- skinframe->avgcolor[0] = avgcolor[0];
- skinframe->avgcolor[1] = avgcolor[1];
- skinframe->avgcolor[2] = avgcolor[2];
- skinframe->avgcolor[3] = avgcolor[4] / (basepixels_width * 255.0 * basepixels_height);
+ 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)
int i;
unsigned char *temp1, *temp2;
skinframe_t *skinframe;
- double avgcolor[5], w, wsum;
- int j;
if (cls.state == ca_dedicated)
return NULL;
}
}
- avgcolor[0] = 0;
- avgcolor[1] = 0;
- avgcolor[2] = 0;
- avgcolor[3] = 0;
- avgcolor[4] = 0;
- wsum = 0;
- for(j = 0; j < width * height * 4; j += 4)
- {
- w = (int)skindata[j + 0] + (int)skindata[j + 1] + (int)skindata[j + 2];
- avgcolor[2] += skindata[j + 0] * w;
- avgcolor[1] += skindata[j + 1] * w;
- avgcolor[0] += skindata[j + 2] * w;
- avgcolor[3] += skindata[j + 3] * w;
- avgcolor[4] += skindata[j + 3];
- wsum += w;
- }
- if(avgcolor[3] == 0) // just fully transparent pixels seen? bad luck...
- avgcolor[3] = 255.0 * wsum;
- if(avgcolor[3] == 0) // no pixels seen? even worse
- avgcolor[3] = 1;
- avgcolor[0] /= avgcolor[3];
- avgcolor[1] /= avgcolor[3];
- avgcolor[2] /= avgcolor[3];
- avgcolor[3] /= 255.0 * wsum; // to 0..1 range
- skinframe->avgcolor[0] = avgcolor[0];
- skinframe->avgcolor[1] = avgcolor[1];
- skinframe->avgcolor[2] = avgcolor[2];
- skinframe->avgcolor[3] = avgcolor[4] / (width * 255.0 * height);
+ 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;
- double avgcolor[5], w, wsum;
- int j;
if (cls.state == ca_dedicated)
return NULL;
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
}
- avgcolor[0] = 0;
- avgcolor[1] = 0;
- avgcolor[2] = 0;
- avgcolor[3] = 0;
- avgcolor[4] = 0;
- wsum = 0;
- for(j = 0; j < width * height; ++j)
- {
- temp1 = ((unsigned char *)palette_bgra_alpha) + (skindata[j]*4);
- w = (int)temp1[0] + (int)temp1[1] + (int)temp1[2];
- avgcolor[2] += temp1[0] * w;
- avgcolor[1] += temp1[1] * w;
- avgcolor[0] += temp1[2] * w;
- avgcolor[3] += temp1[3] * w;
- avgcolor[4] += temp1[3];
- wsum += w;
- }
- if(avgcolor[3] == 0) // just fully transparent pixels seen? bad luck...
- avgcolor[3] = 255.0 * wsum;
- if(avgcolor[3] == 0) // no pixels seen? even worse
- avgcolor[3] = 1;
- avgcolor[0] /= avgcolor[3];
- avgcolor[1] /= avgcolor[3];
- avgcolor[2] /= avgcolor[3];
- avgcolor[3] /= 255.0 * wsum; // to 0..1 range
- skinframe->avgcolor[0] = avgcolor[0];
- skinframe->avgcolor[1] = avgcolor[1];
- skinframe->avgcolor[2] = avgcolor[2];
- skinframe->avgcolor[3] = avgcolor[4] / (width * 255.0 * height);
+ 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;
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_animcache);
Cvar_RegisterVariable(&r_depthfirst);
Cvar_RegisterVariable(&r_useinfinitefarclip);
Cvar_RegisterVariable(&r_nearclip);
Cvar_RegisterVariable(&r_dynamic);
Cvar_RegisterVariable(&r_fullbright);
Cvar_RegisterVariable(&r_shadows);
+ Cvar_RegisterVariable(&r_shadows_darken);
+ Cvar_RegisterVariable(&r_shadows_drawafterrtlightning);
+ Cvar_RegisterVariable(&r_shadows_castfrombmodels);
Cvar_RegisterVariable(&r_shadows_throwdistance);
+ Cvar_RegisterVariable(&r_shadows_throwdirection);
Cvar_RegisterVariable(&r_q1bsp_skymasking);
Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
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();
//==================================================================================
+// 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 ; idx<r_animcachestate.maxindex ; idx++)
+ {
+ r_animcachestate.entity[idx].maxvertices = 0;
+ Mem_Free(r_animcachestate.entity[idx].vertex3f);
+ r_animcachestate.entity[idx].vertex3f = NULL;
+ r_animcachestate.entity[idx].normal3f = NULL;
+ r_animcachestate.entity[idx].svector3f = NULL;
+ r_animcachestate.entity[idx].tvector3f = NULL;
+ }
+ r_animcachestate.currentindex = 0;
+ r_animcachestate.maxindex = 0;
+}
+
+void R_AnimCache_ResizeEntityCache(const int cacheIdx, const int numvertices)
+{
+ int arraySize;
+ float *base;
+ r_animcache_entity_t *cache = &r_animcachestate.entity[cacheIdx];
+
+ if (cache->maxvertices >= 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;
}
}
-// 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)
{
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_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;
// 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();
{
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;
}
(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)
{
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!
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;
// 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
+
+ R_AnimCache_NewFrame();
+
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_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);
if (r_refdef.scene.extraupdate)
S_ExtraUpdate ();
- if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
+ if (r_shadows.integer > 0 && !r_shadows_drawafterrtlightning.integer && r_refdef.lightmapintensity > 0)
{
R_DrawModelShadows();
-
R_ResetViewRendering3D();
-
// don't let sound skip if going slow
if (r_refdef.scene.extraupdate)
S_ExtraUpdate ();
if (r_refdef.scene.extraupdate)
S_ExtraUpdate ();
+ if (r_shadows.integer > 0 && r_shadows_drawafterrtlightning.integer && r_refdef.lightmapintensity > 0)
+ {
+ R_DrawModelShadows();
+ R_ResetViewRendering3D();
+ // don't let sound skip if going slow
+ if (r_refdef.scene.extraupdate)
+ S_ExtraUpdate ();
+ }
+
if (cl.csqc_vidvars.drawworld)
{
R_DrawLightningBeams();
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;
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;
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)
+ 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;
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)
{
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;
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;
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);
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;
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;
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;
{
int texturesurfaceindex;
int i;
- float f;
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)
{
- f = FogPoint_Model(v);
- c2[0] = 1;
- c2[1] = 1;
- c2[2] = 1;
+ c2[0] = 0.5;
+ c2[1] = 0.5;
+ c2[2] = 0.5;
c2[3] = 1;
}
}
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 / 64.0;
- c2[1] = c[1] + r_refdef.scene.ambient / 64.0;
- c2[2] = c[2] + r_refdef.scene.ambient / 64.0;
+ 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];
}
}
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));
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);
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;
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;
if (rsurface.texture->currentskinframe->pants || rsurface.texture->currentskinframe->shirt)
{
- c[0] = rsurface.colormap_pantscolor[0] * 0.2 + rsurface.colormap_shirtcolor[0] * 0.3;
- c[1] = rsurface.colormap_pantscolor[1] * 0.2 + rsurface.colormap_shirtcolor[1] * 0.3;
- c[2] = rsurface.colormap_pantscolor[2] * 0.2 + rsurface.colormap_shirtcolor[2] * 0.3;
+ 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")
GL_DepthMask(writedepth);
}
- rsurface.lightmapcolor4f = rsurface.modellightmapcolor4f;
- rsurface.lightmapcolor4f_bufferobject = rsurface.modellightmapcolor4f_bufferobject;
- rsurface.lightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset;
+ rsurface.lightmapcolor4f = NULL;
- if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
+ 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_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();
// 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);
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)
{
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)
{
- for (i = 0;i < numsurfaces;i++)
- if (surfacelist[i]->texture->currentframe->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION))
- R_Water_AddWaterPlane(surfacelist[i]);
+ 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)
{
// 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 && 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);
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
}