cvar_t r_motionblur_maxblur = {CVAR_SAVE, "r_motionblur_maxblur", "0.88", "cap for motionblur alpha value"};
cvar_t r_motionblur_randomize = {CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
+// TODO do we want a r_equalize_entities cvar that works on all ents, or would that be a cheat?
+cvar_t r_equalize_entities_fullbright = {CVAR_SAVE, "r_equalize_entities_fullbright", "0", "render fullbright entities by equalizing their lightness, not by not rendering light"};
+cvar_t r_equalize_entities_minambient = {CVAR_SAVE, "r_equalize_entities_minambient", "1", "light equalizing: ensure at least this ambient/diffuse ratio"};
+cvar_t r_equalize_entities_by = {CVAR_SAVE, "r_equalize_entities_by", "0.7", "light equalizing: exponent of dynamics compression (0 = no compression, 1 = full compression)"};
+cvar_t r_equalize_entities_to = {CVAR_SAVE, "r_equalize_entities_to", "0.8", "light equalizing: target light level"};
+
cvar_t r_animcache = {CVAR_SAVE, "r_animcache", "1", "cache animation frames to save CPU usage, primarily optimizes shadows and reflections"};
cvar_t r_depthfirst = {CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
r_refdef.fog_end = 0;
}
-float FogForDistance(vec_t dist)
-{
- unsigned int fogmasktableindex = (unsigned int)(dist * r_refdef.fogmasktabledistmultiplier);
- return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
-}
-
-float FogPoint_World(const vec3_t p)
-{
- return FogForDistance(VectorDistance((p), r_refdef.view.origin));
-}
-
-float FogPoint_Model(const vec3_t p)
-{
- return FogForDistance(VectorDistance((p), rsurface.modelorg) * Matrix4x4_ScaleFromMatrix(&rsurface.matrix));
-}
-
static void R_BuildBlankTextures(void)
{
unsigned char data[4];
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_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
}
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)
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;
Cvar_RegisterVariable(&r_motionblur_vcoeff);
Cvar_RegisterVariable(&r_motionblur_randomize);
Cvar_RegisterVariable(&r_damageblur);
+ Cvar_RegisterVariable(&r_equalize_entities_fullbright);
+ Cvar_RegisterVariable(&r_equalize_entities_minambient);
+ Cvar_RegisterVariable(&r_equalize_entities_by);
+ Cvar_RegisterVariable(&r_equalize_entities_to);
Cvar_RegisterVariable(&r_animcache);
Cvar_RegisterVariable(&r_depthfirst);
Cvar_RegisterVariable(&r_useinfinitefarclip);
{
int i;
entity_render_t *ent;
- vec3_t tempdiffusenormal;
+ vec3_t tempdiffusenormal, avg;
+ vec_t f, fa, fd, fdd;
for (i = 0;i < r_refdef.scene.numentities;i++)
{
vec3_t org;
Matrix4x4_OriginFromMatrix(&ent->matrix, org);
r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal);
+ if(ent->flags & RENDER_EQUALIZE)
+ {
+ // first fix up ambient lighting...
+ if(r_equalize_entities_minambient.value > 0)
+ {
+ fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2];
+ if(fd > 0)
+ {
+ fa = (0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2]);
+ if(fa < r_equalize_entities_minambient.value * fd)
+ {
+ // solve:
+ // fa'/fd' = minambient
+ // fa'+0.25*fd' = fa+0.25*fd
+ // ...
+ // fa' = fd' * minambient
+ // fd'*(0.25+minambient) = fa+0.25*fd
+ // ...
+ // fd' = (fa+0.25*fd) * 1 / (0.25+minambient)
+ // fa' = (fa+0.25*fd) * minambient / (0.25+minambient)
+ // ...
+ fdd = (fa + 0.25f * fd) / (0.25f + r_equalize_entities_minambient.value);
+ f = fdd / fd; // f>0 because all this is additive; f<1 because fdd<fd because this follows from fa < r_equalize_entities_minambient.value * fd
+ VectorMA(ent->modellight_ambient, (1-f)*0.25f, ent->modellight_diffuse, ent->modellight_ambient);
+ VectorScale(ent->modellight_diffuse, f, ent->modellight_diffuse);
+ }
+ }
+ }
+
+ if(r_equalize_entities_to.value > 0 && r_equalize_entities_by.value != 0)
+ {
+ VectorMA(ent->modellight_ambient, 0.25f, ent->modellight_diffuse, avg);
+ f = 0.299f * avg[0] + 0.587f * avg[1] + 0.114f * avg[2];
+ if(f > 0)
+ {
+ f = pow(f / r_equalize_entities_to.value, -r_equalize_entities_by.value);
+ VectorScale(ent->modellight_ambient, f, ent->modellight_ambient);
+ VectorScale(ent->modellight_diffuse, f, ent->modellight_diffuse);
+ }
+ }
+ }
}
else // highly rare
VectorSet(ent->modellight_ambient, 1, 1, 1);
if (R_DrawBrushModelsSky() && r_timereport_active)
R_TimeReport("bmodelsky");
+
+ if (skyrendermasked && skyrenderlater)
+ {
+ // we have to force off the water clipping plane while rendering sky
+ R_SetupView(false);
+ R_Sky();
+ R_SetupView(true);
+ }
}
R_AnimCache_CacheVisibleEntities();
R_Mesh_Matrix(&identitymatrix);
R_Mesh_ResetTextureState();
+ // set up global fogging in worldspace (RSurf_FogVertex depends on this)
+ VectorCopy(r_refdef.view.origin, rsurface.localvieworigin);
+
vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2]; //
vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
{
for (i = 0, v = vertex3f, c = color4f;i < 8;i++, v += 3, c += 4)
{
- f1 = FogPoint_World(v);
+ f1 = RSurf_FogVertex(v);
f2 = 1 - f1;
c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
int i;
float f1, f2, *c;
float color4f[6*4];
+
+ // set up global fogging in worldspace (RSurf_FogVertex depends on this)
+ VectorCopy(r_refdef.view.origin, rsurface.localvieworigin);
+
// this is only called once per entity so numsurfaces is always 1, and
// surfacelist is always {0}, so this code does not handle batches
R_Mesh_Matrix(&ent->matrix);
memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
R_Mesh_ColorPointer(color4f, 0, 0);
Matrix4x4_OriginFromMatrix(&ent->matrix, org);
- f1 = FogPoint_World(org);
+ f1 = RSurf_FogVertex(org);
f2 = 1 - f1;
for (i = 0, c = color4f;i < 6;i++, c += 4)
{
float fog = 1.0f;
float vertex3f[12];
+ // set up global fogging in worldspace (RSurf_FogVertex depends on this)
+ VectorCopy(r_refdef.view.origin, rsurface.localvieworigin);
+
if (r_refdef.fogenabled && !depthdisable) // TODO maybe make the unfog effect a separate flag?
- fog = FogPoint_World(origin);
+ fog = RSurf_FogVertex(origin);
R_Mesh_Matrix(&identitymatrix);
GL_BlendFunc(blendfunc1, blendfunc2);
rsurface.matrix = identitymatrix;
rsurface.inversematrix = identitymatrix;
R_Mesh_Matrix(&identitymatrix);
- VectorCopy(r_refdef.view.origin, rsurface.modelorg);
+ VectorCopy(r_refdef.view.origin, rsurface.localvieworigin);
VectorSet(rsurface.modellight_ambient, 0, 0, 0);
VectorSet(rsurface.modellight_diffuse, 0, 0, 0);
VectorSet(rsurface.modellight_lightdir, 0, 0, 1);
rsurface.matrix = ent->matrix;
rsurface.inversematrix = ent->inversematrix;
R_Mesh_Matrix(&rsurface.matrix);
- Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.modelorg);
+ Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
rsurface.modellight_ambient[0] = ent->modellight_ambient[0] * ent->colormod[0];
rsurface.modellight_ambient[1] = ent->modellight_ambient[1] * ent->colormod[1];
rsurface.modellight_ambient[2] = ent->modellight_ambient[2] * ent->colormod[2];
rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
}
+float RSurf_FogVertex(const float *v)
+{
+ float len = VectorDistance(rsurface.localvieworigin, v);
+ unsigned int fogmasktableindex;
+ fogmasktableindex = (unsigned int)(len * r_refdef.fogmasktabledistmultiplier);
+ return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
+}
+
static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, msurface_t **texturesurfacelist)
{
VectorSubtract(end, start, up);
VectorNormalize(up);
// calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
- VectorSubtract(rsurface.modelorg, center, forward);
+ VectorSubtract(rsurface.localvieworigin, center, forward);
//Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
VectorNegate(forward, forward);
VectorReflect(forward, 0, up, forward);
float viewer[3], d, reflected[3], worldreflected[3];
- VectorSubtract(rsurface.modelorg, vertex, viewer);
+ VectorSubtract(rsurface.localvieworigin, vertex, viewer);
// VectorNormalize(viewer);
d = DotProduct(normal, viewer);
const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4)
{
- f = FogPoint_Model(v);
+ f = RSurf_FogVertex(v);
c2[0] = c[0] * f;
c2[1] = c[1] * f;
c2[2] = c[2] * f;
const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c2 += 4)
{
- f = FogPoint_Model(v);
+ f = RSurf_FogVertex(v);
c2[0] = f;
c2[1] = f;
c2[2] = f;
const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4)
{
- f = FogPoint_Model(v);
+ f = RSurf_FogVertex(v);
c2[0] = c[0] * f + r_refdef.fogcolor[0] * (1 - f);
c2[1] = c[1] * f + r_refdef.fogcolor[1] * (1 - f);
c2[2] = c[2] * f + r_refdef.fogcolor[2] * (1 - f);
if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
return;
R_SetupGenericShader(false);
- if (skyrendernow)
- {
- skyrendernow = false;
- // we have to force off the water clipping plane while rendering sky
- R_SetupView(false);
- R_Sky();
- R_SetupView(true);
- // restore entity matrix
- R_Mesh_Matrix(&rsurface.matrix);
- }
+ skyrenderlater = true;
RSurf_SetupDepthAndCulling();
GL_DepthMask(true);
// LordHavoc: HalfLife maps have freaky skypolys so don't use
const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4)
{
- f = 1 - FogPoint_Model(v);
+ f = 1 - RSurf_FogVertex(v);
c[0] = layercolor[0];
c[1] = layercolor[1];
c[2] = layercolor[2];
const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4)
{
- f = 1 - FogPoint_Model(v);
+ f = 1 - RSurf_FogVertex(v);
c[0] = layer->color[0];
c[1] = layer->color[1];
c[2] = layer->color[2];