added r_shadow_bouncegrid cvar, this feature does realtime global
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 23 Feb 2011 16:13:24 +0000 (16:13 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 23 Feb 2011 16:13:24 +0000 (16:13 +0000)
illumination by particle tracing and uploading a new 3D texture every
frame containing the lighting

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10856 d7cf8633-e32d-0410-b094-e92efae38249

cl_gecko.c
cl_video.c
dpsoftrast.h
gl_draw.c
gl_rmain.c
gl_rsurf.c
gl_textures.c
r_shadow.c
r_shadow.h
r_textures.h

index 015b9be..d92ed0a 100644 (file)
@@ -435,7 +435,7 @@ static void cl_gecko_updatecallback( rtexture_t *texture, void* callbackData ) {
        if( instance->browser ) {
                // TODO: OSGK only supports BGRA right now
                TIMING_TIMESTATEMENT(data = osgk_browser_lock_data( instance->browser, NULL ));
-               R_UpdateTexture( texture, data, 0, 0, instance->width, instance->height );
+               R_UpdateTexture( texture, data, 0, 0, 0, instance->width, instance->height, 1 );
                osgk_browser_unlock_data( instance->browser, data );
        }
 }
index aca8249..2db4756 100644 (file)
@@ -61,7 +61,7 @@ static qboolean OpenStream( clvideo_t * video )
 static void VideoUpdateCallback(rtexture_t *rt, void *data)
 {
        clvideo_t *video = (clvideo_t *) data;
-       R_UpdateTexture( video->cpif.tex, (unsigned char *)video->imagedata, 0, 0, video->cpif.width, video->cpif.height );
+       R_UpdateTexture( video->cpif.tex, (unsigned char *)video->imagedata, 0, 0, 0, video->cpif.width, video->cpif.height, 1 );
 }
 
 static void LinkVideoTexture( clvideo_t *video )
index a3e0103..016d211 100644 (file)
@@ -186,13 +186,14 @@ typedef enum shaderpermutation_e
        SHADERPERMUTATION_SHADOWMAPPCF2 = 1<<19, ///< (lightsource) use higher quality percentage closer filtering on shadowmap test results
        SHADERPERMUTATION_SHADOWSAMPLER = 1<<20, ///< (lightsource) use hardware shadowmap test
        SHADERPERMUTATION_SHADOWMAPVSDCT = 1<<21, ///< (lightsource) use virtual shadow depth cube texture for shadowmap indexing
-       SHADERPERMUTATION_SHADOWMAPORTHO = 1<<22, //< (lightsource) use orthographic shadowmap projection
+       SHADERPERMUTATION_SHADOWMAPORTHO = 1<<22, ///< (lightsource) use orthographic shadowmap projection
        SHADERPERMUTATION_DEFERREDLIGHTMAP = 1<<23, ///< (lightmap) read Texture_ScreenDiffuse/Specular textures and add them on top of lightmapping
        SHADERPERMUTATION_ALPHAKILL = 1<<24, ///< (deferredgeometry) discard pixel if diffuse texture alpha below 0.5
        SHADERPERMUTATION_REFLECTCUBE = 1<<25, ///< fake reflections using global cubemap (not HDRI light probe)
-       SHADERPERMUTATION_NORMALMAPSCROLLBLEND = 1<<26, // (water) counter-direction normalmaps scrolling
-       SHADERPERMUTATION_LIMIT = 1<<27, ///< size of permutations array
-       SHADERPERMUTATION_COUNT = 27 ///< size of shaderpermutationinfo array
+       SHADERPERMUTATION_NORMALMAPSCROLLBLEND = 1<<26, ///< (water) counter-direction normalmaps scrolling
+       SHADERPERMUTATION_BOUNCEGRID = 1<<27, ///< (lightmap) use Texture_BounceGrid as an additional source of ambient light
+       SHADERPERMUTATION_LIMIT = 1<<28, ///< size of permutations array
+       SHADERPERMUTATION_COUNT = 28 ///< size of shaderpermutationinfo array
 }
 shaderpermutation_t;
 
index 1654cd4..38e1c7a 100644 (file)
--- a/gl_draw.c
+++ b/gl_draw.c
@@ -516,7 +516,7 @@ cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, u
        {
                if (pic->tex && pic->width == width && pic->height == height)
                {
-                       R_UpdateTexture(pic->tex, pixels_bgra, 0, 0, width, height);
+                       R_UpdateTexture(pic->tex, pixels_bgra, 0, 0, 0, width, height, 1);
                        return pic;
                }
        }
