]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
changed sky rendering to occur after depthmask polygons, instead of before
[xonotic/darkplaces.git] / gl_rmain.c
index 12402b28fdf982a3f55c2fc4c2620ea888aa98f5..6a0c378d4afb5a646955aa263796403e57c17166 100644 (file)
@@ -44,6 +44,12 @@ cvar_t r_motionblur_vcoeff = {CVAR_SAVE, "r_motionblur_vcoeff", "0.05", "sliding
 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"};
@@ -259,22 +265,6 @@ void FOG_clear(void)
        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];
@@ -1486,10 +1476,10 @@ typedef enum shaderpermutation_e
        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
 }
@@ -2236,7 +2226,7 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                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)
@@ -2691,6 +2681,52 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i
        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;
@@ -2842,6 +2878,10 @@ void GL_Main_Init(void)
        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);
@@ -3240,7 +3280,8 @@ static void R_View_UpdateEntityLighting (void)
 {
        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++)
        {
@@ -3269,6 +3310,47 @@ static void R_View_UpdateEntityLighting (void)
                        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);
@@ -4777,6 +4859,14 @@ void R_RenderScene(void)
 
                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();
@@ -4939,6 +5029,9 @@ void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, floa
        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];
@@ -4952,7 +5045,7 @@ void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, floa
        {
                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;
@@ -5071,6 +5164,10 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight
        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);
@@ -5102,7 +5199,7 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight
                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)
                {
@@ -5173,8 +5270,11 @@ void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, rtexture_
        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);
@@ -5738,7 +5838,7 @@ void RSurf_ActiveWorldEntity(void)
        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);
@@ -5805,7 +5905,7 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
        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];
@@ -5916,6 +6016,14 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
        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)
 {
@@ -6115,7 +6223,7 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta
                                        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);
@@ -6301,7 +6409,7 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta
 
                                float viewer[3], d, reflected[3], worldreflected[3];
 
-                               VectorSubtract(rsurface.modelorg, vertex, viewer);
+                               VectorSubtract(rsurface.localvieworigin, vertex, viewer);
                                // VectorNormalize(viewer);
 
                                d = DotProduct(normal, viewer);
@@ -6651,7 +6759,7 @@ static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, msurface_t **t
                        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;
@@ -6666,7 +6774,7 @@ static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, msurface_t **t
                        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;
@@ -6693,7 +6801,7 @@ static void RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(int texturenumsu
                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);
@@ -6926,16 +7034,7 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, msurface_t **te
        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
@@ -7176,7 +7275,7 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **t
                                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];
@@ -7305,7 +7404,7 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **t
                                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];