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", "0.5", "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", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
+cvar_t r_polygonoffset_decals_factor = {0, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
+cvar_t r_polygonoffset_decals_offset = {0, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
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_blue = 0;
r_refdef.fog_alpha = 1;
r_refdef.fog_start = 0;
- 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));
+ r_refdef.fog_end = 16384;
+ r_refdef.fog_height = 1<<30;
+ r_refdef.fog_fadedepth = 128;
}
static void R_BuildBlankTextures(void)
"// written by Forest 'LordHavoc' Hale\n"
"\n"
"// enable various extensions depending on permutation:\n"
-"\n"
+"\n"
"#ifdef USESHADOWMAPRECT\n"
"# extension GL_ARB_texture_rectangle : enable\n"
"#endif\n"
"# define myhalf4 vec4\n"
"//#endif\n"
"\n"
+"#ifdef USEFOGINSIDE\n"
+"# define USEFOG\n"
+"#else\n"
+"# ifdef USEFOGOUTSIDE\n"
+"# define USEFOG\n"
+"# endif\n"
+"#endif\n"
+"\n"
"#ifdef MODE_DEPTH_OR_SHADOW\n"
"\n"
"# ifdef VERTEX_SHADER\n"
"# endif\n"
"\n"
"#else // !MODE_GENERIC\n"
+"#ifdef MODE_BLOOMBLUR\n"
+"# ifdef VERTEX_SHADER\n"
+"void main(void)\n"
+"{\n"
+" gl_FrontColor = gl_Color;\n"
+" gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
+" gl_Position = ftransform();\n"
+"}\n"
+"# endif\n"
+"# ifdef FRAGMENT_SHADER\n"
+"\n"
+"uniform sampler2D Texture_First;\n"
+"uniform vec4 BloomBlur_Parameters;\n"
+"\n"
+"void main(void)\n"
+"{\n"
+" int i;\n"
+" vec2 tc = gl_TexCoord[0].xy;\n"
+" vec3 color = texture2D(Texture_First, tc).rgb;\n"
+" tc += BloomBlur_Parameters.xy;\n"
+" for (i = 1;i < SAMPLES;i++)\n"
+" {\n"
+" color += texture2D(Texture_First, tc).rgb;\n"
+" tc += BloomBlur_Parameters.xy;\n"
+" }\n"
+" gl_FragColor = vec4(color * BloomBlur_Parameters.z + vec3(BloomBlur_Parameters.w), 1);\n"
+"}\n"
+"# endif\n"
+"\n"
+"#else // !MODE_BLOOMBLUR\n"
"\n"
"varying vec2 TexCoord;\n"
"#ifdef USEVERTEXTEXTUREBLEND\n"
"varying vec3 EyeVector;\n"
"#ifdef USEFOG\n"
"varying vec3 EyeVectorModelSpace;\n"
+"varying float FogPlaneVertexDist;\n"
"#endif\n"
"\n"
"varying vec3 VectorS; // direction of S texcoord (sometimes crudely called tangent)\n"
"uniform vec3 LightPosition;\n"
"uniform vec3 EyePosition;\n"
"uniform vec3 LightDir;\n"
+"uniform vec4 FogPlane;\n"
"\n"
"// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3), this would require sending a 4 component texcoord1 with W as 1 or -1 according to which side the texcoord2 should be on\n"
"\n"
" EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
" EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
"\n"
+"#ifdef USEFOG\n"
+" FogPlaneVertexDist = dot(FogPlane, gl_Vertex);\n"
+"#endif\n"
+"\n"
"#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
" VectorS = gl_MultiTexCoord1.xyz;\n"
" VectorT = gl_MultiTexCoord2.xyz;\n"
"uniform float OffsetMapping_Scale;\n"
"uniform float OffsetMapping_Bias;\n"
"uniform float FogRangeRecip;\n"
+"uniform float FogPlaneViewDist;\n"
+"uniform float FogHeightFade;\n"
"\n"
"uniform myhalf AmbientScale;\n"
"uniform myhalf DiffuseScale;\n"
"# else\n"
"# define texval(x, y) texture2D(Texture_ShadowMap2D, center + vec2(x, y)*ShadowMap_TextureScale).r \n"
"# endif\n"
-"# if USESHADOWMAPPCF > 1\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"
" 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"
"# endif\n"
"# else\n"
" f = step(shadowmaptc.z, texture2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale).r);\n"
"\n"
" // apply fog after Contrastboost/SceneBrightness because its color is already modified appropriately\n"
"#ifdef USEFOG\n"
-" color.rgb = mix(FogColor, color.rgb, myhalf(texture2D(Texture_FogMask, myhalf2(length(EyeVectorModelSpace)*FogRangeRecip, 0.0))));\n"
+" float fogfrac;\n"
+"#ifdef USEFOGOUTSIDE\n"
+" fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0, min(0.0, FogPlaneVertexDist) * FogHeightFade);\n"
+"#else\n"
+" fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist)) * min(1.0, (min(0.0, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);\n"
+"#endif\n"
+"// float FogHeightFade1 = -0.5/1024.0;\n"
+"// if (FogPlaneViewDist >= 0.0)\n"
+"// fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0, min(0.0, FogPlaneVertexDist) * FogHeightFade1);\n"
+"// else\n"
+"// fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist)) * min(1.0, (min(0.0, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade1);\n"
+"//# ifdef USEFOGABOVE\n"
+"// if (FogPlaneViewDist >= 0.0)\n"
+"// fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist);\n"
+"// else\n"
+"// fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist));\n"
+"// fogfrac *= min(1.0, (min(0.0, FogPlaneVertexDist) + min(0.0, FogPlaneViewDist))*FogHeightFade1);\n"
+"// fogfrac *= min(1.0, (max(0.0, fade*FogPlaneVertexDist) + max(0.0, fade*FogPlaneViewDist)));\n"
+"// fogfrac *= min(1.0, (max(0.0, FogHeightFade1*FogPlaneVertexDist) + max(0.0, FogHeightFade1*FogPlaneViewDist)));\n"
+"// fogfrac *= min(1.0, (min(0.0, FogPlaneVertexDist) + min(0.0, FogPlaneViewDist))*FogHeightFade1);\n"
+"\n"
+" //fogfrac *= min(1.0, max(0.0, (max(-2048, min(0, FogPlaneVertexDist)) + max(-2048, min(0, FogPlaneViewDist)))/-2048.0));\n"
+" //float fade = -0.5/128.0;\n"
+" //fogfrac *= max(0.0, min(1.0, fade*FogPlaneVertexDist)) + max(0.0, min(1.0, fade*FogPlaneViewDist));\n"
+" //fogfrac *= max(0.0, min(1.0, FogHeightFade1*FogPlaneVertexDist)) + max(0.0, min(1.0, FogHeightFade1*FogPlaneViewDist));\n"
+" //fogfrac *= min(1.0, max(0.0, FogHeightFade1*FogPlaneVertexDist)) + min(1.0, max(0.0, FogHeightFade1*FogPlaneViewDist));\n"
+" //fogfrac *= min(1.0, max(0.0, FogHeightFade1*FogPlaneVertexDist) + max(0.0, FogHeightFade1*FogPlaneViewDist));\n"
+" //fogfrac *= min(1.0, min(1.0, max(0.0, FogHeightFade1*FogPlaneVertexDist)) + min(1.0, max(0.0, FogHeightFade1*FogPlaneViewDist)));\n"
+" //fogfrac *= min(1.0, max(0.0, FogHeightFade1*FogPlaneVertexDist) + max(0.0, FogHeightFade1*FogPlaneViewDist));\n"
+" //fogfrac *= min(1.0, (min(0.0, FogPlaneVertexDist) + min(0.0, FogPlaneViewDist)) * FogHeightFade1);\n"
+" //fogfrac *= min(1.0, (min(0.0, FogPlaneVertexDist) + min(0.0, FogPlaneViewDist)) * FogHeightFade1);\n"
+"//# endif\n"
+" color.rgb = mix(FogColor, color.rgb, myhalf(texture2D(Texture_FogMask, myhalf2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0))));\n"
"#endif\n"
"\n"
" // reflection must come last because it already contains exactly the correct fog (the reflection render preserves camera distance from the plane, it only flips the side) and ContrastBoost/SceneBrightness\n"
"\n"
"#endif // FRAGMENT_SHADER\n"
"\n"
+"#endif // !MODE_BLOOMBLUR\n"
"#endif // !MODE_GENERIC\n"
"#endif // !MODE_POSTPROCESS\n"
"#endif // !MODE_SHOWDEPTH\n"
{
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_VIEWTINT = 1<<1, ///< view tint (postprocessing only)
- SHADERPERMUTATION_COLORMAPPING = 1<<2, ///< indicates this is a colormapped skin
- SHADERPERMUTATION_SATURATION = 1<<2, ///< saturation (postprocessing only)
- SHADERPERMUTATION_FOG = 1<<3, ///< tint the color by fog color or black if using additive blend mode
- SHADERPERMUTATION_GAMMARAMPS = 1<<3, ///< gamma (postprocessing only)
- SHADERPERMUTATION_CUBEFILTER = 1<<4, ///< (lightsource) use cubemap light filter
- SHADERPERMUTATION_GLOW = 1<<5, ///< (lightmap) blend in an additive glow texture
- SHADERPERMUTATION_BLOOM = 1<<5, ///< bloom (postprocessing only)
- SHADERPERMUTATION_SPECULAR = 1<<6, ///< (lightsource or deluxemapping) render specular effects
- SHADERPERMUTATION_POSTPROCESSING = 1<<6, ///< user defined postprocessing (postprocessing only)
- SHADERPERMUTATION_EXACTSPECULARMATH = 1<<7, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
- SHADERPERMUTATION_REFLECTION = 1<<8, ///< normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface
- SHADERPERMUTATION_OFFSETMAPPING = 1<<9, ///< adjust texcoords to roughly simulate a displacement mapped surface
- SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<10, ///< adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!)
- 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_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_VIEWTINT = 1<<2, ///< view tint (postprocessing only)
+ SHADERPERMUTATION_COLORMAPPING = 1<<3, ///< indicates this is a colormapped skin
+ SHADERPERMUTATION_SATURATION = 1<<4, ///< saturation (postprocessing only)
+ SHADERPERMUTATION_FOGINSIDE = 1<<5, ///< tint the color by fog color or black if using additive blend mode
+ SHADERPERMUTATION_FOGOUTSIDE = 1<<6, ///< tint the color by fog color or black if using additive blend mode
+ SHADERPERMUTATION_GAMMARAMPS = 1<<7, ///< gamma (postprocessing only)
+ SHADERPERMUTATION_CUBEFILTER = 1<<8, ///< (lightsource) use cubemap light filter
+ SHADERPERMUTATION_GLOW = 1<<9, ///< (lightmap) blend in an additive glow texture
+ SHADERPERMUTATION_BLOOM = 1<<10, ///< bloom (postprocessing only)
+ SHADERPERMUTATION_SPECULAR = 1<<11, ///< (lightsource or deluxemapping) render specular effects
+ SHADERPERMUTATION_POSTPROCESSING = 1<<12, ///< user defined postprocessing (postprocessing only)
+ SHADERPERMUTATION_EXACTSPECULARMATH = 1<<13, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
+ SHADERPERMUTATION_REFLECTION = 1<<14, ///< normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface
+ SHADERPERMUTATION_OFFSETMAPPING = 1<<15, ///< adjust texcoords to roughly simulate a displacement mapped surface
+ SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<16, ///< adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!)
+ SHADERPERMUTATION_SHADOWMAPRECT = 1<<17, ///< (lightsource) use shadowmap rectangle texture as light filter
+ SHADERPERMUTATION_SHADOWMAPCUBE = 1<<18, ///< (lightsource) use shadowmap cubemap texture as light filter
+ SHADERPERMUTATION_SHADOWMAP2D = 1<<19, ///< (lightsource) use shadowmap rectangle texture as light filter
+ SHADERPERMUTATION_SHADOWMAPPCF = 1<<20, ///< (lightsource) use percentage closer filtering on shadowmap test results
+ SHADERPERMUTATION_SHADOWMAPPCF2 = 1<<21, ///< (lightsource) use higher quality percentage closer filtering on shadowmap test results
+ SHADERPERMUTATION_SHADOWSAMPLER = 1<<22, ///< (lightsource) use hardware shadowmap test
+ SHADERPERMUTATION_SHADOWMAPVSDCT = 1<<23, ///< (lightsource) use virtual shadow depth cube texture for shadowmap indexing
+ SHADERPERMUTATION_LIMIT = 1<<24, ///< size of permutations array
+ SHADERPERMUTATION_COUNT = 24 ///< size of shaderpermutationinfo array
}
shaderpermutation_t;
shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
{
{"#define USEDIFFUSE\n", " diffuse"},
- {"#define USEVERTEXTEXTUREBLEND\n#define USEVIEWTINT\n", " vertextextureblend/tint"},
- {"#define USECOLORMAPPING\n#define USESATURATION\n", " colormapping/saturation"},
- {"#define USEFOG\n#define USEGAMMARAMPS\n", " fog/gammaramps"},
+ {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
+ {"#define USEVIEWTINT\n", " viewtint"},
+ {"#define USECOLORMAPPING\n", " colormapping"},
+ {"#define USESATURATION\n", " saturation"},
+ {"#define USEFOGINSIDE\n", " foginside"},
+ {"#define USEFOGOUTSIDE\n", " fogoutside"},
+ {"#define USEGAMMARAMPS\n", " gammaramps"},
{"#define USECUBEFILTER\n", " cubefilter"},
- {"#define USEGLOW\n#define USEBLOOM\n", " glow/bloom"},
- {"#define USESPECULAR\n#define USEPOSTPROCESSING", " specular/postprocessing"},
+ {"#define USEGLOW\n", " glow"},
+ {"#define USEBLOOM\n", " bloom"},
+ {"#define USESPECULAR\n", " specular"},
+ {"#define USEPOSTPROCESSING\n", " postprocessing"},
{"#define USEEXACTSPECULARMATH\n", " exactspecularmath"},
{"#define USEREFLECTION\n", " reflection"},
{"#define USEOFFSETMAPPING\n", " offsetmapping"},
int loc_EyePosition;
int loc_Color_Pants;
int loc_Color_Shirt;
+ int loc_FogPlane;
+ int loc_FogPlaneViewDist;
int loc_FogRangeRecip;
+ int loc_FogHeightFade;
int loc_AmbientScale;
int loc_DiffuseScale;
int loc_SpecularScale;
p->loc_EyePosition = qglGetUniformLocationARB(p->program, "EyePosition");
p->loc_Color_Pants = qglGetUniformLocationARB(p->program, "Color_Pants");
p->loc_Color_Shirt = qglGetUniformLocationARB(p->program, "Color_Shirt");
+ p->loc_FogPlane = qglGetUniformLocationARB(p->program, "FogPlane");
+ p->loc_FogPlaneViewDist = qglGetUniformLocationARB(p->program, "FogPlaneViewDist");
p->loc_FogRangeRecip = qglGetUniformLocationARB(p->program, "FogRangeRecip");
+ p->loc_FogHeightFade = qglGetUniformLocationARB(p->program, "FogHeightFade");
p->loc_AmbientScale = qglGetUniformLocationARB(p->program, "AmbientScale");
p->loc_DiffuseScale = qglGetUniformLocationARB(p->program, "DiffuseScale");
p->loc_SpecularPower = qglGetUniformLocationARB(p->program, "SpecularPower");
if (specularscale > 0)
permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
if (r_refdef.fogenabled)
- permutation |= SHADERPERMUTATION_FOG;
+ permutation |= r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE;
if (rsurface.texture->colormapping)
permutation |= SHADERPERMUTATION_COLORMAPPING;
if (r_shadow_usingshadowmaprect || r_shadow_usingshadowmap2d || r_shadow_usingshadowmapcube)
if (rsurface.texture->currentskinframe->glow && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
permutation |= SHADERPERMUTATION_GLOW;
if (r_refdef.fogenabled)
- permutation |= SHADERPERMUTATION_FOG;
+ permutation |= r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE;
if (rsurface.texture->colormapping)
permutation |= SHADERPERMUTATION_COLORMAPPING;
if (r_glsl_offsetmapping.integer)
if (specularscale > 0)
permutation |= SHADERPERMUTATION_SPECULAR;
if (r_refdef.fogenabled)
- permutation |= SHADERPERMUTATION_FOG;
+ permutation |= r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE;
if (rsurface.texture->colormapping)
permutation |= SHADERPERMUTATION_COLORMAPPING;
if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
if (rsurface.texture->currentskinframe->glow && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
permutation |= SHADERPERMUTATION_GLOW;
if (r_refdef.fogenabled)
- permutation |= SHADERPERMUTATION_FOG;
+ permutation |= r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE;
if (rsurface.texture->colormapping)
permutation |= SHADERPERMUTATION_COLORMAPPING;
if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
if (rsurface.texture->currentskinframe->glow && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
permutation |= SHADERPERMUTATION_GLOW;
if (r_refdef.fogenabled)
- permutation |= SHADERPERMUTATION_FOG;
+ permutation |= r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE;
if (rsurface.texture->colormapping)
permutation |= SHADERPERMUTATION_COLORMAPPING;
if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
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)
else
qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
}
- if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, r_refdef.fograngerecip * Matrix4x4_ScaleFromMatrix(&rsurface.matrix));
+ if (r_glsl_permutation->loc_FogPlane >= 0) qglUniform4fARB(r_glsl_permutation->loc_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);
+ if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
+ if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
+ if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
if(permutation & SHADERPERMUTATION_EXACTSPECULARMATH)
{
if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * 0.25);
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);
Cvar_RegisterVariable(&r_q1bsp_skymasking);
Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
+ Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
+ Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
Cvar_RegisterVariable(&r_fog_exp2);
Cvar_RegisterVariable(&r_drawfog);
Cvar_RegisterVariable(&r_textureunits);
{
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;
ent = r_refdef.scene.entities[i];
if (!(ent->flags & renderimask))
if (!R_CullBox(ent->mins, ent->maxs) || (ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
- if ((ent->effects & EF_NODEPTHTEST) || (ent->flags & RENDER_VIEWMODEL) || r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs))
+ if ((ent->flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL)) || r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs))
r_refdef.viewcache.entityvisible[i] = true;
}
if(r_cullentities_trace.integer && r_refdef.scene.worldmodel->brush.TraceLineOfSight)
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 + RENDER_NOCULL)) && !(ent->model && (ent->model->name[0] == '*')))
+ if(r_refdef.viewcache.entityvisible[i] && !(ent->flags & (RENDER_VIEWMODEL | RENDER_NOCULL | RENDER_NODEPTHTEST)) && !(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;
}
}
+static void R_DrawModelDecals_Entity(entity_render_t *ent);
+static void R_DrawModelDecals(void)
+{
+ int i;
+ entity_render_t *ent;
+
+ R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
+
+ if (!r_drawentities.integer || r_showsurfaces.integer)
+ return;
+
+ for (i = 0;i < r_refdef.scene.numentities;i++)
+ {
+ if (!r_refdef.viewcache.entityvisible[i])
+ continue;
+ ent = r_refdef.scene.entities[i];
+ r_refdef.stats.entities++;
+ if (ent->decalsystem.numdecals)
+ R_DrawModelDecals_Entity(ent);
+ }
+}
+
static void R_View_SetFrustum(void)
{
int i;
R_SetupGenericShader(true);
R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
- R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
+ R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
// we now have a bloom image in the framebuffer
GL_Color(r, r, r, 1);
R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
- R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
+ R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
// copy the vertically blurred bloom view to a texture
brighten = r_bloom_brighten.value;
if (r_hdr.integer)
brighten *= r_hdr_range.value;
+ brighten = sqrt(brighten);
if(range >= 1)
- brighten *= pow((3 * range) / (2 * range - 1), 2); // compensate for the "dot particle"
+ 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);
// 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);
+ //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_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
GL_BlendFunc(GL_ONE, GL_ONE);
}
R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
GL_Color(1, 1, 1, 1);
- R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
+ R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
GL_BlendFunc(GL_ONE, GL_ONE);
R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
GL_Color(r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 1);
- R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
+ R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
qglBlendEquationEXT(GL_FUNC_ADD_EXT);
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_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
}
}
}
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_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
return;
}
GL_BlendFunc(GL_ONE, GL_ONE);
R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
- R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
+ R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
}
else if (r_bloomstate.texture_bloom)
else
{
R_SetupGenericShader(true);
- R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
+ R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
// now blend on the bloom texture
GL_BlendFunc(GL_ONE, GL_ONE);
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_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
}
if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
R_SetupGenericShader(false);
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
- R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
+ R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
}
}
r_refdef.fogcolor[1] = r_refdef.fog_green;
r_refdef.fogcolor[2] = r_refdef.fog_blue;
+ Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
+ r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
+ r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
+ r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
+
{
vec3_t fogvec;
VectorCopy(r_refdef.fogcolor, fogvec);
r_refdef.fog_alpha = 1;
r_refdef.fog_start = 0;
r_refdef.fog_end = gl_skyclip.value;
+ r_refdef.fog_height = 1<<30;
+ r_refdef.fog_fadedepth = 128;
}
else if (r_refdef.oldgl_fogenable)
{
r_refdef.fog_alpha = 0;
r_refdef.fog_start = 0;
r_refdef.fog_end = 0;
+ r_refdef.fog_height = 1<<30;
+ r_refdef.fog_fadedepth = 128;
}
}
extern cvar_t cl_locs_show;
static void R_DrawLocs(void);
static void R_DrawEntityBBoxes(void);
+extern cvar_t cl_decals_newsystem;
void R_RenderScene(void)
{
r_refdef.stats.renders++;
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();
if (cl.csqc_vidvars.drawworld)
{
- R_DrawLightningBeams();
- if (r_timereport_active)
- R_TimeReport("lightning");
-
- R_DrawDecals();
- if (r_timereport_active)
- R_TimeReport("decals");
+ if (cl_decals_newsystem.integer)
+ {
+ R_DrawModelDecals();
+ if (r_timereport_active)
+ R_TimeReport("modeldecals");
+ }
+ else
+ {
+ R_DrawDecals();
+ if (r_timereport_active)
+ R_TimeReport("decals");
+ }
R_DrawParticles();
if (r_timereport_active)
R_DrawExplosions();
if (r_timereport_active)
R_TimeReport("explosions");
+
+ R_DrawLightningBeams();
+ if (r_timereport_active)
+ R_TimeReport("lightning");
}
R_SetupGenericShader(true);
{
int i;
float *v, *c, f1, f2, vertex3f[8*3], color4f[8*4];
+
+ RSurf_ActiveWorldEntity();
+
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GL_DepthMask(false);
GL_DepthRange(0, 1);
GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
- R_Mesh_Matrix(&identitymatrix);
R_Mesh_ResetTextureState();
vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = 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;
prog = prog_save;
}
-unsigned short nomodelelements[24] =
+static const int nomodelelement3i[24] =
{
5, 2, 0,
5, 1, 2,
1, 3, 4
};
-float nomodelvertex3f[6*3] =
+static const unsigned short nomodelelement3s[24] =
+{
+ 5, 2, 0,
+ 5, 1, 2,
+ 5, 0, 3,
+ 5, 3, 1,
+ 0, 2, 4,
+ 2, 1, 4,
+ 3, 0, 4,
+ 1, 3, 4
+};
+
+static const float nomodelvertex3f[6*3] =
{
-16, 0, 0,
16, 0, 0,
0, 0, 16
};
-float nomodelcolor4f[6*4] =
+static const float nomodelcolor4f[6*4] =
{
0.0f, 0.0f, 0.5f, 1.0f,
0.0f, 0.0f, 0.5f, 1.0f,
int i;
float f1, f2, *c;
float color4f[6*4];
+
+ RSurf_ActiveCustomEntity(&ent->matrix, &ent->inversematrix, ent->flags, ent->shadertime, ent->colormod[0], ent->colormod[1], ent->colormod[2], ent->alpha, 6, nomodelvertex3f, NULL, NULL, NULL, NULL, nomodelcolor4f, 8, nomodelelement3i, nomodelelement3s, false, false);
+
// 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);
- if (ent->flags & EF_ADDITIVE)
+ if (rsurface.ent_flags & RENDER_ADDITIVE)
{
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
GL_DepthMask(false);
}
- else if (ent->alpha < 1)
+ else if (rsurface.ent_color[3] < 1)
{
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GL_DepthMask(false);
GL_BlendFunc(GL_ONE, GL_ZERO);
GL_DepthMask(true);
}
- GL_DepthRange(0, (ent->flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
- GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
- GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
- GL_CullFace((ent->effects & EF_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
+ GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
+ GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
+ GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
+ GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
R_SetupGenericShader(false);
- R_Mesh_VertexPointer(nomodelvertex3f, 0, 0);
+ R_Mesh_VertexPointer(rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
+ memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
+ R_Mesh_ColorPointer(color4f, 0, 0);
+ for (i = 0, c = color4f;i < 6;i++, c += 4)
+ {
+ c[0] *= rsurface.ent_color[0];
+ c[1] *= rsurface.ent_color[1];
+ c[2] *= rsurface.ent_color[2];
+ c[3] *= rsurface.ent_color[3];
+ }
if (r_refdef.fogenabled)
{
- vec3_t org;
- memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
- R_Mesh_ColorPointer(color4f, 0, 0);
- Matrix4x4_OriginFromMatrix(&ent->matrix, org);
- f1 = FogPoint_World(org);
- f2 = 1 - f1;
for (i = 0, c = color4f;i < 6;i++, c += 4)
{
+ f1 = RSurf_FogVertex(rsurface.vertex3f + 3*i);
+ f2 = 1 - f1;
c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
- c[3] *= ent->alpha;
}
}
- else if (ent->alpha != 1)
- {
- memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
- R_Mesh_ColorPointer(color4f, 0, 0);
- for (i = 0, c = color4f;i < 6;i++, c += 4)
- c[3] *= ent->alpha;
- }
- else
- R_Mesh_ColorPointer(nomodelcolor4f, 0, 0);
R_Mesh_ResetTextureState();
- R_Mesh_Draw(0, 6, 0, 8, NULL, nomodelelements, 0, 0);
+ R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, nomodelelement3s, 0, 0);
}
void R_DrawNoModel(entity_render_t *ent)
{
vec3_t org;
Matrix4x4_OriginFromMatrix(&ent->matrix, org);
- //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
- R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_refdef.view.origin : org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
- //else
- // R_DrawNoModelCallback(ent, 0);
+ if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
+ R_MeshQueue_AddTransparent(ent->flags & RENDER_NODEPTHTEST ? r_refdef.view.origin : org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
+ else
+ R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
}
void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
vert[11] = org2[2] + width * right2[2];
}
-float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
-
-void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, rtexture_t *fogtexture, qboolean depthdisable, qboolean depthshort, const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2, float cr, float cg, float cb, float ca)
+void R_CalcSprite_Vertex3f(float *vertex3f, const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2)
{
- // NOTE: this must not call qglDepthFunc (see r_shadow.c, R_BeginCoronaQuery) thanks to ATI
- float fog = 1.0f;
- float vertex3f[12];
-
- if (r_refdef.fogenabled && !depthdisable) // TODO maybe make the unfog effect a separate flag?
- fog = FogPoint_World(origin);
-
- R_Mesh_Matrix(&identitymatrix);
- GL_BlendFunc(blendfunc1, blendfunc2);
-
- GL_CullFace(GL_NONE);
-
- GL_DepthMask(false);
- GL_DepthRange(0, depthshort ? 0.0625 : 1);
- GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
- GL_DepthTest(!depthdisable);
-
vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
-
- R_Mesh_VertexPointer(vertex3f, 0, 0);
- R_Mesh_ColorPointer(NULL, 0, 0);
- R_Mesh_ResetTextureState();
- R_SetupGenericShader(true);
- R_Mesh_TexBind(0, R_GetTexture(texture));
- R_Mesh_TexCoordPointer(0, 2, spritetexcoord2f, 0, 0);
- // FIXME: fixed function path can't properly handle r_refdef.view.colorscale > 1
- GL_Color(cr * fog * r_refdef.view.colorscale, cg * fog * r_refdef.view.colorscale, cb * fog * r_refdef.view.colorscale, ca);
- R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
-
- if (blendfunc2 == GL_ONE_MINUS_SRC_ALPHA)
- {
- R_Mesh_TexBind(0, R_GetTexture(fogtexture));
- GL_BlendFunc(blendfunc1, GL_ONE);
- fog = 1 - fog;
- GL_Color(r_refdef.fogcolor[0] * fog, r_refdef.fogcolor[1] * fog, r_refdef.fogcolor[2] * fog, ca);
- R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
- }
}
int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
// 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;
// switch to an alternate material if this is a q1bsp animated material
{
texture_t *texture = t;
- int s = ent->skinnum;
+ int s = rsurface.ent_skinnum;
if ((unsigned int)s >= (unsigned int)model->numskins)
s = 0;
if (model->skinscenes)
{
// use an alternate animation if the entity's frame is not 0,
// and only if the texture has an alternate animation
- if (ent->framegroupblend[0].frame != 0 && t->anim_total[1])
+ if (rsurface.frameblend[0].subframe != 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];
}
// 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 (rsurface.ent_qwskin >= 0)
{
- if (strcmp(r_qwskincache[i], cl.scores[i].qw_skin))
+ i = rsurface.ent_qwskin;
+ 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->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - rsurface.ent_shadertime)) % t->numskinframes];
}
else if (t->numskinframes >= 2)
- t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->shadertime)) % t->numskinframes];
+ t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - rsurface.ent_shadertime)) % t->numskinframes];
if (t->backgroundnumskinframes >= 2)
- t->backgroundcurrentskinframe = t->backgroundskinframes[(int)(t->backgroundskinframerate * (cl.time - ent->shadertime)) % t->backgroundnumskinframes];
+ t->backgroundcurrentskinframe = t->backgroundskinframes[(int)(t->backgroundskinframerate * (cl.time - rsurface.ent_shadertime)) % t->backgroundnumskinframes];
t->currentmaterialflags = t->basematerialflags;
- t->currentalpha = ent->alpha;
+ t->currentalpha = rsurface.ent_color[3];
if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer))
t->currentalpha *= r_wateralpha.value;
if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_waterstate.enabled && !r_refdef.view.isoverlay)
t->currentalpha *= t->r_water_wateralpha;
if(!r_waterstate.enabled || r_refdef.view.isoverlay)
t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION);
- if (!(ent->flags & RENDER_LIGHT))
+ if (!(rsurface.ent_flags & RENDER_LIGHT))
t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT;
else if (rsurface.modeltexcoordlightmap2f == NULL)
{
// pick a model lighting mode
- if (VectorLength2(ent->modellight_diffuse) >= (1.0f / 256.0f))
+ if (VectorLength2(rsurface.modellight_diffuse) >= (1.0f / 256.0f))
t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT | MATERIALFLAG_MODELLIGHT_DIRECTIONAL;
else
t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
}
- if (ent->effects & EF_ADDITIVE)
+ if (rsurface.ent_flags & RENDER_ADDITIVE)
t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
else if (t->currentalpha < 1)
t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
- if (ent->effects & EF_DOUBLESIDED)
+ if (rsurface.ent_flags & RENDER_DOUBLESIDED)
t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
- if (ent->effects & EF_NODEPTHTEST)
- t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
- if (ent->flags & RENDER_VIEWMODEL)
+ if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
if (t->backgroundnumskinframes)
t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
t->currenttexmatrix = r_waterscrollmatrix;
t->currentbackgroundtexmatrix = r_waterscrollmatrix;
}
- else
+ else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
{
Matrix4x4_CreateIdentity(&t->currenttexmatrix);
Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
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->colormapping = VectorLength2(rsurface.colormap_pantscolor) + VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
t->glosstexture = r_texture_black;
t->backgroundbasetexture = t->backgroundnumskinframes ? ((!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base) : r_texture_white;
t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_MODELLIGHT_DIRECTIONAL | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
}
- Vector4Set(t->lightmapcolor, ent->colormod[0], ent->colormod[1], ent->colormod[2], t->currentalpha);
+ Vector4Set(t->lightmapcolor, rsurface.ent_color[0], rsurface.ent_color[1], rsurface.ent_color[2], t->currentalpha);
VectorClear(t->dlightcolor);
t->currentnumlayers = 0;
if (t->currentmaterialflags & MATERIALFLAG_WALL)
{
// fullbright is not affected by r_refdef.lightmapintensity
R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_TEXTURE, t->basetexture, &t->currenttexmatrix, t->lightmapcolor[0], t->lightmapcolor[1], t->lightmapcolor[2], t->lightmapcolor[3]);
- if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
- R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * t->lightmapcolor[0], ent->colormap_pantscolor[1] * t->lightmapcolor[1], ent->colormap_pantscolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
- if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
- R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * t->lightmapcolor[0], ent->colormap_shirtcolor[1] * t->lightmapcolor[1], ent->colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
+ if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
+ R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * t->lightmapcolor[0], rsurface.colormap_pantscolor[1] * t->lightmapcolor[1], rsurface.colormap_pantscolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
+ if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
+ R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * t->lightmapcolor[0], rsurface.colormap_shirtcolor[1] * t->lightmapcolor[1], rsurface.colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
}
else
{
vec3_t ambientcolor;
float colorscale;
// set the color tint used for lights affecting this surface
- VectorSet(t->dlightcolor, ent->colormod[0] * t->lightmapcolor[3], ent->colormod[1] * t->lightmapcolor[3], ent->colormod[2] * t->lightmapcolor[3]);
+ VectorSet(t->dlightcolor, rsurface.ent_color[0] * t->lightmapcolor[3], rsurface.ent_color[1] * t->lightmapcolor[3], rsurface.ent_color[2] * t->lightmapcolor[3]);
colorscale = 2;
// q3bsp has no lightmap updates, so the lightstylevalue that
// would normally be baked into the lightmap must be
// applied to the color
// FIXME: r_glsl 1 rendering doesn't support overbright lightstyles with this (the default light style is not overbright)
- if (ent->model->type == mod_brushq3)
+ if (model->type == mod_brushq3)
colorscale *= r_refdef.scene.rtlightstylevalue[0];
colorscale *= r_refdef.lightmapintensity;
VectorScale(t->lightmapcolor, r_refdef.scene.ambient * (1.0f / 64.0f), ambientcolor);
// basic lit geometry
R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, t->lightmapcolor[0], t->lightmapcolor[1], t->lightmapcolor[2], t->lightmapcolor[3]);
// add pants/shirt if needed
- if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
- R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * t->lightmapcolor[0], ent->colormap_pantscolor[1] * t->lightmapcolor[1], ent->colormap_pantscolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
- if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
- R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * t->lightmapcolor[0], ent->colormap_shirtcolor[1] * t->lightmapcolor[1], ent->colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
+ if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
+ R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * t->lightmapcolor[0], rsurface.colormap_pantscolor[1] * t->lightmapcolor[1], rsurface.colormap_pantscolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
+ if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
+ R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * t->lightmapcolor[0], rsurface.colormap_shirtcolor[1] * t->lightmapcolor[1], rsurface.colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
// now add ambient passes if needed
if (VectorLength2(ambientcolor) >= (1.0f/1048576.0f))
{
R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->basetexture, &t->currenttexmatrix, ambientcolor[0], ambientcolor[1], ambientcolor[2], t->lightmapcolor[3]);
- if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
- R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * ambientcolor[0], ent->colormap_pantscolor[1] * ambientcolor[1], ent->colormap_pantscolor[2] * ambientcolor[2], t->lightmapcolor[3]);
- if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
- R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * ambientcolor[0], ent->colormap_shirtcolor[1] * ambientcolor[1], ent->colormap_shirtcolor[2] * ambientcolor[2], t->lightmapcolor[3]);
+ if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
+ R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * ambientcolor[0], rsurface.colormap_pantscolor[1] * ambientcolor[1], rsurface.colormap_pantscolor[2] * ambientcolor[2], t->lightmapcolor[3]);
+ if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
+ R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * ambientcolor[0], rsurface.colormap_shirtcolor[1] * ambientcolor[1], rsurface.colormap_shirtcolor[2] * ambientcolor[2], t->lightmapcolor[3]);
}
}
if (t->currentskinframe->glow != NULL && !gl_lightmaps.integer)
//if (rsurface.entity == r_refdef.scene.worldentity)
// return;
rsurface.entity = r_refdef.scene.worldentity;
+ rsurface.ent_skinnum = 0;
+ rsurface.ent_qwskin = -1;
+ rsurface.ent_shadertime = 0;
+ Vector4Set(rsurface.ent_color, 1, 1, 1, 1);
+ rsurface.ent_flags = r_refdef.scene.worldentity->flags;
if (rsurface.array_size < model->surfmesh.num_vertices)
R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
rsurface.matrix = identitymatrix;
rsurface.inversematrix = identitymatrix;
+ rsurface.matrixscale = 1;
+ rsurface.inversematrixscale = 1;
R_Mesh_Matrix(&identitymatrix);
- VectorCopy(r_refdef.view.origin, rsurface.modelorg);
+ VectorCopy(r_refdef.view.origin, rsurface.localvieworigin);
+ Vector4Copy(r_refdef.fogplane, rsurface.fogplane);
+ rsurface.fograngerecip = r_refdef.fograngerecip;
+ rsurface.fogheightfade = r_refdef.fogheightfade;
+ rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist;
+ rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
VectorSet(rsurface.modellight_ambient, 0, 0, 0);
VectorSet(rsurface.modellight_diffuse, 0, 0, 0);
VectorSet(rsurface.modellight_lightdir, 0, 0, 1);
//if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
// return;
rsurface.entity = (entity_render_t *)ent;
+ rsurface.ent_skinnum = ent->skinnum;
+ rsurface.ent_qwskin = (ent->entitynumber <= cl.maxclients && ent->entitynumber >= 1 && cls.protocol == PROTOCOL_QUAKEWORLD && cl.scores[ent->entitynumber - 1].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl")) ? (ent->entitynumber - 1) : -1;
+ rsurface.ent_shadertime = ent->shadertime;
+ Vector4Set(rsurface.ent_color, ent->colormod[0], ent->colormod[1], ent->colormod[2], ent->alpha);
+ rsurface.ent_flags = ent->flags;
if (rsurface.array_size < model->surfmesh.num_vertices)
R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
rsurface.matrix = ent->matrix;
rsurface.inversematrix = ent->inversematrix;
+ rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
+ rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
R_Mesh_Matrix(&rsurface.matrix);
- Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.modelorg);
- 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];
- rsurface.modellight_diffuse[0] = ent->modellight_diffuse[0] * ent->colormod[0];
- rsurface.modellight_diffuse[1] = ent->modellight_diffuse[1] * ent->colormod[1];
- rsurface.modellight_diffuse[2] = ent->modellight_diffuse[2] * ent->colormod[2];
+ Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
+ Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
+ rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
+ rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
+ rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
+ rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
+ VectorCopy(ent->modellight_ambient, rsurface.modellight_ambient);
VectorCopy(ent->modellight_diffuse, rsurface.modellight_diffuse);
VectorCopy(ent->modellight_lightdir, rsurface.modellight_lightdir);
VectorCopy(ent->colormap_pantscolor, rsurface.colormap_pantscolor);
rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
}
+void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, int entflags, double shadertime, float r, float g, float b, float a, int numvertices, const float *vertex3f, const float *texcoord2f, const float *normal3f, const float *svector3f, const float *tvector3f, const float *color4f, int numtriangles, const int *element3i, const unsigned short *element3s, qboolean wantnormals, qboolean wanttangents)
+{
+ rsurface.entity = r_refdef.scene.worldentity;
+ rsurface.ent_skinnum = 0;
+ rsurface.ent_qwskin = -1;
+ rsurface.ent_shadertime = shadertime;
+ Vector4Set(rsurface.ent_color, r, g, b, a);
+ rsurface.ent_flags = entflags;
+ rsurface.modelnum_vertices = numvertices;
+ rsurface.modelnum_triangles = numtriangles;
+ if (rsurface.array_size < rsurface.modelnum_vertices)
+ R_Mesh_ResizeArrays(rsurface.modelnum_vertices);
+ rsurface.matrix = *matrix;
+ rsurface.inversematrix = *inversematrix;
+ rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
+ rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
+ R_Mesh_Matrix(&rsurface.matrix);
+ Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
+ Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
+ rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
+ rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
+ rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
+ rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
+ 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.basepolygonoffset = r_refdef.polygonoffset;
+ if (wanttangents)
+ {
+ rsurface.modelvertex3f = vertex3f;
+ rsurface.modelsvector3f = svector3f ? svector3f : rsurface.array_modelsvector3f;
+ rsurface.modeltvector3f = tvector3f ? tvector3f : rsurface.array_modeltvector3f;
+ rsurface.modelnormal3f = normal3f ? normal3f : rsurface.array_modelnormal3f;
+ }
+ else if (wantnormals)
+ {
+ rsurface.modelvertex3f = vertex3f;
+ rsurface.modelsvector3f = NULL;
+ rsurface.modeltvector3f = NULL;
+ rsurface.modelnormal3f = normal3f ? normal3f : rsurface.array_modelnormal3f;
+ }
+ else
+ {
+ rsurface.modelvertex3f = vertex3f;
+ rsurface.modelsvector3f = NULL;
+ rsurface.modeltvector3f = NULL;
+ rsurface.modelnormal3f = NULL;
+ }
+ rsurface.modelvertex3f_bufferobject = 0;
+ rsurface.modelvertex3f_bufferoffset = 0;
+ rsurface.modelsvector3f_bufferobject = 0;
+ rsurface.modelsvector3f_bufferoffset = 0;
+ rsurface.modeltvector3f_bufferobject = 0;
+ rsurface.modeltvector3f_bufferoffset = 0;
+ rsurface.modelnormal3f_bufferobject = 0;
+ rsurface.modelnormal3f_bufferoffset = 0;
+ rsurface.generatedvertex = true;
+ rsurface.modellightmapcolor4f = color4f;
+ rsurface.modellightmapcolor4f_bufferobject = 0;
+ rsurface.modellightmapcolor4f_bufferoffset = 0;
+ rsurface.modeltexcoordtexture2f = texcoord2f;
+ rsurface.modeltexcoordtexture2f_bufferobject = 0;
+ rsurface.modeltexcoordtexture2f_bufferoffset = 0;
+ rsurface.modeltexcoordlightmap2f = NULL;
+ rsurface.modeltexcoordlightmap2f_bufferobject = 0;
+ rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
+ rsurface.modelelement3i = element3i;
+ rsurface.modelelement3s = element3s;
+ rsurface.modelelement3i_bufferobject = 0;
+ rsurface.modelelement3s_bufferobject = 0;
+ rsurface.modellightmapoffsets = NULL;
+ rsurface.modelsurfaces = NULL;
+ rsurface.vertex3f = rsurface.modelvertex3f;
+ rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
+ rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
+ rsurface.svector3f = rsurface.modelsvector3f;
+ rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
+ rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
+ rsurface.tvector3f = rsurface.modeltvector3f;
+ rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
+ rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
+ rsurface.normal3f = rsurface.modelnormal3f;
+ rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
+ rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
+ rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
+
+ if (rsurface.modelnum_vertices && rsurface.modelelement3i)
+ {
+ if ((wantnormals || wanttangents) && !normal3f)
+ Mod_BuildNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
+ if (wanttangents && !svector3f)
+ 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);
+ }
+}
+
+float RSurf_FogPoint(const float *v)
+{
+ // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
+ float FogPlaneViewDist = r_refdef.fogplaneviewdist;
+ float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
+ float FogHeightFade = r_refdef.fogheightfade;
+ float fogfrac;
+ unsigned int fogmasktableindex;
+ if (r_refdef.fogplaneviewabove)
+ fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
+ else
+ fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
+ fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
+ return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
+}
+
+float RSurf_FogVertex(const float *v)
+{
+ // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
+ float FogPlaneViewDist = rsurface.fogplaneviewdist;
+ float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
+ float FogHeightFade = rsurface.fogheightfade;
+ float fogfrac;
+ unsigned int fogmasktableindex;
+ if (r_refdef.fogplaneviewabove)
+ fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
+ else
+ fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
+ fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.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)
+void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, const msurface_t **texturesurfacelist)
{
int deformindex;
int texturesurfaceindex;
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);
R_Mesh_VertexPointer(rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
}
-void RSurf_DrawBatch_Simple(int texturenumsurfaces, msurface_t **texturesurfacelist)
+void RSurf_DrawBatch_Simple(int texturenumsurfaces, const msurface_t **texturesurfacelist)
{
int i, j;
const msurface_t *surface = texturesurfacelist[0];
}
}
-static void RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(int texturenumsurfaces, msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit, int refractiontexunit, int reflectiontexunit)
+static void RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(int texturenumsurfaces, const msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit, int refractiontexunit, int reflectiontexunit)
{
int i, planeindex, vertexindex;
float d, bestd;
vec3_t vert;
const float *v;
r_waterstate_waterplane_t *p, *bestp;
- msurface_t *surface;
+ const msurface_t *surface;
if (r_waterstate.renderingscene)
return;
for (i = 0;i < texturenumsurfaces;i++)
}
}
-static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit)
+static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, const msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit)
{
int i;
int j;
}
}
-static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
+static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist)
{
int j;
int texturesurfaceindex;
}
}
-static void RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(int texturenumsurfaces, msurface_t **texturesurfacelist)
+static void RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(int texturenumsurfaces, const msurface_t **texturesurfacelist)
{
int texturesurfaceindex;
int i;
- float *v, *c2;
+ const float *v;
+ float *c2;
for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
{
const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
rsurface.lightmapcolor4f_bufferoffset = 0;
}
-static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, msurface_t **texturesurfacelist)
+static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, const msurface_t **texturesurfacelist)
{
int texturesurfaceindex;
int i;
float f;
- float *v, *c, *c2;
+ const float *v;
+ const float *c;
+ float *c2;
if (rsurface.lightmapcolor4f)
{
// generate color arrays for the surfaces in this list
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;
rsurface.lightmapcolor4f_bufferoffset = 0;
}
-static void RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(int texturenumsurfaces, msurface_t **texturesurfacelist)
+static void RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(int texturenumsurfaces, const msurface_t **texturesurfacelist)
{
int texturesurfaceindex;
int i;
float f;
- float *v, *c, *c2;
+ const float *v;
+ const float *c;
+ float *c2;
if (!rsurface.lightmapcolor4f)
return;
// generate color arrays for the surfaces in this list
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);
rsurface.lightmapcolor4f_bufferoffset = 0;
}
-static void RSurf_DrawBatch_GL11_ApplyColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a)
+static void RSurf_DrawBatch_GL11_ApplyColor(int texturenumsurfaces, const msurface_t **texturesurfacelist, float r, float g, float b, float a)
{
int texturesurfaceindex;
int i;
- float *c, *c2;
+ const float *c;
+ float *c2;
if (!rsurface.lightmapcolor4f)
return;
for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
rsurface.lightmapcolor4f_bufferoffset = 0;
}
-static void RSurf_DrawBatch_GL11_ApplyAmbient(int texturenumsurfaces, msurface_t **texturesurfacelist)
+static void RSurf_DrawBatch_GL11_ApplyAmbient(int texturenumsurfaces, const msurface_t **texturesurfacelist)
{
int texturesurfaceindex;
int i;
- float *c, *c2;
+ const float *c;
+ float *c2;
if (!rsurface.lightmapcolor4f)
return;
for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
rsurface.lightmapcolor4f_bufferoffset = 0;
}
-static void RSurf_DrawBatch_GL11_Lightmap(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
+static void RSurf_DrawBatch_GL11_Lightmap(int texturenumsurfaces, const msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
{
// TODO: optimize
rsurface.lightmapcolor4f = NULL;
RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 0, -1);
}
-static void RSurf_DrawBatch_GL11_Unlit(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
+static void RSurf_DrawBatch_GL11_Unlit(int texturenumsurfaces, const msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
{
// TODO: optimize applyfog && applycolor case
// just apply fog if necessary, and tint the fog color array if necessary
RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
}
-static void RSurf_DrawBatch_GL11_VertexColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
+static void RSurf_DrawBatch_GL11_VertexColor(int texturenumsurfaces, const msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
{
int texturesurfaceindex;
int i;
RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
}
-static void RSurf_DrawBatch_GL11_ApplyVertexShade(int texturenumsurfaces, msurface_t **texturesurfacelist, float *r, float *g, float *b, float *a, qboolean *applycolor)
+static void RSurf_DrawBatch_GL11_ApplyVertexShade(int texturenumsurfaces, const msurface_t **texturesurfacelist, float *r, float *g, float *b, float *a, qboolean *applycolor)
{
int texturesurfaceindex;
int i;
float f;
- float *v, *c, *c2, alpha;
+ float alpha;
+ const float *v;
+ const float *n;
+ float *c;
vec3_t ambientcolor;
vec3_t diffusecolor;
vec3_t lightdir;
const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
int numverts = surface->num_vertices;
v = rsurface.vertex3f + 3 * surface->num_firstvertex;
- c2 = rsurface.normal3f + 3 * surface->num_firstvertex;
+ n = rsurface.normal3f + 3 * surface->num_firstvertex;
c = rsurface.array_color4f + 4 * surface->num_firstvertex;
// q3-style directional shading
- for (i = 0;i < numverts;i++, v += 3, c2 += 3, c += 4)
+ for (i = 0;i < numverts;i++, v += 3, n += 3, c += 4)
{
- if ((f = DotProduct(c2, lightdir)) > 0)
+ if ((f = DotProduct(n, lightdir)) > 0)
VectorMA(ambientcolor, f, diffusecolor, c);
else
VectorCopy(ambientcolor, c);
}
}
-static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
+static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, const msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
{
RSurf_DrawBatch_GL11_ApplyVertexShade(texturenumsurfaces, texturesurfacelist, &r, &g, &b, &a, &applycolor);
if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
}
-static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, msurface_t **texturesurfacelist)
+static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
{
// transparent sky would be ridiculous
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
GL_Color(1, 1, 1, 1);
}
-static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth)
+static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
{
if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION)))
return;
GL_LockArrays(0, 0);
}
-static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth)
+static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
{
// OpenGL 1.3 path - anything not completely ancient
int texturesurfaceindex;
for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
{
int i;
- float f, *v, *c;
+ float f;
+ const float *v;
+ float *c;
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];
}
}
-static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth)
+static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
{
// OpenGL 1.1 - crusty old voodoo path
int texturesurfaceindex;
for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
{
int i;
- float f, *v, *c;
+ float f;
+ const float *v;
+ float *c;
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];
}
}
-static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth)
+static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
{
float c[4];
RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
}
-static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth)
+static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
{
CHECKGLERROR
RSurf_SetupDepthAndCulling();
CHECKGLERROR
}
-static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth)
+static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
{
CHECKGLERROR
RSurf_SetupDepthAndCulling();
int i, j;
int texturenumsurfaces, endsurface;
texture_t *texture;
- msurface_t *surface;
- msurface_t *texturesurfacelist[1024];
+ const msurface_t *surface;
+ const msurface_t *texturesurfacelist[1024];
// if the model is static it doesn't matter what value we give for
// wantnormals and wanttangents, so this logic uses only rules applicable
GL_AlphaTest(false);
}
-static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly)
+static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly)
{
const entity_render_t *queueentity = r_refdef.scene.worldentity;
CHECKGLERROR
CHECKGLERROR
}
-void R_QueueWorldSurfaceList(int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly)
+void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly)
{
int i, j;
texture_t *texture;
}
}
-static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity)
+static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity)
{
CHECKGLERROR
if (depthonly)
CHECKGLERROR
}
-void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly)
+void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly)
{
int i, j;
texture_t *texture;
}
}
-void R_DrawDebugModel(entity_render_t *ent)
+void R_DecalSystem_Reset(decalsystem_t *decalsystem)
+{
+ if (decalsystem->decals)
+ Mem_Free(decalsystem->decals);
+ memset(decalsystem, 0, sizeof(*decalsystem));
+}
+
+void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, const float *v1, const float *v2, const float *t0, const float *t1, const float *t2, const float *c0, const float *c1, const float *c2, int triangleindex)
{
+ float *v3f;
+ float *tc2f;
+ float *c4f;
+ float ca;
+ tridecal_t *decal;
+ tridecal_t *decals;
+ int i;
+ int maxdecals;
+
+ // expand or initialize the system
+ if (decalsystem->maxdecals <= decalsystem->numdecals)
+ {
+ decalsystem_t old = *decalsystem;
+ qboolean useshortelements;
+ decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
+ useshortelements = decalsystem->maxdecals * 3 <= 65536;
+ decalsystem->decals = Mem_Alloc(cls.levelmempool, decalsystem->maxdecals * (sizeof(tridecal_t) + sizeof(float[3][3]) + sizeof(float[3][2]) + sizeof(float[3][4]) + sizeof(int[3]) + (useshortelements ? sizeof(unsigned short[3]) : 0)));
+ decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
+ decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
+ decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
+ decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
+ decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
+ if (decalsystem->numdecals)
+ {
+ memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
+ memcpy(decalsystem->vertex3f, old.vertex3f, decalsystem->numdecals * sizeof(float[3][3]));
+ memcpy(decalsystem->texcoord2f, old.texcoord2f, decalsystem->numdecals * sizeof(float[3][2]));
+ memcpy(decalsystem->color4f, old.color4f, decalsystem->numdecals * sizeof(float[3][4]));
+ }
+ Mem_Free(old.decals);
+ for (i = 0;i < decalsystem->maxdecals*3;i++)
+ decalsystem->element3i[i] = i;
+ if (useshortelements)
+ for (i = 0;i < decalsystem->maxdecals*3;i++)
+ decalsystem->element3s[i] = i;
+ }
+
+ // grab a decal and search for another free slot for the next one
+ maxdecals = decalsystem->maxdecals;
+ decals = decalsystem->decals;
+ decal = decalsystem->decals + (i = decalsystem->freedecal++);
+ v3f = decalsystem->vertex3f + 9*i;
+ tc2f = decalsystem->texcoord2f + 6*i;
+ c4f = decalsystem->color4f + 12*i;
+ for (i = decalsystem->freedecal;i < maxdecals && decals[i].colors[0][3];i++)
+ ;
+ decalsystem->freedecal = i;
+ if (decalsystem->numdecals <= i)
+ decalsystem->numdecals = i + 1;
+
+ // initialize the decal
+ decal->lived = 0;
+ decal->triangleindex = triangleindex;
+ decal->colors[0][0] = (unsigned char)(c0[0]*255.0f);
+ decal->colors[0][1] = (unsigned char)(c0[1]*255.0f);
+ decal->colors[0][2] = (unsigned char)(c0[2]*255.0f);
+ decal->colors[0][3] = 255;
+ decal->colors[1][0] = (unsigned char)(c1[0]*255.0f);
+ decal->colors[1][1] = (unsigned char)(c1[1]*255.0f);
+ decal->colors[1][2] = (unsigned char)(c1[2]*255.0f);
+ decal->colors[1][3] = 255;
+ decal->colors[2][0] = (unsigned char)(c2[0]*255.0f);
+ decal->colors[2][1] = (unsigned char)(c2[1]*255.0f);
+ decal->colors[2][2] = (unsigned char)(c2[2]*255.0f);
+ decal->colors[2][3] = 255;
+ v3f[0] = v0[0];
+ v3f[1] = v0[1];
+ v3f[2] = v0[2];
+ v3f[3] = v1[0];
+ v3f[4] = v1[1];
+ v3f[5] = v1[2];
+ v3f[6] = v2[0];
+ v3f[7] = v2[1];
+ v3f[8] = v2[2];
+ tc2f[0] = t0[0];
+ tc2f[1] = t0[1];
+ tc2f[2] = t1[0];
+ tc2f[3] = t1[1];
+ tc2f[4] = t2[0];
+ tc2f[5] = t2[1];
+ ca = (1.0f/255.0f);
+ c4f[ 0] = decal->colors[0][0] * ca;
+ c4f[ 1] = decal->colors[0][1] * ca;
+ c4f[ 2] = decal->colors[0][2] * ca;
+ c4f[ 3] = 1;
+ c4f[ 4] = decal->colors[1][0] * ca;
+ c4f[ 5] = decal->colors[1][1] * ca;
+ c4f[ 6] = decal->colors[1][2] * ca;
+ c4f[ 7] = 1;
+ c4f[ 8] = decal->colors[2][0] * ca;
+ c4f[ 9] = decal->colors[2][1] * ca;
+ c4f[10] = decal->colors[2][2] * ca;
+ c4f[11] = 1;
+}
+
+extern cvar_t cl_decals_bias;
+void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize)
+{
+ matrix4x4_t projection;
+ decalsystem_t *decalsystem;
+ qboolean dynamic;
+ dp_model_t *model;
+ const float *vertex3f;
+ const msurface_t *surface;
+ const msurface_t *surfaces;
+ const int *surfacelist;
+ int numvertices;
+ int numtriangles;
+ int numsurfacelist;
+ int surfacelistindex;
+ int triangleindex;
+ int cornerindex;
+ int index;
+ int numpoints;
+ const int *e;
+ float localorigin[3];
+ float localnormal[3];
+ float localmins[3];
+ float localmaxs[3];
+ float localsize;
+ float ilocalsize;
+ float v[9][3];
+ float tc[9][2];
+ float c[9][4];
+ //float normal[3];
+ float planes[6][4];
+ float f;
+ float points[2][9][3];
+ float angles[3];
+ float temp[3];
+
+ model = ent->model;
+ if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
+ {
+ R_DecalSystem_Reset(&ent->decalsystem);
+ return;
+ }
+
+ decalsystem = &ent->decalsystem;
+ if (decalsystem->model != model)
+ R_DecalSystem_Reset(decalsystem);
+ decalsystem->model = model;
+
+ RSurf_ActiveModelEntity(ent, false, false);
+
+ Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
+ Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
+ VectorNormalize(localnormal);
+ localsize = worldsize*rsurface.inversematrixscale;
+ ilocalsize = 1.0f / localsize;
+ localmins[0] = localorigin[0] - localsize;
+ localmins[1] = localorigin[1] - localsize;
+ localmins[2] = localorigin[2] - localsize;
+ localmaxs[0] = localorigin[0] + localsize;
+ localmaxs[1] = localorigin[1] + localsize;
+ localmaxs[2] = localorigin[2] + localsize;
+
+ //VectorCopy(localnormal, planes[4]);
+ //VectorVectors(planes[4], planes[2], planes[0]);
+ AnglesFromVectors(angles, localnormal, NULL, false);
+ AngleVectors(angles, planes[0], planes[2], planes[4]);
+ VectorNegate(planes[0], planes[1]);
+ VectorNegate(planes[2], planes[3]);
+ VectorNegate(planes[4], planes[5]);
+ planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
+ planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
+ planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
+ planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
+ planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
+ planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
+
+#if 1
+// works
+{
+ matrix4x4_t forwardprojection;
+ Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
+ Matrix4x4_Invert_Simple(&projection, &forwardprojection);
+}
+#else
+// broken
+{
+ float projectionvector[4][3];
+ VectorScale(planes[0], ilocalsize, projectionvector[0]);
+ VectorScale(planes[2], ilocalsize, projectionvector[1]);
+ VectorScale(planes[4], ilocalsize, projectionvector[2]);
+ projectionvector[0][0] = planes[0][0] * ilocalsize;
+ projectionvector[0][1] = planes[1][0] * ilocalsize;
+ projectionvector[0][2] = planes[2][0] * ilocalsize;
+ projectionvector[1][0] = planes[0][1] * ilocalsize;
+ projectionvector[1][1] = planes[1][1] * ilocalsize;
+ projectionvector[1][2] = planes[2][1] * ilocalsize;
+ projectionvector[2][0] = planes[0][2] * ilocalsize;
+ projectionvector[2][1] = planes[1][2] * ilocalsize;
+ projectionvector[2][2] = planes[2][2] * ilocalsize;
+ projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
+ projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
+ projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
+ Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
+}
+#endif
+
+ dynamic = model->surfmesh.isanimated;
+ vertex3f = rsurface.modelvertex3f;
+ numsurfacelist = model->nummodelsurfaces;
+ surfacelist = model->sortedmodelsurfaces;
+ surfaces = model->data_surfaces;
+ for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
+ {
+ surface = surfaces + surfacelist[surfacelistindex];
+ // skip transparent surfaces
+ if ((surface->texture->surfaceflags & Q3SURFACEFLAG_NOMARKS) || surface->texture->currentalpha < 1 || (surface->texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION)))
+ continue;
+ if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
+ continue;
+ numvertices = surface->num_vertices;
+ numtriangles = surface->num_triangles;
+ for (triangleindex = 0, e = model->surfmesh.data_element3i + 3*surface->num_firsttriangle;triangleindex < numtriangles;triangleindex++, e += 3)
+ {
+ for (cornerindex = 0;cornerindex < 3;cornerindex++)
+ {
+ index = 3*e[cornerindex];
+ VectorCopy(vertex3f + index, v[cornerindex]);
+ }
+ // cull backfaces
+ //TriangleNormal(v[0], v[1], v[2], normal);
+ //if (DotProduct(normal, localnormal) < 0.0f)
+ // continue;
+ // clip by each of the box planes formed from the projection matrix
+ // if anything survives, we emit the decal
+ numpoints = PolygonF_Clip(3 , v[0] , planes[0][0], planes[0][1], planes[0][2], planes[0][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[1][0]);
+ numpoints = PolygonF_Clip(numpoints, points[1][0], planes[1][0], planes[1][1], planes[1][2], planes[1][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[0][0]);
+ numpoints = PolygonF_Clip(numpoints, points[0][0], planes[2][0], planes[2][1], planes[2][2], planes[2][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[1][0]);
+ numpoints = PolygonF_Clip(numpoints, points[1][0], planes[3][0], planes[3][1], planes[3][2], planes[3][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[0][0]);
+ numpoints = PolygonF_Clip(numpoints, points[0][0], planes[4][0], planes[4][1], planes[4][2], planes[4][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[1][0]);
+ numpoints = PolygonF_Clip(numpoints, points[1][0], planes[5][0], planes[5][1], planes[5][2], planes[5][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), v[0]);
+ if (numpoints < 3)
+ continue;
+ // some part of the triangle survived, so we have to accept it...
+ if (dynamic)
+ {
+ // dynamic always uses the original triangle
+ numpoints = 3;
+ for (cornerindex = 0;cornerindex < 3;cornerindex++)
+ {
+ index = 3*e[cornerindex];
+ VectorCopy(vertex3f + index, v[cornerindex]);
+ }
+ }
+ for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
+ {
+ // convert vertex positions to texcoords
+ Matrix4x4_Transform(&projection, v[cornerindex], temp);
+ tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
+ tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
+ // calculate distance fade from the projection origin
+ f = a * (1.0f-fabs(temp[0]));
+ f = max(0.0f, f);
+ c[cornerindex][0] = r * f;
+ c[cornerindex][1] = g * f;
+ c[cornerindex][2] = b * f;
+ c[cornerindex][3] = 1.0f;
+ //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
+ }
+ if (dynamic)
+ R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[1], v[2], tc[0], tc[1], tc[2], c[0], c[1], c[2], triangleindex);
+ else
+ for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
+ R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[cornerindex+1], v[cornerindex+2], tc[0], tc[cornerindex+1], tc[cornerindex+2], c[0], c[cornerindex+1], c[cornerindex+2], -1);
+ }
+ }
+}
+
+void R_DecalSystem_SplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize)
+{
+ int renderentityindex;
+ float worldmins[3];
+ float worldmaxs[3];
+ entity_render_t *ent;
+
+ worldmins[0] = worldorigin[0] - worldsize;
+ worldmins[1] = worldorigin[1] - worldsize;
+ worldmins[2] = worldorigin[2] - worldsize;
+ worldmaxs[0] = worldorigin[0] + worldsize;
+ worldmaxs[1] = worldorigin[1] + worldsize;
+ worldmaxs[2] = worldorigin[2] + worldsize;
+
+ R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize);
+
+ for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
+ {
+ ent = r_refdef.scene.entities[renderentityindex];
+ if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
+ continue;
+
+ R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize);
+ }
+}
+
+extern skinframe_t *decalskinframe;
+static void R_DrawModelDecals_Entity(entity_render_t *ent)
+{
+ int i;
+ decalsystem_t *decalsystem = &ent->decalsystem;
+ int numdecals;
+ tridecal_t *decal;
+ float frametime;
+ float fadedelay;
+ float faderate;
+ float alpha;
+ float *v3f;
+ float *c4f;
+ const int *e;
+
+ if (!decalsystem->numdecals)
+ return;
+
+ if (r_showsurfaces.integer)
+ return;
+
+ if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
+ {
+ R_DecalSystem_Reset(decalsystem);
+ return;
+ }
+
+ // if the model is static it doesn't matter what value we give for
+ // wantnormals and wanttangents, so this logic uses only rules applicable
+ // to a model, knowing that they are meaningless otherwise
+ if (ent == r_refdef.scene.worldentity)
+ RSurf_ActiveWorldEntity();
+ else
+ RSurf_ActiveModelEntity(ent, false, false);
+
+ if (decalsystem->lastupdatetime)
+ frametime = cl.time - decalsystem->lastupdatetime;
+ else
+ frametime = 0;
+ decalsystem->lastupdatetime = cl.time;
+ decal = decalsystem->decals;
+ numdecals = decalsystem->numdecals;
+
+ fadedelay = cl_decals_time.value;
+ faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
+
+ for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
+ {
+ if (!decal->colors[0][3])
+ continue;
+
+ decal->lived += frametime;
+ if (decal->lived >= fadedelay)
+ {
+ alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
+ if (alpha <= 0)
+ {
+ // kill the decal by zeroing vertex data
+ memset(decalsystem->vertex3f + 9*i, 0, sizeof(float[3][3]));
+ memset(decalsystem->texcoord2f + 6*i, 0, sizeof(float[3][2]));
+ memset(decalsystem->color4f + 12*i, 0, sizeof(float[3][4]));
+ memset(decal, 0, sizeof(*decal));
+ if (decalsystem->freedecal > i)
+ decalsystem->freedecal = i;
+ continue;
+ }
+
+ // update color values for fading decals
+ alpha *= (1.0f/255.0f);
+ c4f = decalsystem->color4f + 12*i;
+ c4f[ 0] = decal->colors[0][0] * alpha;
+ c4f[ 1] = decal->colors[0][1] * alpha;
+ c4f[ 2] = decal->colors[0][2] * alpha;
+ c4f[ 3] = 1;
+ c4f[ 4] = decal->colors[1][0] * alpha;
+ c4f[ 5] = decal->colors[1][1] * alpha;
+ c4f[ 6] = decal->colors[1][2] * alpha;
+ c4f[ 7] = 1;
+ c4f[ 8] = decal->colors[2][0] * alpha;
+ c4f[ 9] = decal->colors[2][1] * alpha;
+ c4f[10] = decal->colors[2][2] * alpha;
+ c4f[11] = 1;
+ }
+
+ // update vertex positions for animated models
+ if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnum_triangles)
+ {
+ e = rsurface.modelelement3i + 3*decal->triangleindex;
+ v3f = decalsystem->vertex3f + 9*i;
+ VectorCopy(rsurface.vertex3f + 3*e[0], v3f);
+ VectorCopy(rsurface.vertex3f + 3*e[1], v3f + 3);
+ VectorCopy(rsurface.vertex3f + 3*e[2], v3f + 6);
+ }
+ }
+
+ // reduce numdecals if possible
+ while (numdecals > 0 && !decalsystem->decals[numdecals - 1].colors[0][3])
+ numdecals--;
+ decalsystem->numdecals = numdecals;
+
+ if (numdecals > 0)
+ {
+ r_refdef.stats.decals += numdecals;
+ // now render the decals all at once
+ // (this assumes they all use one particle font texture!)
+ RSurf_ActiveCustomEntity(&rsurface.matrix, &rsurface.inversematrix, rsurface.ent_flags, rsurface.ent_shadertime, 1, 1, 1, 1, numdecals*3, decalsystem->vertex3f, decalsystem->texcoord2f, NULL, NULL, NULL, decalsystem->color4f, numdecals, decalsystem->element3i, decalsystem->element3s, false, false);
+ R_Mesh_ResetTextureState();
+ R_Mesh_VertexPointer(decalsystem->vertex3f, 0, 0);
+ R_Mesh_TexCoordPointer(0, 2, decalsystem->texcoord2f, 0, 0);
+ R_Mesh_ColorPointer(decalsystem->color4f, 0, 0);
+ R_SetupGenericShader(true);
+ GL_DepthMask(false);
+ GL_DepthRange(0, 1);
+ GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
+ GL_DepthTest(true);
+ GL_CullFace(GL_NONE);
+ GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
+ R_Mesh_TexBind(0, R_GetTexture(decalskinframe->base));
+ //R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
+ GL_LockArrays(0, numdecals * 3);
+ R_Mesh_Draw(0, numdecals * 3, 0, numdecals, decalsystem->element3i, decalsystem->element3s, 0, 0);
+ GL_LockArrays(0, 0);
+ }
+
+ if (numdecals <= 0)
+ {
+ // if there are no decals left, reset decalsystem
+ R_DecalSystem_Reset(decalsystem);
+ }
+}
+
+void R_DrawDebugModel(void)
+{
+ entity_render_t *ent = rsurface.entity;
int i, j, k, l, flagsmask;
const int *elements;
q3mbrush_t *brush;
- msurface_t *surface;
+ const msurface_t *surface;
dp_model_t *model = ent->model;
vec3_t v;
GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
else
GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
- elements = (ent->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
+ elements = (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, 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
extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
int r_maxsurfacelist = 0;
-msurface_t **r_surfacelist = NULL;
+const msurface_t **r_surfacelist = NULL;
void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug)
{
int i, j, endj, f, flagsmask;
r_maxsurfacelist = model->num_surfaces;
if (r_surfacelist)
Mem_Free(r_surfacelist);
- r_surfacelist = (msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
+ r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
}
RSurf_ActiveWorldEntity();
if (debug)
{
- R_DrawDebugModel(r_refdef.scene.worldentity);
+ R_DrawDebugModel();
rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
return;
}
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
}
r_maxsurfacelist = model->num_surfaces;
if (r_surfacelist)
Mem_Free(r_surfacelist);
- r_surfacelist = (msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
+ r_surfacelist = (const 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
if (debug)
{
- R_DrawDebugModel(ent);
+ R_DrawDebugModel();
rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
return;
}
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
}
+
+void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth)
+{
+ static texture_t texture;
+ static msurface_t surface;
+ const msurface_t *surfacelist = &surface;
+
+ // fake enough texture and surface state to render this geometry
+
+ texture.update_lastrenderframe = -1; // regenerate this texture
+ texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
+ texture.currentskinframe = skinframe;
+ texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
+ texture.specularscalemod = 1;
+ texture.specularpowermod = 1;
+
+ surface.texture = &texture;
+ surface.num_triangles = numtriangles;
+ surface.num_firsttriangle = firsttriangle;
+ surface.num_vertices = numvertices;
+ surface.num_firstvertex = firstvertex;
+
+ // now render it
+ rsurface.texture = R_GetCurrentTexture(surface.texture);
+ rsurface.uselightmaptexture = false;
+ R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth);
+}