index 90e49a7..67ebbd2 100644 (file)
@@ -512,8 +512,8 @@ static void R_BuildFogTexture(void)
        }
        if (r_texture_fogattenuation)
        {
-               R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, FOGWIDTH, 1);
-               //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, FOGWIDTH, 1);
+               R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
+               //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
        }
        else
        {
@@ -3438,6 +3438,7 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
        {"#define USEALPHAKILL\n", " alphakill"},
        {"#define USEREFLECTCUBE\n", " reflectcube"},
        {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
+       {"#define USEBOUNCEGRID\n", " bouncegrid"},
 };
 
 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
@@ -3525,6 +3526,7 @@ typedef struct r_glsl_permutation_s
        int tex_Texture_ScreenSpecular;
        int tex_Texture_ReflectMask;
        int tex_Texture_ReflectCube;
+       int tex_Texture_BounceGrid;
        /// locations of detected uniforms in program object, or -1 if not found
        int loc_Texture_First;
        int loc_Texture_Second;
@@ -3555,6 +3557,7 @@ typedef struct r_glsl_permutation_s
        int loc_Texture_ScreenSpecular;
        int loc_Texture_ReflectMask;
        int loc_Texture_ReflectCube;
+       int loc_Texture_BounceGrid;
        int loc_Alpha;
        int loc_BloomBlur_Parameters;
        int loc_ClientTime;
@@ -3608,6 +3611,8 @@ typedef struct r_glsl_permutation_s
        int loc_ShadowMapMatrix;
        int loc_BloomColorSubtract;
        int loc_NormalmapScrollBlend;
+       int loc_BounceGridMatrix;
+       int loc_BounceGridIntensity;
 }
 r_glsl_permutation_t;
 
@@ -3854,6 +3859,7 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
                p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
                p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
+               p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
                p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
                p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
                p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
@@ -3907,6 +3913,8 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
                p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
                p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
+               p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
+               p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
                // initialize the samplers to refer to the texture units we use
                p->tex_Texture_First = -1;
                p->tex_Texture_Second = -1;
@@ -3937,6 +3945,7 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                p->tex_Texture_ScreenSpecular = -1;
                p->tex_Texture_ReflectMask = -1;
                p->tex_Texture_ReflectCube = -1;
+               p->tex_Texture_BounceGrid = -1;
                sampler = 0;
                if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
                if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
@@ -3967,6 +3976,7 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
                if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
                if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
+               if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
                CHECKGLERROR
                Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
        }
@@ -4872,6 +4882,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        static float dummy_colormod[3] = {1, 1, 1};
        float *colormod = rsurface.colormod;
        float m16f[16];
+       matrix4x4_t tempmatrix;
        r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
        if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
                permutation |= SHADERPERMUTATION_ALPHAKILL;
@@ -5025,6 +5036,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= SHADERPERMUTATION_REFLECTION;
                if (rsurface.texture->reflectmasktexture)
                        permutation |= SHADERPERMUTATION_REFLECTCUBE;
+               if (r_shadow_bouncegridtexture)
+                       permutation |= SHADERPERMUTATION_BOUNCEGRID;
                GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
                allow_colormod = R_BlendFuncAllowsColormod(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
        }
@@ -5074,6 +5087,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
                if (rsurface.texture->reflectmasktexture)
                        permutation |= SHADERPERMUTATION_REFLECTCUBE;
+               if (r_shadow_bouncegridtexture)
+                       permutation |= SHADERPERMUTATION_BOUNCEGRID;
                GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
                allow_colormod = R_BlendFuncAllowsColormod(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
        }
@@ -5120,6 +5135,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
                if (rsurface.texture->reflectmasktexture)
                        permutation |= SHADERPERMUTATION_REFLECTCUBE;
+               if (r_shadow_bouncegridtexture)
+                       permutation |= SHADERPERMUTATION_BOUNCEGRID;
                GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
                allow_colormod = R_BlendFuncAllowsColormod(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
        }
@@ -5202,6 +5219,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        // ordinary vertex coloring (q3bsp)
                        mode = SHADERMODE_VERTEXCOLOR;
                }
