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"};
+// TODO do we want a r_equalize_entities cvar that works on all ents, or would that be a cheat?
+cvar_t r_equalize_entities_fullbright = {CVAR_SAVE, "r_equalize_entities_fullbright", "0", "render fullbright entities by equalizing their lightness, not by not rendering light"};
+cvar_t r_equalize_entities_minambient = {CVAR_SAVE, "r_equalize_entities_minambient", "1", "light equalizing: ensure at least this ambient/diffuse ratio"};
+cvar_t r_equalize_entities_by = {CVAR_SAVE, "r_equalize_entities_by", "0.7", "light equalizing: exponent of dynamics compression (0 = no compression, 1 = full compression)"};
+cvar_t r_equalize_entities_to = {CVAR_SAVE, "r_equalize_entities_to", "0.8", "light equalizing: target light level"};
+
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_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_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "4", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
cvar_t r_fog_exp2 = {0, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
cvar_t r_drawfog = {CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
unsigned int r_numqueries;
unsigned int r_maxqueries;
-char r_qwskincache[MAX_SCOREBOARD][MAX_QPATH];
-skinframe_t *r_qwskincache_skinframe[MAX_SCOREBOARD];
+typedef struct r_qwskincache_s
+{
+ char name[MAX_QPATH];
+ skinframe_t *skinframe;
+}
+r_qwskincache_t;
+
+static r_qwskincache_t *r_qwskincache;
+static int r_qwskincache_size;
/// vertex coordinates for a quad that covers the screen exactly
const float r_screenvertex3f[12] =
r_refdef.fog_end = 0;
}
-float FogForDistance(vec_t dist)
-{
- unsigned int fogmasktableindex = (unsigned int)(dist * r_refdef.fogmasktabledistmultiplier);
- return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
-}
-
-float FogPoint_World(const vec3_t p)
-{
- return FogForDistance(VectorDistance((p), r_refdef.view.origin));
-}
-
-float FogPoint_Model(const vec3_t p)
-{
- return FogForDistance(VectorDistance((p), rsurface.modelorg) * Matrix4x4_ScaleFromMatrix(&rsurface.matrix));
-}
-
static void R_BuildBlankTextures(void)
{
unsigned char data[4];
static const char *builtinshaderstring =
"// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
"// written by Forest 'LordHavoc' Hale\n"
+"\n"
+"// enable various extensions depending on permutation:\n"
+"\n"
"#ifdef USESHADOWMAPRECT\n"
"# extension GL_ARB_texture_rectangle : enable\n"
"#endif\n"
"# endif\n"
"# ifdef GL_ARB_texture_gather\n"
"# extension GL_ARB_texture_gather : enable\n"
-"# define USETEXTUREGATHER\n"
"# else\n"
"# ifdef GL_AMD_texture_texture4\n"
"# extension GL_AMD_texture_texture4 : enable\n"
-"# define USETEXTUREGATHER\n"
-"# define textureGather texture4\n"
"# endif\n"
"# endif\n"
"#endif\n"
"# extension GL_EXT_gpu_shader4 : enable\n"
"#endif\n"
"\n"
+"#ifdef USESHADOWSAMPLER\n"
+"# extension GL_ARB_shadow : enable\n"
+"#endif\n"
+"\n"
"// common definitions between vertex shader and fragment shader:\n"
"\n"
"//#ifdef __GLSL_CG_DATA_TYPES\n"
"//# endif\n"
"//#endif\n"
"\n"
-"uniform myhalf GlowScale;\n"
+"uniform myhalf3 GlowColor;\n"
"uniform myhalf SceneBrightness;\n"
"\n"
"uniform float OffsetMapping_Scale;\n"
"#endif // USEOFFSETMAPPING\n"
"\n"
"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D) || defined(USESHADOWMAPCUBE)\n"
-"uniform vec4 ShadowMap_TextureScale;\n"
+"uniform vec2 ShadowMap_TextureScale;\n"
"uniform vec4 ShadowMap_Parameters;\n"
"#endif\n"
"\n"
" float ma;\n"
" if (adir.x > adir.y)\n"
" {\n"
-" if (adir.x > adir.z)\n"
+" if (adir.x > adir.z) // X\n"
" {\n"
" ma = adir.x;\n"
-" if (dir.x >= 0.0) { tc = vec2(-dir.z, -dir.y); offset = vec2(0.5, 0.5); } // +X\n"
-" else { tc = vec2( dir.z, -dir.y); offset = vec2(1.5, 0.5); } // -X\n"
+" tc = dir.zy;\n"
+" offset = vec2(mix(0.5, 1.5, dir.x < 0.0), 0.5);\n"
" }\n"
-" else\n"
+" else // Z\n"
" {\n"
" ma = adir.z;\n"
-" if (dir.z >= 0.0) { tc = vec2( dir.x, -dir.y); offset = vec2(0.5, 2.5); } // +Z\n"
-" else { tc = vec2(-dir.x, -dir.y); offset = vec2(1.5, 2.5); } // -Z\n"
+" tc = dir.xy;\n"
+" offset = vec2(mix(0.5, 1.5, dir.z < 0.0), 2.5);\n"
" }\n"
" }\n"
" else\n"
" {\n"
-" if (adir.y > adir.z)\n"
+" if (adir.y > adir.z) // Y\n"
" {\n"
" ma = adir.y;\n"
-" if (dir.y >= 0.0) { tc = vec2( dir.x, dir.z); offset = vec2(0.5, 1.5); } // +Y\n"
-" else { tc = vec2( dir.x, -dir.z); offset = vec2(1.5, 1.5); } // -Y\n"
+" tc = dir.xz;\n"
+" offset = vec2(mix(0.5, 1.5, dir.y < 0.0), 1.5);\n"
" }\n"
-" else\n"
+" else // Z\n"
" {\n"
" ma = adir.z;\n"
-" if (dir.z >= 0.0) { tc = vec2( dir.x, -dir.y); offset = vec2(0.5, 2.5); } // +Z\n"
-" else { tc = vec2(-dir.x, -dir.y); offset = vec2(1.5, 2.5); } // -Z\n"
+" tc = dir.xy;\n"
+" offset = vec2(mix(0.5, 1.5, dir.z < 0.0), 2.5);\n"
" }\n"
" }\n"
"\n"
-" vec3 stc = vec3(tc * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma + vec3(offset * ShadowMap_Parameters.y, ShadowMap_Parameters.z);\n"
-" stc.xy *= ShadowMap_TextureScale.xy;\n"
+" vec3 stc = vec3(tc * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma;\n"
+" stc.xy += offset * ShadowMap_Parameters.y;\n"
+" stc.z += ShadowMap_Parameters.z;\n"
+"# if showshadowmap\n"
+" stc.xy *= ShadowMap_TextureScale;\n"
+"# endif\n"
" return stc;\n"
"# else\n"
-" return vec3(textureCube(Texture_CubeProjection, dir.xyz).ra * ShadowMap_Parameters.xy, ShadowMap_Parameters.z + ShadowMap_Parameters.w / max(max(adir.x, adir.y), adir.z));\n"
+" vec4 proj = textureCube(Texture_CubeProjection, dir);\n"
+" float ma = max(max(adir.x, adir.y), adir.z);\n"
+" vec3 stc = vec3(mix(dir.xy, dir.zz, proj.xy) * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma;\n"
+" stc.xy += proj.zw * ShadowMap_Parameters.y;\n"
+" stc.z += ShadowMap_Parameters.z;\n"
+"# if showshadowmap\n"
+" stc.xy *= ShadowMap_TextureScale;\n"
+"# endif\n"
+" return stc;\n"
"# endif\n"
"}\n"
"#endif // defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D)\n"
"# else\n"
"\n"
"# ifdef USESHADOWMAPPCF\n"
-"# define texval(x, y) texture2DRect(Texture_ShadowMapRect, center + vec2(x, y)).r\n"
-"# if 1\n"
+"# if USESHADOWMAPPCF > 1\n"
+"# define texval(x, y) texture2DRect(Texture_ShadowMapRect, center + vec2(x, y)).r\n"
" vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n"
-" vec4 row1 = step(shadowmaptc.z, vec4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0))),\n"
-" row2 = step(shadowmaptc.z, vec4(texval(-1.0, 0.0), texval( 0.0, 0.0), texval( 1.0, 0.0), texval( 2.0, 0.0))),\n"
-" row3 = step(shadowmaptc.z, vec4(texval(-1.0, 1.0), texval( 0.0, 1.0), texval( 1.0, 1.0), texval( 2.0, 1.0))),\n"
-" row4 = step(shadowmaptc.z, vec4(texval(-1.0, 2.0), texval( 0.0, 2.0), texval( 1.0, 2.0), texval( 2.0, 2.0))),\n"
-" cols = row2 + row3 + mix(row1, row4, offset.y);\n"
+" vec4 row1 = step(shadowmaptc.z, vec4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0)));\n"
+" vec4 row2 = step(shadowmaptc.z, vec4(texval(-1.0, 0.0), texval( 0.0, 0.0), texval( 1.0, 0.0), texval( 2.0, 0.0)));\n"
+" vec4 row3 = step(shadowmaptc.z, vec4(texval(-1.0, 1.0), texval( 0.0, 1.0), texval( 1.0, 1.0), texval( 2.0, 1.0)));\n"
+" vec4 row4 = step(shadowmaptc.z, vec4(texval(-1.0, 2.0), texval( 0.0, 2.0), texval( 1.0, 2.0), texval( 2.0, 2.0)));\n"
+" vec4 cols = row2 + row3 + mix(row1, row4, offset.y);\n"
" f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n"
"# else\n"
+"# define texval(x, y) texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2(x, y)).r\n"
" vec2 offset = fract(shadowmaptc.xy);\n"
-" vec3 row1 = step(shadowmaptc.z, vec3(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0))),\n"
-" row2 = step(shadowmaptc.z, vec3(texval(-1.0, 0.0), texval( 0.0, 0.0), texval( 1.0, 0.0)))\n"
-" row3 = step(shadowmaptc.z, vec3(texval(-1.0, 1.0), texval( 0.0, 1.0), texval( 1.0, 1.0))),\n"
-" cols = row2 + mix(row1, row3, offset.y);\n"
+" vec3 row1 = step(shadowmaptc.z, vec3(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0)));\n"
+" vec3 row2 = step(shadowmaptc.z, vec3(texval(-1.0, 0.0), texval( 0.0, 0.0), texval( 1.0, 0.0)));\n"
+" vec3 row3 = step(shadowmaptc.z, vec3(texval(-1.0, 1.0), texval( 0.0, 1.0), texval( 1.0, 1.0)));\n"
+" vec3 cols = row2 + mix(row1, row3, offset.y);\n"
" f = dot(mix(cols.xy, cols.yz, offset.x), vec2(0.25));\n"
"# endif\n"
"# else\n"
"\n"
"# ifdef USESHADOWSAMPLER\n"
"# ifdef USESHADOWMAPPCF\n"
-"# ifdef GL_EXT_gpu_shader4\n"
-"# define texval(x, y) shadow2DOffset(Texture_ShadowMap2D, shadowmaptc, ivec2(x, y)).r\n"
-"# else\n"
-"# define texval(x, y) shadow2D(Texture_ShadowMap2D, vec3(shadowmaptc.xy + vec2(x, y)*ShadowMap_TextureScale.xy, shadowmaptc.z)).r \n"
-"# endif\n"
+"# define texval(x, y) shadow2D(Texture_ShadowMap2D, vec3(center + vec2(x, y)*ShadowMap_TextureScale, shadowmaptc.z)).r \n"
+" vec2 center = shadowmaptc.xy*ShadowMap_TextureScale;\n"
" f = dot(vec4(0.25), vec4(texval(-0.4, 1.0), texval(-1.0, -0.4), texval(0.4, -1.0), texval(1.0, 0.4)));\n"
"# else\n"
-" f = shadow2D(Texture_ShadowMap2D, shadowmaptc).r;\n"
+" f = shadow2D(Texture_ShadowMap2D, vec3(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z)).r;\n"
"# endif\n"
"# else\n"
"# ifdef USESHADOWMAPPCF\n"
-"# ifdef USETEXTUREGATHER\n"
-" vec2 center = shadowmaptc.xy*ShadowMap_TextureScale.zw - 0.5, offset = fract(center);\n"
-" vec4 group1 = step(shadowmaptc.z, textureGather(Texture_ShadowMap2D, (center + vec2(-1.0, -1.0))*ShadowMap_TextureScale.xy)),\n"
-" group2 = step(shadowmaptc.z, textureGather(Texture_ShadowMap2D, (center + vec2( 1.0, -1.0))*ShadowMap_TextureScale.xy)),\n"
-" group3 = step(shadowmaptc.z, textureGather(Texture_ShadowMap2D, (center + vec2(-1.0, 1.0))*ShadowMap_TextureScale.xy)),\n"
-" group4 = step(shadowmaptc.z, textureGather(Texture_ShadowMap2D, (center + vec2( 1.0, 1.0))*ShadowMap_TextureScale.xy)),\n"
-" cols = vec4(group1.rg, group2.rg) + vec4(group3.ab, group4.ab) +\n"
+"# if defined(GL_ARB_texture_gather) || defined(GL_AMD_texture_texture4)\n"
+"# ifdef GL_ARB_texture_gather\n"
+"# define texval(x, y) textureGatherOffset(Texture_ShadowMap2D, center, ivec(x, y))\n"
+"# else\n"
+"# define texval(x, y) texture4(Texture_ShadowMap2D, center + vec2(x,y)*ShadowMap_TextureScale)\n"
+"# endif\n"
+" vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n"
+" center *= ShadowMap_TextureScale;\n"
+" vec4 group1 = step(shadowmaptc.z, texval(-1.0, -1.0));\n"
+" vec4 group2 = step(shadowmaptc.z, texval( 1.0, -1.0));\n"
+" vec4 group3 = step(shadowmaptc.z, texval(-1.0, 1.0));\n"
+" vec4 group4 = step(shadowmaptc.z, texval( 1.0, 1.0));\n"
+" vec4 cols = vec4(group1.rg, group2.rg) + vec4(group3.ab, group4.ab) +\n"
" mix(vec4(group1.ab, group2.ab), vec4(group3.rg, group4.rg), offset.y);\n"
" f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n"
"# else\n"
-"# ifdef GL_EXT_gpu_shader4\n"
-" vec2 center = shadowmaptc.xy - 0.5*ShadowMap_TextureScale.xy, offset = fract(center*ShadowMap_TextureScale.zw);\n"
-"# define texval(x, y) texture2DOffset(Texture_ShadowMap2D, center, ivec2(x, y)).r\n"
-"# else\n"
-" vec2 center = shadowmaptc.xy*ShadowMap_TextureScale.zw - 0.5, offset = fract(center);\n"
-"# define texval(x, y) texture2D(Texture_ShadowMap2D, (center + vec2(x, y))*ShadowMap_TextureScale.xy).r \n"
-"# endif\n"
-" vec4 row1 = step(shadowmaptc.z, vec4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0))),\n"
-" row2 = step(shadowmaptc.z, vec4(texval(-1.0, 0.0), texval( 0.0, 0.0), texval( 1.0, 0.0), texval( 2.0, 0.0))),\n"
-" row3 = step(shadowmaptc.z, vec4(texval(-1.0, 1.0), texval( 0.0, 1.0), texval( 1.0, 1.0), texval( 2.0, 1.0))),\n"
-" row4 = step(shadowmaptc.z, vec4(texval(-1.0, 2.0), texval( 0.0, 2.0), texval( 1.0, 2.0), texval( 2.0, 2.0))),\n"
-" cols = row2 + row3 + mix(row1, row4, offset.y);\n"
+"# ifdef GL_EXT_gpu_shader4\n"
+"# define texval(x, y) texture2DOffset(Texture_ShadowMap2D, center, ivec2(x, y)).r\n"
+"# else\n"
+"# define texval(x, y) texture2D(Texture_ShadowMap2D, center + vec2(x, y)*ShadowMap_TextureScale).r \n"
+"# endif\n"
+"# if USESHADOWMAPPCF > 1\n"
+" vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n"
+" center *= ShadowMap_TextureScale;\n"
+" vec4 row1 = step(shadowmaptc.z, vec4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0)));\n"
+" vec4 row2 = step(shadowmaptc.z, vec4(texval(-1.0, 0.0), texval( 0.0, 0.0), texval( 1.0, 0.0), texval( 2.0, 0.0)));\n"
+" vec4 row3 = step(shadowmaptc.z, vec4(texval(-1.0, 1.0), texval( 0.0, 1.0), texval( 1.0, 1.0), texval( 2.0, 1.0)));\n"
+" vec4 row4 = step(shadowmaptc.z, vec4(texval(-1.0, 2.0), texval( 0.0, 2.0), texval( 1.0, 2.0), texval( 2.0, 2.0)));\n"
+" vec4 cols = row2 + row3 + mix(row1, row4, offset.y);\n"
" f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n"
+"# else\n"
+" vec2 center = shadowmaptc.xy*ShadowMap_TextureScale, offset = fract(shadowmaptc.xy);\n"
+" vec3 row1 = step(shadowmaptc.z, vec3(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0)));\n"
+" vec3 row2 = step(shadowmaptc.z, vec3(texval(-1.0, 0.0), texval( 0.0, 0.0), texval( 1.0, 0.0)));\n"
+" vec3 row3 = step(shadowmaptc.z, vec3(texval(-1.0, 1.0), texval( 0.0, 1.0), texval( 1.0, 1.0)));\n"
+" vec3 cols = row2 + mix(row1, row3, offset.y);\n"
+" f = dot(mix(cols.xy, cols.yz, offset.x), vec2(0.25));\n"
+"# endif\n"
"# endif\n"
"# else\n"
-" f = step(shadowmaptc.z, texture2D(Texture_ShadowMap2D, shadowmaptc.xy).r);\n"
+" f = step(shadowmaptc.z, texture2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale).r);\n"
"# endif\n"
"# endif\n"
" return f;\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"
+" color.rgb += myhalf3(texture2D(Texture_Glow, TexCoord)) * GlowColor;\n"
"#endif\n"
"#endif\n"
"\n"
SHADERPERMUTATION_SHADOWMAPRECT = 1<<11, ///< (lightsource) use shadowmap rectangle texture as light filter
SHADERPERMUTATION_SHADOWMAPCUBE = 1<<12, ///< (lightsource) use shadowmap cubemap texture as light filter
SHADERPERMUTATION_SHADOWMAP2D = 1<<13, ///< (lightsource) use shadowmap rectangle texture as light filter
- SHADERPERMUTATION_SHADOWMAPPCF = 1<<14, //< (lightsource) use percentage closer filtering on shadowmap test results
- SHADERPERMUTATION_SHADOWSAMPLER = 1<<15, //< (lightsource) use hardware shadowmap test
- SHADERPERMUTATION_SHADOWMAPVSDCT = 1<<16, //< (lightsource) use virtual shadow depth cube texture for shadowmap indexing
- SHADERPERMUTATION_LIMIT = 1<<17, ///< size of permutations array
- SHADERPERMUTATION_COUNT = 17 ///< size of shaderpermutationinfo array
+ SHADERPERMUTATION_SHADOWMAPPCF = 1<<14, ///< (lightsource) use percentage closer filtering on shadowmap test results
+ SHADERPERMUTATION_SHADOWMAPPCF2 = 1<<15, ///< (lightsource) use higher quality percentage closer filtering on shadowmap test results
+ SHADERPERMUTATION_SHADOWSAMPLER = 1<<16, ///< (lightsource) use hardware shadowmap test
+ SHADERPERMUTATION_SHADOWMAPVSDCT = 1<<17, ///< (lightsource) use virtual shadow depth cube texture for shadowmap indexing
+ SHADERPERMUTATION_LIMIT = 1<<18, ///< size of permutations array
+ SHADERPERMUTATION_COUNT = 18 ///< size of shaderpermutationinfo array
}
shaderpermutation_t;
{"#define USESHADOWMAPRECT\n", " shadowmaprect"},
{"#define USESHADOWMAPCUBE\n", " shadowmapcube"},
{"#define USESHADOWMAP2D\n", " shadowmap2d"},
- {"#define USESHADOWMAPPCF\n", " shadowmappcf"},
+ {"#define USESHADOWMAPPCF 1\n", " shadowmappcf"},
+ {"#define USESHADOWMAPPCF 2\n", " shadowmappcf2"},
{"#define USESHADOWSAMPLER\n", " shadowsampler"},
{"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"},
};
int loc_DiffuseScale;
int loc_SpecularScale;
int loc_SpecularPower;
- int loc_GlowScale;
+ int loc_GlowColor;
int loc_SceneBrightness; // or: Scenebrightness * ContrastBoost
int loc_OffsetMapping_Scale;
int loc_TintColor;
p->loc_DiffuseScale = qglGetUniformLocationARB(p->program, "DiffuseScale");
p->loc_SpecularPower = qglGetUniformLocationARB(p->program, "SpecularPower");
p->loc_SpecularScale = qglGetUniformLocationARB(p->program, "SpecularScale");
- p->loc_GlowScale = qglGetUniformLocationARB(p->program, "GlowScale");
+ p->loc_GlowColor = qglGetUniformLocationARB(p->program, "GlowColor");
p->loc_SceneBrightness = qglGetUniformLocationARB(p->program, "SceneBrightness");
p->loc_OffsetMapping_Scale = qglGetUniformLocationARB(p->program, "OffsetMapping_Scale");
p->loc_TintColor = qglGetUniformLocationARB(p->program, "TintColor");
extern qboolean r_shadow_usingshadowmaprect;
extern qboolean r_shadow_usingshadowmapcube;
extern qboolean r_shadow_usingshadowmap2d;
-extern float r_shadow_shadowmap_texturescale[4];
+extern float r_shadow_shadowmap_texturescale[2];
extern float r_shadow_shadowmap_parameters[4];
-extern int r_shadow_shadowmapvsdct;
-extern int r_shadow_shadowmapfilter;
+extern qboolean r_shadow_shadowmapvsdct;
+extern qboolean r_shadow_shadowmapsampler;
+extern int r_shadow_shadowmappcf;
void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass)
{
// select a permutation of the lighting shader appropriate to this
else if(r_shadow_shadowmapvsdct)
permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
- if (r_shadow_shadowmapfilter == 3)
- permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
- else if (r_shadow_shadowmapfilter == 2)
- permutation |= SHADERPERMUTATION_SHADOWMAPPCF | SHADERPERMUTATION_SHADOWSAMPLER;
- else if (r_shadow_shadowmapfilter == 1)
+ if (r_shadow_shadowmapsampler)
permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
+ if (r_shadow_shadowmappcf > 1)
+ permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
+ else if (r_shadow_shadowmappcf)
+ permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
}
}
else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
// additive passes are only darkened by fog, not tinted
if (r_glsl_permutation->loc_FogColor >= 0)
qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
- if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4fARB(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1], r_shadow_shadowmap_texturescale[2], r_shadow_shadowmap_texturescale[3]);
+ if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform2fARB(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4fARB(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
}
else
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_GlowColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_GlowColor, rsurface.glowmod[0] * r_hdr_glowintensity.value, rsurface.glowmod[1] * r_hdr_glowintensity.value, rsurface.glowmod[2] * r_hdr_glowintensity.value);
// additive passes are only darkened by fog, not tinted
if (r_glsl_permutation->loc_FogColor >= 0)
{
if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectOffset, rsurface.texture->reflectmin);
}
if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_refdef.view.colorscale);
- if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, rsurface.modelorg[0], rsurface.modelorg[1], rsurface.modelorg[2]);
+ if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
if (r_glsl_permutation->loc_Color_Pants >= 0)
{
if (rsurface.texture->currentskinframe->pants)
int basepixels_height;
skinframe_t *skinframe;
- *has_alpha = false;
+ if (has_alpha)
+ *has_alpha = false;
if (cls.state == ca_dedicated)
return NULL;
if (j < basepixels_width * basepixels_height * 4)
{
// has transparent pixels
- *has_alpha = true;
+ if (has_alpha)
+ *has_alpha = true;
pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
for (j = 0;j < image_width * image_height * 4;j += 4)
{
skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain)
{
- qboolean has_alpha;
- return R_SkinFrame_LoadExternal_CheckAlpha(name, textureflags, complain, &has_alpha);
+ return R_SkinFrame_LoadExternal_CheckAlpha(name, textureflags, complain, NULL);
}
static rtexture_t *R_SkinFrame_TextureForSkinLayer(const unsigned char *in, int width, int height, const char *name, const unsigned int *palette, int textureflags, qboolean force)
return skinframe;
}
+skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette)
+{
+ int i;
+ skinframe_t *skinframe;
+
+ if (cls.state == ca_dedicated)
+ return NULL;
+
+ // if already loaded just return it, otherwise make a new skinframe
+ skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
+ if (skinframe && skinframe->base)
+ return skinframe;
+
+ skinframe->stain = NULL;
+ skinframe->merged = NULL;
+ skinframe->base = r_texture_notexture;
+ skinframe->pants = NULL;
+ skinframe->shirt = NULL;
+ skinframe->nmap = r_texture_blanknormalmap;
+ skinframe->gloss = NULL;
+ skinframe->glow = NULL;
+ skinframe->fog = NULL;
+
+ // if no data was provided, then clearly the caller wanted to get a blank skinframe
+ if (!skindata)
+ return NULL;
+
+ if (developer_loading.integer)
+ Con_Printf("loading embedded 8bit image \"%s\"\n", name);
+
+ skinframe->base = skinframe->merged = R_SkinFrame_TextureForSkinLayer(skindata, width, height, skinframe->basename, palette, skinframe->textureflags, true);
+ if (textureflags & TEXF_ALPHA)
+ {
+ for (i = 0;i < width * height;i++)
+ if (((unsigned char *)alphapalette)[skindata[i]*4+3] < 255)
+ break;
+ if (i < width * height)
+ skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), alphapalette, skinframe->textureflags, true); // fog mask
+ }
+
+ R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
+ //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
+
+ return skinframe;
+}
+
skinframe_t *R_SkinFrame_LoadMissing(void)
{
skinframe_t *skinframe;
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_qwskincache = NULL;
+ r_qwskincache_size = 0;
// set up r_skinframe loading system for textures
memset(&r_skinframe, 0, sizeof(r_skinframe));
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_qwskincache = NULL;
+ r_qwskincache_size = 0;
// clear out the r_skinframe state
Mem_ExpandableArray_FreeArray(&r_skinframe.array);
// FIXME: move this code to client
int l;
char *entities, entname[MAX_QPATH];
+ if (r_qwskincache)
+ Mem_Free(r_qwskincache);
+ r_qwskincache = NULL;
+ r_qwskincache_size = 0;
if (cl.worldmodel)
{
strlcpy(entname, cl.worldmodel->name, sizeof(entname));
Cvar_RegisterVariable(&r_motionblur_vcoeff);
Cvar_RegisterVariable(&r_motionblur_randomize);
Cvar_RegisterVariable(&r_damageblur);
+ Cvar_RegisterVariable(&r_equalize_entities_fullbright);
+ Cvar_RegisterVariable(&r_equalize_entities_minambient);
+ Cvar_RegisterVariable(&r_equalize_entities_by);
+ Cvar_RegisterVariable(&r_equalize_entities_to);
Cvar_RegisterVariable(&r_animcache);
Cvar_RegisterVariable(&r_depthfirst);
Cvar_RegisterVariable(&r_useinfinitefarclip);
{
int i;
entity_render_t *ent;
- vec3_t tempdiffusenormal;
+ vec3_t tempdiffusenormal, avg;
+ vec_t f, fa, fd, fdd;
for (i = 0;i < r_refdef.scene.numentities;i++)
{
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);
+ if(ent->flags & RENDER_EQUALIZE)
+ {
+ // first fix up ambient lighting...
+ if(r_equalize_entities_minambient.value > 0)
+ {
+ fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2];
+ if(fd > 0)
+ {
+ fa = (0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2]);
+ if(fa < r_equalize_entities_minambient.value * fd)
+ {
+ // solve:
+ // fa'/fd' = minambient
+ // fa'+0.25*fd' = fa+0.25*fd
+ // ...
+ // fa' = fd' * minambient
+ // fd'*(0.25+minambient) = fa+0.25*fd
+ // ...
+ // fd' = (fa+0.25*fd) * 1 / (0.25+minambient)
+ // fa' = (fa+0.25*fd) * minambient / (0.25+minambient)
+ // ...
+ fdd = (fa + 0.25f * fd) / (0.25f + r_equalize_entities_minambient.value);
+ f = fdd / fd; // f>0 because all this is additive; f<1 because fdd<fd because this follows from fa < r_equalize_entities_minambient.value * fd
+ VectorMA(ent->modellight_ambient, (1-f)*0.25f, ent->modellight_diffuse, ent->modellight_ambient);
+ VectorScale(ent->modellight_diffuse, f, ent->modellight_diffuse);
+ }
+ }
+ }
+
+ if(r_equalize_entities_to.value > 0 && r_equalize_entities_by.value != 0)
+ {
+ VectorMA(ent->modellight_ambient, 0.25f, ent->modellight_diffuse, avg);
+ f = 0.299f * avg[0] + 0.587f * avg[1] + 0.114f * avg[2];
+ if(f > 0)
+ {
+ f = pow(f / r_equalize_entities_to.value, -r_equalize_entities_by.value);
+ VectorScale(ent->modellight_ambient, f, ent->modellight_ambient);
+ VectorScale(ent->modellight_diffuse, f, ent->modellight_diffuse);
+ }
+ }
+ }
}
else // highly rare
VectorSet(ent->modellight_ambient, 1, 1, 1);
}
}
+#define MAX_LINEOFSIGHTTRACES 64
+
+static qboolean R_CanSeeBox(int numsamples, vec_t enlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
+{
+ int i;
+ vec3_t boxmins, boxmaxs;
+ vec3_t start;
+ vec3_t end;
+ dp_model_t *model = r_refdef.scene.worldmodel;
+
+ if (!model || !model->brush.TraceLineOfSight)
+ return true;
+
+ // expand the box a little
+ boxmins[0] = (enlarge+1) * entboxmins[0] - enlarge * entboxmaxs[0];
+ boxmaxs[0] = (enlarge+1) * entboxmaxs[0] - enlarge * entboxmins[0];
+ boxmins[1] = (enlarge+1) * entboxmins[1] - enlarge * entboxmaxs[1];
+ boxmaxs[1] = (enlarge+1) * entboxmaxs[1] - enlarge * entboxmins[1];
+ boxmins[2] = (enlarge+1) * entboxmins[2] - enlarge * entboxmaxs[2];
+ boxmaxs[2] = (enlarge+1) * entboxmaxs[2] - enlarge * entboxmins[2];
+
+ // try center
+ VectorCopy(eye, start);
+ VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, end);
+ if (model->brush.TraceLineOfSight(model, start, end))
+ return true;
+
+ // try various random positions
+ for (i = 0;i < numsamples;i++)
+ {
+ VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
+ if (model->brush.TraceLineOfSight(model, start, end))
+ return true;
+ }
+
+ return false;
+}
+
+
static void R_View_UpdateEntityVisible (void)
{
int i, renderimask;
for (i = 0;i < r_refdef.scene.numentities;i++)
{
ent = r_refdef.scene.entities[i];
- if(r_refdef.viewcache.entityvisible[i] && !(ent->effects & EF_NODEPTHTEST) && !(ent->flags & RENDER_VIEWMODEL) && !(ent->model && (ent->model->name[0] == '*')))
+ if(r_refdef.viewcache.entityvisible[i] && !(ent->effects & EF_NODEPTHTEST) && !(ent->flags & (RENDER_VIEWMODEL + RENDER_NOCULL)) && !(ent->model && (ent->model->name[0] == '*')))
{
- if(Mod_CanSeeBox_Trace(r_cullentities_trace_samples.integer, r_cullentities_trace_enlarge.value, r_refdef.scene.worldmodel, r_refdef.view.origin, ent->mins, ent->maxs))
+ if(R_CanSeeBox(r_cullentities_trace_samples.integer, r_cullentities_trace_enlarge.value, r_refdef.view.origin, ent->mins, ent->maxs))
ent->last_trace_visibility = realtime;
if(ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
r_refdef.viewcache.entityvisible[i] = 0;
}
// allocate textures as needed
- if (r_waterstate.waterwidth != waterwidth || r_waterstate.waterheight != waterheight || r_waterstate.texturewidth != texturewidth || r_waterstate.textureheight != textureheight)
+ if (r_waterstate.texturewidth != texturewidth || r_waterstate.textureheight != textureheight)
{
r_waterstate.maxwaterplanes = MAX_WATERPLANES;
for (i = 0, p = r_waterstate.waterplanes;i < r_waterstate.maxwaterplanes;i++, p++)
p->texture_reflection = NULL;
}
memset(&r_waterstate, 0, sizeof(r_waterstate));
- r_waterstate.waterwidth = waterwidth;
- r_waterstate.waterheight = waterheight;
r_waterstate.texturewidth = texturewidth;
r_waterstate.textureheight = textureheight;
}
- // when doing a reduced render (HDR) we want to use a smaller area
- waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
- waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
-
- if (r_waterstate.waterwidth)
+ if (r_waterstate.texturewidth)
{
r_waterstate.enabled = true;
+ // when doing a reduced render (HDR) we want to use a smaller area
+ r_waterstate.waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
+ r_waterstate.waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
+
// set up variables that will be used in shader setup
- r_waterstate.screenscale[0] = 0.5f * (float)waterwidth / (float)texturewidth;
- r_waterstate.screenscale[1] = 0.5f * (float)waterheight / (float)textureheight;
- r_waterstate.screencenter[0] = 0.5f * (float)waterwidth / (float)texturewidth;
- r_waterstate.screencenter[1] = 0.5f * (float)waterheight / (float)textureheight;
+ r_waterstate.screenscale[0] = 0.5f * (float)r_waterstate.waterwidth / (float)r_waterstate.texturewidth;
+ r_waterstate.screenscale[1] = 0.5f * (float)r_waterstate.waterheight / (float)r_waterstate.textureheight;
+ r_waterstate.screencenter[0] = 0.5f * (float)r_waterstate.waterwidth / (float)r_waterstate.texturewidth;
+ r_waterstate.screencenter[1] = 0.5f * (float)r_waterstate.waterheight / (float)r_waterstate.textureheight;
}
r_waterstate.maxwaterplanes = MAX_WATERPLANES;
brighten = r_bloom_brighten.value;
if (r_hdr.integer)
brighten *= r_hdr_range.value;
+ brighten = sqrt(brighten);
+ if(range >= 1)
+ brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f, 0, 0);
{
// blend on at multiple vertical offsets to achieve a vertical blur
// TODO: do offset blends using GLSL
+ // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
GL_BlendFunc(GL_ONE, GL_ZERO);
for (x = -range;x <= range;x++)
{
// black at the edges
// (probably not realistic but looks good enough)
//r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
- //r = (dir ? 1.0f : brighten)/(range*2+1);
- r = (dir ? 1.0f : brighten)/(range*2+1)*(1 - x*x/(float)(range*range));
+ //r = brighten/(range*2+1);
+ r = brighten / (range * 2 + 1);
+ if(range >= 1)
+ r *= (1 - x*x/(float)(range*range));
GL_Color(r, r, r, 1);
R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
return;
}
- if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0/* || !r_refdef.scene.worldmodel*/)
+ if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer/* || !r_refdef.scene.worldmodel*/)
return; //Host_Error ("R_RenderView: NULL worldmodel");
r_refdef.view.colorscale = r_hdr_scenebrightness.value;
if (R_DrawBrushModelsSky() && r_timereport_active)
R_TimeReport("bmodelsky");
+
+ if (skyrendermasked && skyrenderlater)
+ {
+ // we have to force off the water clipping plane while rendering sky
+ R_SetupView(false);
+ R_Sky();
+ R_SetupView(true);
+ }
}
R_AnimCache_CacheVisibleEntities();
R_Mesh_Matrix(&identitymatrix);
R_Mesh_ResetTextureState();
+ // set up global fogging in worldspace (RSurf_FogVertex depends on this)
+ VectorCopy(r_refdef.view.origin, rsurface.localvieworigin);
+
vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2]; //
vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
{
for (i = 0, v = vertex3f, c = color4f;i < 8;i++, v += 3, c += 4)
{
- f1 = FogPoint_World(v);
+ f1 = RSurf_FogVertex(v);
f2 = 1 - f1;
c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
int i;
float f1, f2, *c;
float color4f[6*4];
+
+ // set up global fogging in worldspace (RSurf_FogVertex depends on this)
+ VectorCopy(r_refdef.view.origin, rsurface.localvieworigin);
+
// this is only called once per entity so numsurfaces is always 1, and
// surfacelist is always {0}, so this code does not handle batches
R_Mesh_Matrix(&ent->matrix);
memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
R_Mesh_ColorPointer(color4f, 0, 0);
Matrix4x4_OriginFromMatrix(&ent->matrix, org);
- f1 = FogPoint_World(org);
+ f1 = RSurf_FogVertex(org);
f2 = 1 - f1;
for (i = 0, c = color4f;i < 6;i++, c += 4)
{
float fog = 1.0f;
float vertex3f[12];
+ // set up global fogging in worldspace (RSurf_FogVertex depends on this)
+ VectorCopy(r_refdef.view.origin, rsurface.localvieworigin);
+
if (r_refdef.fogenabled && !depthdisable) // TODO maybe make the unfog effect a separate flag?
- fog = FogPoint_World(origin);
+ fog = RSurf_FogVertex(origin);
R_Mesh_Matrix(&identitymatrix);
GL_BlendFunc(blendfunc1, blendfunc2);
// figure out how large a bounding box we need to properly compute this brush
maxdist = 0;
for (w = 0;w < numplanes;w++)
- maxdist = max(maxdist, planes[w].dist);
+ maxdist = max(maxdist, fabs(planes[w].dist));
// now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
Matrix4x4_Concat(texmatrix, &matrix, &temp);
}
+void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
+{
+ int textureflags = TEXF_PRECACHE | (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP | TEXF_COMPRESS;
+ char name[MAX_QPATH];
+ skinframe_t *skinframe;
+ unsigned char pixels[296*194];
+ strlcpy(cache->name, skinname, sizeof(cache->name));
+ dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
+ if (developer_loading.integer)
+ Con_Printf("loading %s\n", name);
+ skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
+ if (!skinframe || !skinframe->base)
+ {
+ unsigned char *f;
+ fs_offset_t filesize;
+ skinframe = NULL;
+ f = FS_LoadFile(name, tempmempool, true, &filesize);
+ if (f)
+ {
+ if (LoadPCX_QWSkin(f, filesize, pixels, 296, 194))
+ skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
+ Mem_Free(f);
+ }
+ }
+ cache->skinframe = skinframe;
+}
+
texture_t *R_GetCurrentTexture(texture_t *t)
{
int i;
// update currentskinframe to be a qw skin or animation frame
if ((i = ent->entitynumber - 1) >= 0 && i < cl.maxclients && cls.protocol == PROTOCOL_QUAKEWORLD && cl.scores[i].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl"))
{
- if (strcmp(r_qwskincache[i], cl.scores[i].qw_skin))
+ if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
{
- strlcpy(r_qwskincache[i], cl.scores[i].qw_skin, sizeof(r_qwskincache[i]));
- if (developer_loading.integer)
- Con_Printf("loading skins/%s\n", r_qwskincache[i]);
- r_qwskincache_skinframe[i] = R_SkinFrame_LoadExternal(va("skins/%s", r_qwskincache[i]), TEXF_PRECACHE | (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP | TEXF_COMPRESS, developer.integer > 0);
+ r_qwskincache_size = cl.maxclients;
+ if (r_qwskincache)
+ Mem_Free(r_qwskincache);
+ r_qwskincache = Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
}
- t->currentskinframe = r_qwskincache_skinframe[i];
+ if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
+ R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
+ t->currentskinframe = r_qwskincache[i].skinframe;
if (t->currentskinframe == NULL)
t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->shadertime)) % t->numskinframes];
}
t->glosstexture = r_texture_white;
t->backgroundglosstexture = r_texture_white;
t->specularscale = r_shadow_gloss2intensity.value;
+ t->specularpower = r_shadow_gloss2exponent.value;
}
}
+ t->specularscale *= t->specularscalemod;
+ t->specularpower *= t->specularpowermod;
// lightmaps mode looks bad with dlights using actual texturing, so turn
// off the colormap and glossmap, but leave the normalmap on as it still
rsurface.matrix = identitymatrix;
rsurface.inversematrix = identitymatrix;
R_Mesh_Matrix(&identitymatrix);
- VectorCopy(r_refdef.view.origin, rsurface.modelorg);
+ VectorCopy(r_refdef.view.origin, rsurface.localvieworigin);
VectorSet(rsurface.modellight_ambient, 0, 0, 0);
VectorSet(rsurface.modellight_diffuse, 0, 0, 0);
VectorSet(rsurface.modellight_lightdir, 0, 0, 1);
VectorSet(rsurface.colormap_pantscolor, 0, 0, 0);
VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0);
+ VectorSet(rsurface.glowmod, 1, 1, 1);
memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
rsurface.frameblend[0].lerp = 1;
rsurface.basepolygonfactor = r_refdef.polygonfactor;
rsurface.matrix = ent->matrix;
rsurface.inversematrix = ent->inversematrix;
R_Mesh_Matrix(&rsurface.matrix);
- Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.modelorg);
+ Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
rsurface.modellight_ambient[0] = ent->modellight_ambient[0] * ent->colormod[0];
rsurface.modellight_ambient[1] = ent->modellight_ambient[1] * ent->colormod[1];
rsurface.modellight_ambient[2] = ent->modellight_ambient[2] * ent->colormod[2];
VectorCopy(ent->modellight_lightdir, rsurface.modellight_lightdir);
VectorCopy(ent->colormap_pantscolor, rsurface.colormap_pantscolor);
VectorCopy(ent->colormap_shirtcolor, rsurface.colormap_shirtcolor);
+ VectorCopy(ent->glowmod, rsurface.glowmod);
memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
rsurface.basepolygonfactor = r_refdef.polygonfactor;
rsurface.basepolygonoffset = r_refdef.polygonoffset;
rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
}
+float RSurf_FogVertex(const float *v)
+{
+ float len = VectorDistance(rsurface.localvieworigin, v);
+ unsigned int fogmasktableindex;
+ fogmasktableindex = (unsigned int)(len * r_refdef.fogmasktabledistmultiplier);
+ return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
+}
+
static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, msurface_t **texturesurfacelist)
{
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);
+ VectorSubtract(rsurface.localvieworigin, center, forward);
//Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
VectorNegate(forward, forward);
VectorReflect(forward, 0, up, forward);
float viewer[3], d, reflected[3], worldreflected[3];
- VectorSubtract(rsurface.modelorg, vertex, viewer);
+ VectorSubtract(rsurface.localvieworigin, vertex, viewer);
// VectorNormalize(viewer);
d = DotProduct(normal, viewer);
const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4)
{
- f = FogPoint_Model(v);
+ f = RSurf_FogVertex(v);
c2[0] = c[0] * f;
c2[1] = c[1] * f;
c2[2] = c[2] * f;
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);
+ f = RSurf_FogVertex(v);
c2[0] = f;
c2[1] = f;
c2[2] = f;
const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4)
{
- f = FogPoint_Model(v);
+ f = RSurf_FogVertex(v);
c2[0] = c[0] * f + r_refdef.fogcolor[0] * (1 - f);
c2[1] = c[1] * f + r_refdef.fogcolor[1] * (1 - f);
c2[2] = c[2] * f + r_refdef.fogcolor[2] * (1 - f);
if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
return;
R_SetupGenericShader(false);
- if (skyrendernow)
- {
- skyrendernow = false;
- // we have to force off the water clipping plane while rendering sky
- R_SetupView(false);
- R_Sky();
- R_SetupView(true);
- // restore entity matrix
- R_Mesh_Matrix(&rsurface.matrix);
- }
+ skyrenderlater = true;
RSurf_SetupDepthAndCulling();
GL_DepthMask(true);
// LordHavoc: HalfLife maps have freaky skypolys so don't use
const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4)
{
- f = 1 - FogPoint_Model(v);
+ f = 1 - RSurf_FogVertex(v);
c[0] = layercolor[0];
c[1] = layercolor[1];
c[2] = layercolor[2];
const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4)
{
- f = 1 - FogPoint_Model(v);
+ f = 1 - RSurf_FogVertex(v);
c[0] = layer->color[0];
c[1] = layer->color[1];
c[2] = layer->color[2];
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);
+ if (queueentity->transparent_offset) // transparent offset
+ {
+ center[0] += r_refdef.view.forward[0]*queueentity->transparent_offset;
+ center[1] += r_refdef.view.forward[1]*queueentity->transparent_offset;
+ center[2] += r_refdef.view.forward[2]*queueentity->transparent_offset;
+ }
R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_refdef.view.origin : center, R_DrawSurface_TransparentCallback, queueentity, surface - rsurface.modelsurfaces, rsurface.rtlight);
}
}