+               if (r_shadow_bouncegridtexture)
+                       permutation |= SHADERPERMUTATION_BOUNCEGRID;
                GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
                allow_colormod = R_BlendFuncAllowsColormod(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
        }
@@ -5460,6 +5479,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value*rsurface.texture->offsetscale);
                if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
                if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
+               if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegridmatrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
+               if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegridintensity);
 
                if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
                if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
@@ -5504,6 +5525,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
                        }
                }
+               if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegridtexture);
                CHECKGLERROR
                break;
        case RENDERPATH_GL13:
@@ -9139,7 +9161,7 @@ void R_UpdateVariables(void)
                                }
                                if (r_texture_gammaramps)
                                {
-                                       R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, RAMPWIDTH, 1);
+                                       R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
                                }
                                else
                                {
index 4a05866..f04bb2b 100644 (file)
@@ -119,7 +119,7 @@ void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface)
                }
        }
 
-       R_UpdateTexture(surface->lightmaptexture, templight, surface->lightmapinfo->lightmaporigin[0], surface->lightmapinfo->lightmaporigin[1], smax, tmax);
+       R_UpdateTexture(surface->lightmaptexture, templight, surface->lightmapinfo->lightmaporigin[0], surface->lightmapinfo->lightmaporigin[1], 0, smax, tmax, 1);
 
        // update the surface's deluxemap if it has one
        if (surface->deluxemaptexture != r_texture_blanknormalmap)
@@ -157,7 +157,7 @@ void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface)
                        l = (int)(n[2] * 128 + 128);out[0] = bound(0, l, 255);
                        out[3] = 255;
                }
-               R_UpdateTexture(surface->deluxemaptexture, templight, surface->lightmapinfo->lightmaporigin[0], surface->lightmapinfo->lightmaporigin[1], smax, tmax);
+               R_UpdateTexture(surface->deluxemaptexture, templight, surface->lightmapinfo->lightmaporigin[0], surface->lightmapinfo->lightmaporigin[1], 0, smax, tmax, 1);
        }
 }
 
index 62947bb..fc027b2 100644 (file)
@@ -2425,7 +2425,7 @@ int R_TextureHeight(rtexture_t *rt)
        return rt ? ((gltexture_t *)rt)->inputheight : 0;
 }
 
-void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height)
+void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth)
 {
        gltexture_t *glt = (gltexture_t *)rt;
        if (data == NULL)
@@ -2446,6 +2446,8 @@ void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, in
                int outputskip = glt->tilewidth*bpp;
                const unsigned char *input = data;
                unsigned char *output = glt->bufferpixels;
+               if (glt->inputdepth != 1 || glt->sides != 1)
+                       Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n");
                if (x < 0)
                {
                        width += x;
@@ -2470,8 +2472,8 @@ void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, in
                for (j = 0;j < height;j++, output += outputskip, input += inputskip)
                        memcpy(output, input, width*bpp);
        }
-       else if (x || y || width != glt->inputwidth || height != glt->inputheight)
-               R_UploadPartialTexture(glt, data, x, y, 0, width, height, 1);
+       else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth)
+               R_UploadPartialTexture(glt, data, x, y, z, width, height, depth);
        else
                R_UploadFullTexture(glt, data);
 }
index f7549cf..d4c4570 100644 (file)
@@ -327,6 +327,23 @@ cvar_t r_shadow_particletrace_maxbounce = {CVAR_SAVE, "r_shadow_particletrace_ma
 cvar_t r_shadow_particletrace_bounceintensity = {CVAR_SAVE, "r_shadow_particletrace_bounceintensity", "1", "amount of energy carried over after each bounce"};
 cvar_t r_shadow_particletrace_particlespacing = {CVAR_SAVE, "r_shadow_particletrace_particlespacing", "0.25", "overlap setting in terms of particle size, this affects how many particles are used"};
 cvar_t r_shadow_particletrace_updatepercentage = {CVAR_SAVE, "r_shadow_particletrace_updatepercentage", "0.01", "update this fraction of the particles of a light each frame (0 = best performance)"};
+cvar_t r_shadow_bouncegrid = {CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, requires r_shadow_realtime_world 1"};
+cvar_t r_shadow_bouncegrid_dlightparticlemultiplier = {CVAR_SAVE, "r_shadow_bouncegrid_dlightparticlemultiplier", "0", "if set to a high value like 16 this can make dlights look great, but 0 is recommended for performance reasons"};
+cvar_t r_shadow_bouncegrid_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
+cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "1", "overall brightness of bouncegrid texture"};
+cvar_t r_shadow_bouncegrid_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1)"};
+cvar_t r_shadow_bouncegrid_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_maxbounce", "16", "maximum number of bounces for a particle (minimum is 1)"};
+cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "1", "amount of energy carried over after each bounce"};
+cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "16", "brightness of particles contributing to bouncegrid texture"};
+cvar_t r_shadow_bouncegrid_particlespacing = {CVAR_SAVE, "r_shadow_bouncegrid_particlespacing", "32", "emit one particle per this many units (squared) of radius (squared)"};
+cvar_t r_shadow_bouncegrid_spacingx = {CVAR_SAVE, "r_shadow_bouncegrid_spacingx", "64", "unit size of bouncegrid pixel on X axis"};
+cvar_t r_shadow_bouncegrid_spacingy = {CVAR_SAVE, "r_shadow_bouncegrid_spacingy", "64", "unit size of bouncegrid pixel on Y axis"};
+cvar_t r_shadow_bouncegrid_spacingz = {CVAR_SAVE, "r_shadow_bouncegrid_spacingz", "64", "unit size of bouncegrid pixel on Z axis"};
+cvar_t r_shadow_bouncegrid_stablerandom = {CVAR_SAVE, "r_shadow_bouncegrid_stablerandom", "1", "make particle distribution consistent from frame to frame"};
+cvar_t r_shadow_bouncegrid_updateinterval = {CVAR_SAVE, "r_shadow_bouncegrid_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"};
+cvar_t r_shadow_bouncegrid_x = {CVAR_SAVE, "r_shadow_bouncegrid_x", "128", "maximum texture size of bouncegrid on X axis"};
+cvar_t r_shadow_bouncegrid_y = {CVAR_SAVE, "r_shadow_bouncegrid_y", "128", "maximum texture size of bouncegrid on Y axis"};
+cvar_t r_shadow_bouncegrid_z = {CVAR_SAVE, "r_shadow_bouncegrid_z", "64", "maximum texture size of bouncegrid on Z axis"};
 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksum the proportion of hidden pixels controls corona intensity"};
 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
@@ -340,6 +357,12 @@ cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how
 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
 
+rtexture_t *r_shadow_bouncegridtexture;
+matrix4x4_t r_shadow_bouncegridmatrix;
+vec_t r_shadow_bouncegridintensity;
+static double r_shadow_bouncegridtime;
+static int r_shadow_bouncegridresolution[3];
+
 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
 #define ATTENTABLESIZE 256
 // 1D gradient, 2D circle and 3D sphere attenuation textures
@@ -483,6 +506,7 @@ void R_Shadow_FreeShadowMaps(void)
 void r_shadow_start(void)
 {
        // allocate vertex processing arrays
+       r_shadow_bouncegridtexture = NULL;
        r_shadow_attenuationgradienttexture = NULL;
        r_shadow_attenuation2dtexture = NULL;
        r_shadow_attenuation3dtexture = NULL;
@@ -554,6 +578,7 @@ void r_shadow_shutdown(void)
        r_shadow_prepass_width = r_shadow_prepass_height = 0;
 
        CHECKGLERROR
+       r_shadow_bouncegridtexture = NULL;
        r_shadow_attenuationgradienttexture = NULL;
        r_shadow_attenuation2dtexture = NULL;
        r_shadow_attenuation3dtexture = NULL;
@@ -621,6 +646,7 @@ void r_shadow_shutdown(void)
 
 void r_shadow_newmap(void)
 {
+       if (r_shadow_bouncegridtexture) R_FreeTexture(r_shadow_bouncegridtexture);r_shadow_bouncegridtexture = NULL;
        if (r_shadow_lightcorona)                 R_SkinFrame_MarkUsed(r_shadow_lightcorona);
        if (r_editlights_sprcursor)               R_SkinFrame_MarkUsed(r_editlights_sprcursor);
        if (r_editlights_sprlight)                R_SkinFrame_MarkUsed(r_editlights_sprlight);
@@ -692,6 +718,23 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_particletrace_bounceintensity);
        Cvar_RegisterVariable(&r_shadow_particletrace_particlespacing);
        Cvar_RegisterVariable(&r_shadow_particletrace_updatepercentage);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_particlespacing);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingx);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingy);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingz);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_y);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_z);
        Cvar_RegisterVariable(&r_coronas);
        Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
        Cvar_RegisterVariable(&r_coronas_occlusionquery);
@@ -2244,6 +2287,232 @@ void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadow
        R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
 }
 
+static void R_Shadow_UpdateBounceGridTexture(void)
+{
+#define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
+       dlight_t *light;
+       int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
+       int bouncecount;
+       int bouncelimit;
+       int c[3];
+       int hitsupercontentsmask;
+       int maxbounce;
+       int numpixels;
+       int resolution[3];
+       int shootparticles;
+       int shotparticles;
+       int tex[3];
+       trace_t cliptrace;
+       unsigned char *pixel;
+       unsigned char *pixels;
+       unsigned int lightindex;
+       unsigned int range;
+       unsigned int range1;
+       unsigned int range2;
+       unsigned int seed = (unsigned int)(realtime * 1000.0f);
+       vec3_t shotcolor;
+       vec3_t baseshotcolor;
+       vec3_t clipend;
+       vec3_t clipstart;
+       vec3_t ispacing;
+       vec3_t maxs;
+       vec3_t mins;
+       vec3_t size;
+       vec3_t spacing;
+       vec3_t lightcolor;
+       vec_t radius;
+       vec_t s;
+       vec_t lightintensity;
+       float m[16];
+       qboolean isstatic = r_shadow_bouncegrid_updateinterval.value > 1.0f;
+       rtlight_t *rtlight;
+       if (!r_shadow_bouncegrid.integer || !vid.support.ext_texture_3d)
+       {
+               if (r_shadow_bouncegridtexture)
+               {
+                       R_FreeTexture(r_shadow_bouncegridtexture);
+                       r_shadow_bouncegridtexture = NULL;
+               }
+               return;
+       }
+       if (r_refdef.scene.worldmodel)
+       {
+               VectorSet(spacing, bound(1, r_shadow_bouncegrid_spacingx.value, 512), bound(1, r_shadow_bouncegrid_spacingy.value, 512), bound(1, r_shadow_bouncegrid_spacingz.value, 512));
+               VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
+               VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
+               VectorSubtract(maxs, mins, size);
+               resolution[0] = (int)floor(size[0] / spacing[0] + 0.5f);
+               resolution[1] = (int)floor(size[1] / spacing[1] + 0.5f);
+               resolution[2] = (int)floor(size[2] / spacing[2] + 0.5f);
+               resolution[0] = min(resolution[0], bound(4, r_shadow_bouncegrid_x.integer, (int)vid.maxtexturesize_3d));
+               resolution[1] = min(resolution[1], bound(4, r_shadow_bouncegrid_y.integer, (int)vid.maxtexturesize_3d));
+               resolution[2] = min(resolution[2], bound(4, r_shadow_bouncegrid_z.integer, (int)vid.maxtexturesize_3d));
+               spacing[0] = size[0] / resolution[0];
+               spacing[1] = size[1] / resolution[1];
+               spacing[2] = size[2] / resolution[2];
+               ispacing[0] = 1.0f / spacing[0];
+               ispacing[1] = 1.0f / spacing[1];
+               ispacing[2] = 1.0f / spacing[2];
+       }
+       else
+       {
+               VectorSet(resolution, bound(4, r_shadow_bouncegrid_x.integer, (int)vid.maxtexturesize_3d), bound(4, r_shadow_bouncegrid_y.integer, (int)vid.maxtexturesize_3d), bound(4, r_shadow_bouncegrid_z.integer, (int)vid.maxtexturesize_3d));
+               VectorSet(spacing, bound(1, r_shadow_bouncegrid_spacingx.value, 512), bound(1, r_shadow_bouncegrid_spacingy.value, 512), bound(1, r_shadow_bouncegrid_spacingz.value, 512));
+               VectorMultiply(resolution, spacing, size);
+               ispacing[0] = 1.0f / spacing[0];
+               ispacing[1] = 1.0f / spacing[1];
+               ispacing[2] = 1.0f / spacing[2];
+               mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
+               mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
+               mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
+               VectorAdd(mins, size, maxs);
+       }
+       memset(m, 0, sizeof(m));
+       m[0] = 1.0f / size[0];
+       m[3] = -mins[0] * m[0];
+       m[5] = 1.0f / size[1];
+       m[7] = -mins[1] * m[5];
+       m[10] = 1.0f / size[2];
+       m[11] = -mins[2] * m[10];
+       m[15] = 1.0f;
+       Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m);
+       r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value;
+       if (r_shadow_bouncegridtexture && realtime < r_shadow_bouncegridtime + r_shadow_bouncegrid_updateinterval.value && resolution[0] == r_shadow_bouncegridresolution[0] && resolution[1] == r_shadow_bouncegridresolution[1] && resolution[2] == r_shadow_bouncegridresolution[2])
+               return;
+       numpixels = resolution[0]*resolution[1]*resolution[2];
+       // allocate pixels for this update...
+       pixels = Mem_Alloc(r_main_mempool, numpixels * sizeof(unsigned char[4]));
+       // figure out what we want to interact with
+       if (r_shadow_bouncegrid_hitmodels.integer)
+               hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK;
+       else
+               hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
+       // iterate world rtlights
+       range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
+       range1 = isstatic ? 0 : r_refdef.scene.numlights;
+       range2 = range + range1;
+       for (lightindex = 0;lightindex < range2;lightindex++)
+       {
+               if (isstatic)
+               {
+                       light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+                       if (!light || !(light->flags & flag))
+                               continue;
+                       rtlight = &light->rtlight;
+                       // when static, we skip styled lights because they tend to change...
+                       if (rtlight->style > 0)
+                               continue;
+                       VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
+               }
+               else
+               {
+                       if (lightindex < range)
+                       {
+                               light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+                               rtlight = &light->rtlight;
+                       }
+                       else
+                               rtlight = r_refdef.scene.lights[lightindex - range];
+                       // draw only visible lights (major speedup)
+                       if (!rtlight->draw)
+                               continue;
+                       VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
+               }
+               if (!VectorLength2(lightcolor))
+                       continue;
+               // shoot particles from this light
+               // use a calculation for the number of particles that will not
+               // vary with lightstyle, otherwise we get randomized particle
+               // distribution, the seeded random is only consistent for a
+               // consistent number of particles on this light...
+               radius = rtlight->radius * bound(0.0001f, r_shadow_bouncegrid_lightradiusscale.value, 1024.0f);
+               s = rtlight->radius / bound(1.0f, r_shadow_bouncegrid_particlespacing.value, 1048576.0f);
+               lightintensity = VectorLength(rtlight->color) * rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale;
+               if (lightindex >= range)
+                       lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
+               shootparticles = (int)bound(0, lightintensity * s *s, MAXBOUNCEGRIDPARTICLESPERLIGHT);
+               if (!shootparticles)
+                       continue;
+               s = 255.0f * r_shadow_bouncegrid_particleintensity.value / shootparticles;
+               VectorScale(lightcolor, s, baseshotcolor);
+               maxbounce = bound(1, r_shadow_bouncegrid_maxbounce.integer, 16);
+               for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
+               {
+                       if (r_shadow_bouncegrid_stablerandom.integer > 0)
+                               seed = lightindex * 11937 + shotparticles;
+                       VectorCopy(baseshotcolor, shotcolor);
+                       VectorCopy(rtlight->shadoworigin, clipstart);
+                       if (r_shadow_bouncegrid_stablerandom.integer < 0)
+                               VectorRandom(clipend);
+                       else
+                               VectorCheeseRandom(clipend);
+                       VectorMA(clipstart, radius, clipend, clipend);
+                       bouncelimit = 1 + (rtlight->particlecache_updateparticle % maxbounce);
+                       for (bouncecount = 0;;bouncecount++)
+                       {
+                               cliptrace = CL_TraceLine(clipstart, clipend, r_shadow_bouncegrid_hitmodels.integer ? MOVE_HITMODEL : MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true);
+                               //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
+                               if (cliptrace.fraction >= 1.0f)
+                                       break;
+                               if (VectorLength2(shotcolor) < 1.0f)
+                                       break;
+                               if (bouncecount > 0)
+                               {
+                                       // figure out which texture pixel this is in
+                                       tex[0] = (int)((cliptrace.endpos[0] - mins[0]) * ispacing[0]);
+                                       tex[1] = (int)((cliptrace.endpos[1] - mins[1]) * ispacing[1]);
+                                       tex[2] = (int)((cliptrace.endpos[2] - mins[2]) * ispacing[2]);
+                                       if (tex[0] >= 1 && tex[1] >= 1 && tex[2] >= 1 && tex[0] < resolution[0] - 1 && tex[1] < resolution[1] - 1 && tex[2] < resolution[2] - 1)
+                                       {
+                                               // it is within bounds...
+                                               pixel = pixels + 4 * ((tex[2]*resolution[1]+tex[1])*resolution[0]+tex[0]);
+                                               // add to the pixel color
+                                               c[0] = pixel[0] + (int)shotcolor[2];
+                                               c[1] = pixel[1] + (int)shotcolor[1];
+                                               c[2] = pixel[2] + (int)shotcolor[0];
+                                               pixel[0] = (unsigned char)min(c[0], 255);
+                                               pixel[1] = (unsigned char)min(c[1], 255);
+                                               pixel[2] = (unsigned char)min(c[2], 255);
+                                               pixel[3] = 255;
+                                       }
+                               }
+                               if (bouncecount >= bouncelimit)
+                                       break;
+                               // scale down shot color by bounce intensity and texture color
+                               VectorScale(shotcolor, r_shadow_bouncegrid_particlebounceintensity.value, shotcolor);
+                               if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
+                                       VectorMultiply(shotcolor, rsurface.texture->currentskinframe->avgcolor, shotcolor);
+                               // reflect the remaining portion of the line across plane normal
+                               //VectorSubtract(clipend, cliptrace.endpos, clipdiff);
+                               //VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
+                               // random direction, primarily along plane normal
+                               s = VectorDistance(cliptrace.endpos, clipend);
+                               if (r_shadow_bouncegrid_stablerandom.integer < 0)
+                                       VectorRandom(clipend);
+                               else
+                                       VectorCheeseRandom(clipend);
+                               VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
+                               VectorNormalize(clipend);
+                               VectorScale(clipend, s, clipend);
+                               // calculate the new line start and end
+                               VectorCopy(cliptrace.endpos, clipstart);
+                               VectorAdd(clipstart, clipend, clipend);
+                       }
+               }
+       }
+       if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2])
+               R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]);
+       else
+       {
+               VectorCopy(resolution, r_shadow_bouncegridresolution);
+               if (r_shadow_bouncegridtexture)
+                       R_FreeTexture(r_shadow_bouncegridtexture);
+               r_shadow_bouncegridtexture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2], pixels, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
+       }
+       Mem_Free(pixels);
+       r_shadow_bouncegridtime = realtime;
+}
+
 #define MAXPARTICLESPERLIGHT 262144
 #define MAXLIGHTSPERDRAW 1024
 
@@ -4261,6 +4530,8 @@ void R_Shadow_PrepareLights(void)
 
        if (r_editlights.integer)
                R_Shadow_DrawLightSprites();
+
+       R_Shadow_UpdateBounceGridTexture();
 }
 
 void R_Shadow_DrawLights(void)
index b08f00c..003f4b2 100644 (file)
@@ -37,6 +37,11 @@ extern cvar_t r_shadow_texture3d;
 extern cvar_t gl_ext_separatestencil;
 extern cvar_t gl_ext_stenciltwoside;
 
+// used by shader for bouncegrid feature
+extern rtexture_t *r_shadow_bouncegridtexture;
+extern matrix4x4_t r_shadow_bouncegridmatrix;
+extern vec_t r_shadow_bouncegridintensity;
+
 void R_Shadow_Init(void);
 qboolean R_Shadow_ShadowMappingEnabled(void);
 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris, vec3_t trismins, vec3_t trismaxs);
index 8732ca2..c89b27e 100644 (file)
@@ -142,7 +142,7 @@ void R_FreeTexture(rtexture_t *rt);
 // update a portion of the image data of a texture, used by lightmap updates
 // and procedural textures such as video playback, actual uploads may be
 // delayed by gl_nopartialtextureupdates cvar until R_Mesh_TexBind uses it
-void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int width, int height);
+void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth);
 
 // returns the renderer dependent texture slot number (call this before each
 // use, as a texture might not have been precached)