implemented r_shadow_particletrace cvar which enables an exceptionally
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 21 Feb 2011 10:57:49 +0000 (10:57 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 21 Feb 2011 10:57:49 +0000 (10:57 +0000)
slow realtime global illumination deferred rendering technique,
UNPLAYABLE framerates with this option on, some rendering artifacts,
experimental only

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

cl_screen.c
client.h
dpsoftrast.c
dpsoftrast.h
gl_backend.c
gl_backend.h
gl_rmain.c
mathlib.h
model_shared.h
r_shadow.c
render.h

index f52b143..25e2f2e 100644 (file)
@@ -800,6 +800,7 @@ void R_TimeReport_EndFrame(void)
 "%5i leafs%5i portals%6i/%6i particles%6i/%6i decals %3i%% quality\n"
 "%7i lightmap updates (%7i pixels)%8iKB/%8iKB framedata\n"
 "%4i lights%4i clears%4i scissored%7i light%7i shadow%7i dynamic\n"
+"%4i/%4i bouncelights%4i updated\n"
 "%6i draws%8i vertices%8i triangles bloompixels%8i copied%8i drawn\n"
 "updated%5i indexbuffers%8i bytes%5i vertexbuffers%8i bytes\n"
 "%s"
@@ -810,6 +811,7 @@ void R_TimeReport_EndFrame(void)
 , r_refdef.stats.world_leafs, r_refdef.stats.world_portals, r_refdef.stats.particles, cl.num_particles, r_refdef.stats.drawndecals, r_refdef.stats.totaldecals, (int)(100 * r_refdef.view.quality)
 , r_refdef.stats.lightmapupdates, r_refdef.stats.lightmapupdatepixels, (r_refdef.stats.framedatacurrent+512) / 1024, (r_refdef.stats.framedatasize+512)/1024
 , r_refdef.stats.lights, r_refdef.stats.lights_clears, r_refdef.stats.lights_scissored, r_refdef.stats.lights_lighttriangles, r_refdef.stats.lights_shadowtriangles, r_refdef.stats.lights_dynamicshadowtriangles
+, r_refdef.stats.lights_bouncelightsdrawn, r_refdef.stats.lights_bouncelightscounted, r_refdef.stats.lights_bouncelightsupdated
 , r_refdef.stats.draws, r_refdef.stats.draws_vertices, r_refdef.stats.draws_elements / 3, r_refdef.stats.bloom_copypixels, r_refdef.stats.bloom_drawpixels
 , r_refdef.stats.indexbufferuploadcount, r_refdef.stats.indexbufferuploadsize, r_refdef.stats.vertexbufferuploadcount, r_refdef.stats.vertexbufferuploadsize
 , r_speeds_timestring);
index dd063ff..3df39a7 100644 (file)
--- a/client.h
+++ b/client.h
@@ -89,6 +89,13 @@ typedef struct beam_s
 }
 beam_t;
 
+typedef struct rtlight_particle_s
+{
+       float origin[3];
+       float color[3];
+}
+rtlight_particle_t;
+
 typedef struct rtlight_s
 {
        // shadow volumes are done entirely in model space, so there are no matrices for dealing with them...  they just use the origin
@@ -202,6 +209,11 @@ typedef struct rtlight_s
        /// masks of all shadowmap sides that have any potential static receivers or casters
        int static_shadowmap_receivers;
        int static_shadowmap_casters;
+       /// particle-tracing cache for global illumination
+       int particlecache_numparticles;
+       int particlecache_maxparticles;
+       int particlecache_updateparticle;
+       rtlight_particle_t *particlecache_particles;
 }
 rtlight_t;
 
@@ -1561,6 +1573,9 @@ typedef struct r_refdef_stats_s
        int lights_lighttriangles;
        int lights_shadowtriangles;
        int lights_dynamicshadowtriangles;
+       int lights_bouncelightscounted;
+       int lights_bouncelightsdrawn;
+       int lights_bouncelightsupdated;
        int bloom;
        int bloom_copypixels;
        int bloom_drawpixels;
index f878598..1d1c9ba 100644 (file)
@@ -4204,6 +4204,23 @@ void DPSOFTRAST_PixelShader_DeferredLightSource(DPSOFTRAST_State_Thread *thread,
 
 
 
+void DPSOFTRAST_VertexShader_DeferredBounceLight(void)
+{
+       DPSOFTRAST_Array_TransformProject(DPSOFTRAST_ARRAY_POSITION, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1);
+}
+
+void DPSOFTRAST_PixelShader_DeferredBounceLight(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span)
+{
+       // TODO: IMPLEMENT
+       float buffer_z[DPSOFTRAST_DRAW_MAXSPANLENGTH];
+       unsigned char buffer_FragColorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4];
+       DPSOFTRAST_Draw_Span_Begin(thread, triangle, span, buffer_z);
+       memset(buffer_FragColorbgra8 + span->startx*4, 0, (span->endx - span->startx)*4);
+       DPSOFTRAST_Draw_Span_FinishBGRA8(thread, triangle, span, buffer_FragColorbgra8);
+}
+
+
+
 typedef struct DPSOFTRAST_ShaderModeInfo_s
 {
        int lodarrayindex;
@@ -4231,7 +4248,8 @@ static const DPSOFTRAST_ShaderModeInfo DPSOFTRAST_ShaderModeTable[SHADERMODE_COU
        {2, DPSOFTRAST_VertexShader_Water,                          DPSOFTRAST_PixelShader_Water,                          {~0}},
        {2, DPSOFTRAST_VertexShader_ShowDepth,                      DPSOFTRAST_PixelShader_ShowDepth,                      {~0}},
        {2, DPSOFTRAST_VertexShader_DeferredGeometry,               DPSOFTRAST_PixelShader_DeferredGeometry,               {~0}},
-       {2, DPSOFTRAST_VertexShader_DeferredLightSource,            DPSOFTRAST_PixelShader_DeferredLightSource,            {~0}}
+       {2, DPSOFTRAST_VertexShader_DeferredLightSource,            DPSOFTRAST_PixelShader_DeferredLightSource,            {~0}},
+       {2, DPSOFTRAST_VertexShader_DeferredBounceLight,        DPSOFTRAST_PixelShader_DeferredBounceLight,        {~0}}
 };
 
 void DPSOFTRAST_Draw_ProcessSpans(DPSOFTRAST_State_Thread *thread)
index 28d72ca..a3e0103 100644 (file)
@@ -157,6 +157,7 @@ typedef enum shadermode_e
        SHADERMODE_SHOWDEPTH, ///< (debugging) renders depth as color
        SHADERMODE_DEFERREDGEOMETRY, ///< (deferred) render material properties to screenspace geometry buffers
        SHADERMODE_DEFERREDLIGHTSOURCE, ///< (deferred) use directional pixel shading from light source (rtlight) on screenspace geometry buffers
+       SHADERMODE_DEFERREDBOUNCELIGHT, ///< (deferred) simple area light deferred particles using geometry buffers for Global Illumination purposes
        SHADERMODE_COUNT
 }
 shadermode_t;
index a9b0111..b32cbc8 100644 (file)
@@ -169,6 +169,7 @@ typedef struct gl_state_s
        r_meshbuffer_t *preparevertices_dynamicvertexbuffer;
        r_vertexgeneric_t *preparevertices_vertexgeneric;
        r_vertexmesh_t *preparevertices_vertexmesh;
+       r_vertexbouncelight_t *preparevertices_vertexbouncelight;
        int preparevertices_numvertices;
 
        r_meshbuffer_t *draw_dynamicindexbuffer;
@@ -3737,9 +3738,18 @@ D3DVERTEXELEMENT9 r_vertexmesh_d3d9elements[] =
        D3DDECL_END()
 };
 
+D3DVERTEXELEMENT9 r_vertexbouncelight_d3d9elements[] =
+{
+       {0, (int)((size_t)&((r_vertexmesh_t *)0)->vertex3f          ), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+       {0, (int)((size_t)&((r_vertexmesh_t *)0)->color4ub          ), D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
+       {0, (int)((size_t)&((r_vertexmesh_t *)0)->texcoord4f        ), D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
+       D3DDECL_END()
+};
+
 IDirect3DVertexDeclaration9 *r_vertex3f_d3d9decl;
 IDirect3DVertexDeclaration9 *r_vertexgeneric_d3d9decl;
 IDirect3DVertexDeclaration9 *r_vertexmesh_d3d9decl;
+IDirect3DVertexDeclaration9 *r_vertexbouncelight_d3d9decl;
 #endif
 
 static void R_Mesh_InitVertexDeclarations(void)
@@ -3748,6 +3758,7 @@ static void R_Mesh_InitVertexDeclarations(void)
        r_vertex3f_d3d9decl = NULL;
        r_vertexgeneric_d3d9decl = NULL;
        r_vertexmesh_d3d9decl = NULL;
+       r_vertexbouncelight_d3d9decl = NULL;
        switch(vid.renderpath)
        {
        case RENDERPATH_GL20:
@@ -3759,6 +3770,7 @@ static void R_Mesh_InitVertexDeclarations(void)
                IDirect3DDevice9_CreateVertexDeclaration(vid_d3d9dev, r_vertex3f_d3d9elements, &r_vertex3f_d3d9decl);
                IDirect3DDevice9_CreateVertexDeclaration(vid_d3d9dev, r_vertexgeneric_d3d9elements, &r_vertexgeneric_d3d9decl);
                IDirect3DDevice9_CreateVertexDeclaration(vid_d3d9dev, r_vertexmesh_d3d9elements, &r_vertexmesh_d3d9decl);
+               IDirect3DDevice9_CreateVertexDeclaration(vid_d3d9dev, r_vertexbouncelight_d3d9elements, &r_vertexbouncelight_d3d9decl);
                break;
        case RENDERPATH_D3D10:
                Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
@@ -3784,6 +3796,9 @@ static void R_Mesh_DestroyVertexDeclarations(void)
        if (r_vertexmesh_d3d9decl)
                IDirect3DVertexDeclaration9_Release(r_vertexmesh_d3d9decl);
        r_vertexmesh_d3d9decl = NULL;
+       if (r_vertexbouncelight_d3d9decl)
+               IDirect3DVertexDeclaration9_Release(r_vertexbouncelight_d3d9decl);
+       r_vertexbouncelight_d3d9decl = NULL;
 #endif
 }
 
@@ -4293,3 +4308,202 @@ void R_Mesh_PrepareVertices_Mesh(int numvertices, const r_vertexmesh_t *vertex,
                break;
        }
 }
+
+
+
+r_vertexbouncelight_t *R_Mesh_PrepareVertices_BounceLight_Lock(int numvertices)
+{
+       size_t size;
+       size = sizeof(r_vertexbouncelight_t) * numvertices;
+       if (gl_state.preparevertices_tempdatamaxsize < size)
+       {
+               gl_state.preparevertices_tempdatamaxsize = size;
+               gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize);
+       }
+       gl_state.preparevertices_vertexbouncelight = (r_vertexbouncelight_t *)gl_state.preparevertices_tempdata;
+       gl_state.preparevertices_numvertices = numvertices;
+       return gl_state.preparevertices_vertexbouncelight;
+}
+
+qboolean R_Mesh_PrepareVertices_BounceLight_Unlock(void)
+{
+       R_Mesh_PrepareVertices_BounceLight(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexbouncelight, NULL);
+       gl_state.preparevertices_vertexbouncelight = NULL;
+       gl_state.preparevertices_numvertices = 0;
+       return true;
+}
+
+void R_Mesh_PrepareVertices_BounceLight_Arrays(int numvertices, const float *vertex3f, const float *color4f, const float *texcoord4f)
+{
+       int i;
+       r_vertexbouncelight_t *vertex;
+       switch(vid.renderpath)
+       {
+       case RENDERPATH_GL20:
+       case RENDERPATH_GLES2:
+               if (!vid.useinterleavedarrays)
+               {
+                       R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
+                       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
+                       R_Mesh_TexCoordPointer(0, 4, GL_FLOAT, sizeof(float[4]), texcoord4f, NULL, 0);
+                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
+                       R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
+                       R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
+                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
+                       return;
+               }
+               break;
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL11:
+               if (!vid.useinterleavedarrays)
+               {
+                       R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0);
+                       R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0);
+                       R_Mesh_TexCoordPointer(0, 4, GL_FLOAT, sizeof(float[4]), texcoord4f, NULL, 0);
+                       if (vid.texunits >= 2)
+                               R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
+                       if (vid.texunits >= 3)
+                               R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
+                       return;
+               }
+               break;
+       case RENDERPATH_D3D9:
+       case RENDERPATH_D3D10:
+       case RENDERPATH_D3D11:
+               break;
+       case RENDERPATH_SOFT:
+               DPSOFTRAST_SetVertexPointer(vertex3f, sizeof(float[3]));
+               DPSOFTRAST_SetColorPointer(color4f, sizeof(float[4]));
+               DPSOFTRAST_SetTexCoordPointer(0, 4, sizeof(float[4]), texcoord4f);
+               DPSOFTRAST_SetTexCoordPointer(1, 2, sizeof(float[2]), NULL);
+               DPSOFTRAST_SetTexCoordPointer(2, 2, sizeof(float[2]), NULL);
+               DPSOFTRAST_SetTexCoordPointer(3, 2, sizeof(float[2]), NULL);
+               DPSOFTRAST_SetTexCoordPointer(4, 2, sizeof(float[2]), NULL);
+               return;
+       }
+
+       // no quick path for this case, convert to vertex structs
+       vertex = R_Mesh_PrepareVertices_BounceLight_Lock(numvertices);
+       for (i = 0;i < numvertices;i++)
+               VectorCopy(vertex3f + 3*i, vertex[i].vertex3f);
+       if (color4f)
+       {
+               for (i = 0;i < numvertices;i++)
+                       Vector4Scale(color4f + 4*i, 255.0f, vertex[i].color4ub);
+       }
+       else
+       {
+               float tempcolor4f[4];
+               unsigned char tempcolor4ub[4];
+               Vector4Scale(gl_state.color4f, 255.0f, tempcolor4f);
+               tempcolor4ub[0] = (unsigned char)bound(0.0f, tempcolor4f[0], 255.0f);
+               tempcolor4ub[1] = (unsigned char)bound(0.0f, tempcolor4f[1], 255.0f);
+               tempcolor4ub[2] = (unsigned char)bound(0.0f, tempcolor4f[2], 255.0f);
+               tempcolor4ub[3] = (unsigned char)bound(0.0f, tempcolor4f[3], 255.0f);
+               for (i = 0;i < numvertices;i++)
+                       Vector4Copy(tempcolor4ub, vertex[i].color4ub);
+       }
+       if (texcoord4f)
+               for (i = 0;i < numvertices;i++)
+                       Vector4Copy(texcoord4f + 4*i, vertex[i].texcoord4f);
+       R_Mesh_PrepareVertices_BounceLight_Unlock();
+       R_Mesh_PrepareVertices_BounceLight(numvertices, vertex, NULL);
+}
+
+void R_Mesh_PrepareVertices_BounceLight(int numvertices, const r_vertexbouncelight_t *vertex, const r_meshbuffer_t *vertexbuffer)
+{
+       // upload temporary vertexbuffer for this rendering
+       if (!gl_state.usevbo_staticvertex)
+               vertexbuffer = NULL;
+       if (!vertexbuffer && gl_state.usevbo_dynamicvertex)
+       {
+               if (gl_state.preparevertices_dynamicvertexbuffer)
+                       R_Mesh_UpdateMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer, vertex, numvertices * sizeof(*vertex));
+               else
+                       gl_state.preparevertices_dynamicvertexbuffer = R_Mesh_CreateMeshBuffer(vertex, numvertices * sizeof(*vertex), "temporary", false, true, false);
+               vertexbuffer = gl_state.preparevertices_dynamicvertexbuffer;
+       }
+       switch(vid.renderpath)
+       {
+       case RENDERPATH_GL20:
+       case RENDERPATH_GLES2:
+               if (vertexbuffer)
+               {
+                       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
+                       R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , vertexbuffer, (int)((unsigned char *)vertex->color4ub           - (unsigned char *)vertex));
+                       R_Mesh_TexCoordPointer(0, 4, GL_FLOAT        , sizeof(*vertex), vertex->texcoord4f        , vertexbuffer, (int)((unsigned char *)vertex->texcoord4f         - (unsigned char *)vertex));
+                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
+                       R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
+                       R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
+                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
+               }
+               else
+               {
+                       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
+                       R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , NULL, 0);
+                       R_Mesh_TexCoordPointer(0, 4, GL_FLOAT        , sizeof(*vertex), vertex->texcoord4f        , NULL, 0);
+                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
+                       R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
+                       R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
+                       R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
+               }
+               break;
+       case RENDERPATH_GL13:
+               if (vertexbuffer)
+               {
+                       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
+                       R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , vertexbuffer, (int)((unsigned char *)vertex->color4ub           - (unsigned char *)vertex));
+                       R_Mesh_TexCoordPointer(0, 4, GL_FLOAT        , sizeof(*vertex), vertex->texcoord4f        , vertexbuffer, (int)((unsigned char *)vertex->texcoord4f         - (unsigned char *)vertex));
+                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
+               }
+               else
+               {
+                       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
+                       R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , NULL, 0);
+                       R_Mesh_TexCoordPointer(0, 4, GL_FLOAT        , sizeof(*vertex), vertex->texcoord4f        , NULL, 0);
+                       R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
+               }
+               break;
+       case RENDERPATH_GL11:
+               if (vertexbuffer)
+               {
+                       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , vertexbuffer, (int)((unsigned char *)vertex->vertex3f           - (unsigned char *)vertex));
+                       R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , vertexbuffer, (int)((unsigned char *)vertex->color4ub           - (unsigned char *)vertex));
+                       R_Mesh_TexCoordPointer(0, 4, GL_FLOAT        , sizeof(*vertex), vertex->texcoord4f        , vertexbuffer, (int)((unsigned char *)vertex->texcoord4f         - (unsigned char *)vertex));
+               }
+               else
+               {
+                       R_Mesh_VertexPointer(     3, GL_FLOAT        , sizeof(*vertex), vertex->vertex3f          , NULL, 0);
+                       R_Mesh_ColorPointer(      4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub          , NULL, 0);
+                       R_Mesh_TexCoordPointer(0, 4, GL_FLOAT        , sizeof(*vertex), vertex->texcoord4f        , NULL, 0);
+               }
+               break;
+       case RENDERPATH_D3D9:
+#ifdef SUPPORTD3D
+               IDirect3DDevice9_SetVertexDeclaration(vid_d3d9dev, r_vertexbouncelight_d3d9decl);
+               if (vertexbuffer)
+                       IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, (IDirect3DVertexBuffer9*)vertexbuffer->devicebuffer, 0, sizeof(*vertex));
+               else
+                       IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, NULL, 0, 0);
+               gl_state.d3dvertexbuffer = (void *)vertexbuffer;
+               gl_state.d3dvertexdata = (void *)vertex;
+               gl_state.d3dvertexsize = sizeof(*vertex);
+#endif
+               break;
+       case RENDERPATH_D3D10:
+               Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+               break;
+       case RENDERPATH_D3D11:
+               Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+               break;
+       case RENDERPATH_SOFT:
+               DPSOFTRAST_SetVertexPointer(vertex->vertex3f, sizeof(*vertex));
+               DPSOFTRAST_SetColorPointer4ub(vertex->color4ub, sizeof(*vertex));
+               DPSOFTRAST_SetTexCoordPointer(0, 4, sizeof(*vertex), vertex->texcoord4f);
+               DPSOFTRAST_SetTexCoordPointer(1, 2, sizeof(*vertex), NULL);
+               DPSOFTRAST_SetTexCoordPointer(2, 2, sizeof(*vertex), NULL);
+               DPSOFTRAST_SetTexCoordPointer(3, 2, sizeof(*vertex), NULL);
+               DPSOFTRAST_SetTexCoordPointer(4, 2, sizeof(*vertex), NULL);
+               break;
+       }
+}
index fb63449..76ff5ba 100644 (file)
@@ -87,6 +87,11 @@ qboolean R_Mesh_PrepareVertices_Mesh_Unlock(void); // if this returns false, you
 void R_Mesh_PrepareVertices_Mesh_Arrays(int numvertices, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *color4f, const float *texcoordtexture2f, const float *texcoordlightmap2f);
 void R_Mesh_PrepareVertices_Mesh(int numvertices, const r_vertexmesh_t *vertex, const r_meshbuffer_t *buffer);
 
+r_vertexbouncelight_t *R_Mesh_PrepareVertices_BounceLight_Lock(int numvertices);
+qboolean R_Mesh_PrepareVertices_BounceLight_Unlock(void);
+void R_Mesh_PrepareVertices_BounceLight_Arrays(int numvertices, const float *vertex3f, const float *color4f, const float *texcoord4f);
+void R_Mesh_PrepareVertices_BounceLight(int numvertices, const r_vertexbouncelight_t *vertex, const r_meshbuffer_t *vertexbuffer);
+
 // sets up the requested vertex transform matrix
 void R_EntityMatrix(const matrix4x4_t *matrix);
 // sets the vertex array pointer
index 59693c3..90e49a7 100644 (file)
@@ -1058,6 +1058,11 @@ static const char *builtinshaderstring =
 "uniform highp vec3 LightPosition;\n"
 "varying highp vec4 ModelViewPosition;\n"
 "#endif\n"
+"#ifdef MODE_DEFERREDBOUNCELIGHT\n"
+"varying highp vec4 ModelViewPosition;\n"
+"varying highp vec4 LightOriginInvRadius;\n"
+"varying mediump vec4 LightColor;\n"
+"#endif\n"
 "\n"
 "#ifdef MODE_LIGHTSOURCE\n"
 "uniform highp vec3 LightPosition;\n"
@@ -1123,6 +1128,9 @@ static const char *builtinshaderstring =
 "uniform sampler2D Texture_ScreenDiffuse;\n"
 "uniform sampler2D Texture_ScreenSpecular;\n"
 "#endif\n"
+"#ifdef MODE_DEFERREDBOUNCELIGHT\n"
+"uniform sampler2D Texture_ScreenDepth;\n"
+"#endif\n"
 "\n"
 "uniform lowp vec3 Color_Pants;\n"
 "uniform lowp vec3 Color_Shirt;\n"
@@ -1488,6 +1496,39 @@ static const char *builtinshaderstring =
 "\n"
 "\n"
 "\n"
+"#ifdef MODE_DEFERREDBOUNCELIGHT\n"
+"#ifdef VERTEX_SHADER\n"
+"uniform highp mat4 ModelViewMatrix;\n"
+"void main(void)\n"
+"{\n"
+"      ModelViewPosition = ModelViewMatrix * Attrib_Position;\n"
+"      LightOriginInvRadius.xyz = (ModelViewMatrix * vec4(Attrib_TexCoord0.xyz, 1.0)).xyz;\n"
+"      LightOriginInvRadius.w = Attrib_TexCoord0.w;\n"
+"      LightColor = Attrib_Color;\n"
+"      gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n"
+"}\n"
+"#endif // VERTEX_SHADER\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"// ScreenToDepth = vec2(Far / (Far - Near), Far * Near / (Near - Far));\n"
+"uniform highp vec2 ScreenToDepth;\n"
+"uniform myhalf2 PixelToScreenTexCoord;\n"
+"void main(void)\n"
+"{\n"
+"      // calculate viewspace pixel position\n"
+"      vec2 ScreenTexCoord = gl_FragCoord.xy * PixelToScreenTexCoord;\n"
+"      vec3 position;\n"
+"      position.z = ScreenToDepth.y / (texture2D(Texture_ScreenDepth, ScreenTexCoord).r + ScreenToDepth.x);\n"
+"      position.xy = ModelViewPosition.xy * (position.z / ModelViewPosition.z);\n"
+"      vec3 CubeVector = (position - LightOriginInvRadius.xyz) * LightOriginInvRadius.w;\n"
+"      gl_FragData[0] = vec4(LightColor.rgb * max(0.0, 1.0 - length(CubeVector)), 1.0);\n"
+"}\n"
+"#endif // FRAGMENT_SHADER\n"
+"#else // !MODE_DEFERREDBOUNCELIGHT\n"
+"\n"
+"\n"
+"\n"
+"\n"
 "#ifdef VERTEX_SHADER\n"
 "uniform highp mat4 TexMatrix;\n"
 "#ifdef USEVERTEXTEXTUREBLEND\n"
@@ -1811,6 +1852,7 @@ static const char *builtinshaderstring =
 "}\n"
 "#endif // FRAGMENT_SHADER\n"
 "\n"
+"#endif // !MODE_DEFERREDBOUNCELIGHT\n"
 "#endif // !MODE_DEFERREDLIGHTSOURCE\n"
 "#endif // !MODE_DEFERREDGEOMETRY\n"
 "#endif // !MODE_WATER\n"
@@ -3417,6 +3459,7 @@ shadermodeinfo_t glslshadermodeinfo[SHADERMODE_COUNT] =
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_SHOWDEPTH\n", " showdepth"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
+       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_DEFERREDBOUNCELIGHT\n", " deferredbouncelight"},
 };
 
 shadermodeinfo_t hlslshadermodeinfo[SHADERMODE_COUNT] =
@@ -3437,6 +3480,7 @@ shadermodeinfo_t hlslshadermodeinfo[SHADERMODE_COUNT] =
        {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_SHOWDEPTH\n", " showdepth"},
        {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
        {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
+       {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_DEFERREDBOUNCELIGHT\n", " deferredbouncelight"},
 };
 
 struct r_glsl_permutation_s;
@@ -5718,6 +5762,50 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
        }
 }
 
+void R_SetupShader_DeferredBounceLight(void)
+{
+       // array of particle lights that contribute only ambient color
+       unsigned int permutation = 0;
+       unsigned int mode = 0;
+       mode = SHADERMODE_DEFERREDBOUNCELIGHT;
+       switch(vid.renderpath)
+       {
+       case RENDERPATH_D3D9:
+#ifdef SUPPORTD3D
+               R_SetupShader_SetPermutationHLSL(mode, permutation);
+               hlslPSSetParameter2f(D3DPSREGISTER_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
+               hlslPSSetParameter2f(D3DPSREGISTER_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height);
+
+               R_Mesh_TexBind(GL20TU_SCREENDEPTH        , r_shadow_prepassgeometrydepthcolortexture           );
+#endif
+               break;
+       case RENDERPATH_D3D10:
+               Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+               break;
+       case RENDERPATH_D3D11:
+               Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+               break;
+       case RENDERPATH_GL20:
+       case RENDERPATH_GLES2:
+               R_SetupShader_SetPermutationGLSL(mode, permutation);
+               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->tex_Texture_ScreenDepth       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDepth        , r_shadow_prepassgeometrydepthtexture                );
+               break;
+       case RENDERPATH_GL13:
+       case RENDERPATH_GL11:
+               break;
+       case RENDERPATH_SOFT:
+               R_SetupShader_SetPermutationGLSL(mode, permutation);
+               DPSOFTRAST_Uniform2f(       DPSOFTRAST_UNIFORM_ScreenToDepth            , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
+               DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
+
+               R_Mesh_TexBind(GL20TU_SCREENDEPTH        , r_shadow_prepassgeometrydepthtexture                );
+               break;
+       }
+}
+
 #define SKINFRAME_HASH 1024
 
 typedef struct
index d8a902d..b3a9f7e 100644 (file)
--- a/mathlib.h
+++ b/mathlib.h
@@ -175,6 +175,10 @@ int PointInfrontOfTriangle(const float *p, const float *a, const float *b, const
 }
 #endif
 
+#define lhcheeserand() (seed = (seed * 987211u) ^ (seed >> 13u) ^ 914867)
+#define lhcheeserandom(MIN,MAX) ((double)(lhcheeserand() + 0.5) / ((double)4096.0*1024.0*1024.0) * ((MAX)-(MIN)) + (MIN))
+#define VectorCheeseRandom(v) do{(v)[0] = lhcheeserandom(-1, 1);(v)[1] = lhcheeserandom(-1, 1);(v)[2] = lhcheeserandom(-1, 1);}while(DotProduct(v, v) > 1)
+
 /*
 // LordHavoc: quaternion math, untested, don't know if these are correct,
 // need to add conversion to/from matrices
index 3247d0f..9950b0f 100644 (file)
@@ -123,6 +123,15 @@ typedef struct r_vertexmesh_s
 }
 r_vertexmesh_t;
 
+typedef struct r_vertexbouncelight_s
+{
+       // 32 bytes
+       float vertex3f[3];
+       unsigned char color4ub[4];
+       float texcoord4f[4];
+}
+r_vertexbouncelight_t;
+
 typedef struct r_meshbuffer_s
 {
        int bufferobject; // OpenGL
index ba4ca14..f7549cf 100644 (file)
@@ -251,7 +251,8 @@ int r_shadow_shadowmapsize; // changes for each light based on distance
 int r_shadow_shadowmaplod; // changes for each light based on distance
 
 GLuint r_shadow_prepassgeometryfbo;
-GLuint r_shadow_prepasslightingfbo;
+GLuint r_shadow_prepasslightingdiffusespecularfbo;
+GLuint r_shadow_prepasslightingdiffusefbo;
 int r_shadow_prepass_width;
 int r_shadow_prepass_height;
 rtexture_t *r_shadow_prepassgeometrydepthtexture;
@@ -318,6 +319,14 @@ cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve perfor
 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
+cvar_t r_shadow_particletrace = {CVAR_SAVE, "r_shadow_particletrace", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity), requires r_shadow_deferred 1, requires r_shadow_realtime_world 1, EXTREMELY SLOW"};
+cvar_t r_shadow_particletrace_intensity = {CVAR_SAVE, "r_shadow_particletrace_intensity", "128", "overall brightness of particle traced radiosity"};
+cvar_t r_shadow_particletrace_size = {CVAR_SAVE, "r_shadow_particletrace_size", "32", "particles produce bounce lights of this radius"};
+cvar_t r_shadow_particletrace_radiusscale = {CVAR_SAVE, "r_shadow_particletrace_radiusscale", "1", "particles stop at this fraction of light radius"};
+cvar_t r_shadow_particletrace_maxbounce = {CVAR_SAVE, "r_shadow_particletrace_maxbounce", "1", "maximum number of bounces for a particle (minimum is 1)"};
+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_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)"};
@@ -675,6 +684,14 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_polygonfactor);
        Cvar_RegisterVariable(&r_shadow_polygonoffset);
        Cvar_RegisterVariable(&r_shadow_texture3d);
+       Cvar_RegisterVariable(&r_shadow_particletrace);
+       Cvar_RegisterVariable(&r_shadow_particletrace_intensity);
+       Cvar_RegisterVariable(&r_shadow_particletrace_size);
+       Cvar_RegisterVariable(&r_shadow_particletrace_radiusscale);
+       Cvar_RegisterVariable(&r_shadow_particletrace_maxbounce);
+       Cvar_RegisterVariable(&r_shadow_particletrace_bounceintensity);
+       Cvar_RegisterVariable(&r_shadow_particletrace_particlespacing);
+       Cvar_RegisterVariable(&r_shadow_particletrace_updatepercentage);
        Cvar_RegisterVariable(&r_coronas);
        Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
        Cvar_RegisterVariable(&r_coronas_occlusionquery);
@@ -2208,7 +2225,7 @@ void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadow
        // only draw light where this geometry was already rendered AND the
        // stencil is 128 (values other than this mean shadow)
        R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
-       R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
+       R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
 
        r_shadow_usingshadowmap2d = shadowmapping;
 
@@ -2227,6 +2244,231 @@ void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadow
        R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
 }
 
+#define MAXPARTICLESPERLIGHT 262144
+#define MAXLIGHTSPERDRAW 1024
+
+static void R_Shadow_RenderParticlesForLight(rtlight_t *rtlight)
+{
+       int batchcount;
+       int i;
+       int j;
+       int bouncecount;
+       int hitsupercontentsmask;
+       int n;
+       int shotparticles;
+       int shootparticles = 0;
+       int bouncelimit;
+       int maxbounce;
+       unsigned int seed = 0;
+       static unsigned short bouncelight_elements[MAXLIGHTSPERDRAW*36];
+       static float vertex3f[MAXLIGHTSPERDRAW*24];
+       static float lightorigin4f[MAXLIGHTSPERDRAW*32];
+       static float color4f[MAXLIGHTSPERDRAW*32];
+       float scaledpoints[8][3];
+       float *v3f;
+       float *lo4f;
+       float *c4f;
+       rtlight_particle_t *p;
+       vec_t wantparticles = 0;
+       vec_t s;
+       vec_t radius;
+       vec_t particlesize;
+       vec_t iparticlesize;
+//     vec3_t offset;
+//     vec3_t right;
+//     vec3_t up;
+       vec4_t org;
+       vec4_t color;
+       vec3_t currentcolor;
+       vec3_t clipstart;
+       vec3_t clipend;
+       vec3_t shotcolor;
+       trace_t cliptrace;
+       if (!rtlight->draw || !rtlight->isstatic || !r_shadow_usingdeferredprepass)
+               return;
+       if (r_shadow_particletrace.integer)
+       {
+               radius = rtlight->radius * bound(0.0001f, r_shadow_particletrace_radiusscale.value, 1.0f) - r_shadow_particletrace_size.value;
+               s = rtlight->radius / bound(1.0f, r_shadow_particletrace_particlespacing.value * r_shadow_particletrace_size.value, 1048576.0f);
+               wantparticles = s*s;
+               n = (int)bound(0, wantparticles, MAXPARTICLESPERLIGHT);
+       }
+       else
+               n = 0;
+       shootparticles = (int)(n * r_shadow_particletrace_updatepercentage.value);
+       if ((n && !rtlight->particlecache_particles) || rtlight->particlecache_maxparticles != n)
+       {
+               if (rtlight->particlecache_particles)
+                       Mem_Free(rtlight->particlecache_particles);
+               rtlight->particlecache_particles = NULL;
+               rtlight->particlecache_numparticles = 0;
+               rtlight->particlecache_maxparticles = n;
+               rtlight->particlecache_updateparticle = 0;
+               if (rtlight->particlecache_maxparticles)
+                       rtlight->particlecache_particles = Mem_Alloc(r_main_mempool, rtlight->particlecache_maxparticles * sizeof(*rtlight->particlecache_particles));
+               shootparticles = n * 16;
+       }
+
+       if (!rtlight->particlecache_maxparticles)
+               return;
+
+//     if (rtlight->particlecache_numparticles < rtlight->particlecache_maxparticles)
+//             shootparticles = rtlight->particlecache_maxparticles;
+
+//     if (rtlight->particlecache_numparticles >= rtlight->particlecache_maxparticles)
+//             shootparticles = 0;
+
+       maxbounce = bound(1, r_shadow_particletrace_maxbounce.integer, 16);
+       r_refdef.stats.lights_bouncelightsupdated += shootparticles;
+       for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
+       {
+               seed = rtlight->particlecache_updateparticle;
+               VectorSet(shotcolor, 1.0f, 1.0f, 1.0f);
+               VectorCopy(rtlight->shadoworigin, clipstart);
+               VectorRandom(clipend);
+               VectorMA(clipstart, radius, clipend, clipend);
+               hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
+               bouncelimit = 1 + (rtlight->particlecache_updateparticle % maxbounce);
+               for (bouncecount = 0;;bouncecount++)
+               {
+                       cliptrace = CL_TraceLine(clipstart, clipend, 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 / 262144.0f))
+                               break;
+                       if (bouncecount >= bouncelimit)
+                       {
+                               VectorCopy(cliptrace.endpos, rtlight->particlecache_particles[rtlight->particlecache_updateparticle].origin);
+                               VectorCopy(shotcolor, rtlight->particlecache_particles[rtlight->particlecache_updateparticle].color);
+                               rtlight->particlecache_updateparticle++;
+                               if (rtlight->particlecache_numparticles < rtlight->particlecache_updateparticle)
+                                       rtlight->particlecache_numparticles = rtlight->particlecache_updateparticle;
+                               if (rtlight->particlecache_updateparticle >= rtlight->particlecache_maxparticles)
+                               {
+                                       rtlight->particlecache_updateparticle = 0;
+                                       shotparticles = shootparticles;
+                               }
+                               break;
+                       }
+                       // scale down shot color by bounce intensity and texture color
+                       VectorScale(shotcolor, r_shadow_particletrace_bounceintensity.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);
+                       VectorRandom(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 (!rtlight->particlecache_numparticles)
+               return;
+
+       // render the particles as deferred lights
+// do global setup needed for the chosen lighting mode
+       R_Shadow_RenderMode_Reset();
+       r_shadow_rendermode = r_shadow_lightingrendermode;
+       r_shadow_usingshadowmap2d = false;
+       R_EntityMatrix(&identitymatrix);
+       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+       // only draw light where this geometry was already rendered AND the
+       // stencil is 128 (values other than this mean shadow)
+       R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
+       R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
+       R_SetupShader_DeferredBounceLight();
+       GL_ColorMask(1,1,1,1);
+       GL_DepthMask(false);
+       GL_DepthRange(0, 1);
+       GL_PolygonOffset(0, 0);
+       GL_DepthTest(true);
+       GL_DepthFunc(GL_GREATER);
+       GL_CullFace(r_refdef.view.cullface_back);
+       s = r_shadow_particletrace_intensity.value / (float)rtlight->particlecache_numparticles;
+       VectorScale(rtlight->currentcolor, s, currentcolor);
+       particlesize = bound(0.0001f, r_shadow_particletrace_size.value, 1024.0f);
+       iparticlesize = 1.0f / particlesize;
+//     VectorScale(r_refdef.view.forward, particlesize, offset);
+//     VectorScale(r_refdef.view.left, -particlesize, right);
+//     VectorScale(r_refdef.view.up, particlesize, up);
+       org[3] = iparticlesize;
+       color[3] = 1.0f;
+       v3f = vertex3f;
+       lo4f = lightorigin4f;
+       c4f = color4f;
+       batchcount = 0;
+       if (!bouncelight_elements[1])
+               for (i = 0;i < MAXLIGHTSPERDRAW;i++)
+                       for (j = 0;j < 36;j++)
+                               bouncelight_elements[i*36+j] = i*8+bboxelements[j];
+       for (j = 0;j < 8;j++)
+               VectorScale(bboxpoints[j], particlesize, scaledpoints[j]);
+       r_refdef.stats.lights_bouncelightscounted += rtlight->particlecache_numparticles;
+       for (j = 0, p = rtlight->particlecache_particles, n = rtlight->particlecache_numparticles;j < n;j++, p++)
+       {
+               VectorCopy(p->origin, org);
+               // org[3] is set above
+               VectorMultiply(p->color, currentcolor, color);
+               // color[3] is set above
+               VectorAdd(scaledpoints[0], org, v3f +  0);
+               VectorAdd(scaledpoints[1], org, v3f +  3);
+               VectorAdd(scaledpoints[2], org, v3f +  6);
+               VectorAdd(scaledpoints[3], org, v3f +  9);
+               VectorAdd(scaledpoints[4], org, v3f + 12);
+               VectorAdd(scaledpoints[5], org, v3f + 15);
+               VectorAdd(scaledpoints[6], org, v3f + 18);
+               VectorAdd(scaledpoints[7], org, v3f + 21);
+               Vector4Copy(org, lo4f +  0);
+               Vector4Copy(org, lo4f +  4);
+               Vector4Copy(org, lo4f +  8);
+               Vector4Copy(org, lo4f + 12);
+               Vector4Copy(org, lo4f + 16);
+               Vector4Copy(org, lo4f + 20);
+               Vector4Copy(org, lo4f + 24);
+               Vector4Copy(org, lo4f + 28);
+               Vector4Copy(color, c4f + 0);
+               Vector4Copy(color, c4f + 4);
+               Vector4Copy(color, c4f + 8);
+               Vector4Copy(color, c4f + 12);
+               Vector4Copy(color, c4f + 16);
+               Vector4Copy(color, c4f + 20);
+               Vector4Copy(color, c4f + 24);
+               Vector4Copy(color, c4f + 28);
+               v3f += 24;
+               lo4f += 32;
+               c4f += 32;
+               batchcount++;
+               if (batchcount >= MAXLIGHTSPERDRAW)
+               {
+                       r_refdef.stats.lights_bouncelightsdrawn += batchcount;
+                       R_Mesh_PrepareVertices_BounceLight_Arrays(batchcount*8, vertex3f, color4f, lightorigin4f);
+                       R_Mesh_Draw(0, batchcount*8, 0, batchcount*12, NULL, NULL, 0, bouncelight_elements, NULL, 0);
+                       v3f = vertex3f;
+                       lo4f = lightorigin4f;
+                       c4f = color4f;
+                       batchcount = 0;
+               }
+       }
+       if (batchcount)
+       {
+               r_refdef.stats.lights_bouncelightsdrawn += batchcount;
+               R_Mesh_PrepareVertices_BounceLight_Arrays(batchcount*8, vertex3f, color4f, lightorigin4f);
+               R_Mesh_Draw(0, batchcount*8, 0, batchcount*12, NULL, NULL, 0, bouncelight_elements, NULL, 0);
+               v3f = vertex3f;
+               lo4f = lightorigin4f;
+               c4f = color4f;
+               batchcount = 0;
+       }
+}
+
 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
 {
        R_Shadow_RenderMode_Reset();
@@ -3742,6 +3984,9 @@ void R_Shadow_DrawLight(rtlight_t *rtlight)
                else
                        R_Shadow_RenderMode_DrawDeferredLight(false, false);
        }
+
+       if (r_shadow_particletrace.integer)
+               R_Shadow_RenderParticlesForLight(rtlight);
 }
 
 static void R_Shadow_FreeDeferred(void)
@@ -3749,8 +3994,11 @@ static void R_Shadow_FreeDeferred(void)
        R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
        r_shadow_prepassgeometryfbo = 0;
 
-       R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingfbo);
-       r_shadow_prepasslightingfbo = 0;
+       R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
+       r_shadow_prepasslightingdiffusespecularfbo = 0;
+
+       R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
+       r_shadow_prepasslightingdiffusefbo = 0;
 
        if (r_shadow_prepassgeometrydepthtexture)
                R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
@@ -3817,7 +4065,7 @@ void R_Shadow_DrawPrepass(void)
        GL_ColorMask(1,1,1,1);
        GL_Color(1,1,1,1);
        GL_DepthTest(true);
-       R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
+       R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
        Vector4Set(clearcolor, 0, 0, 0, 0);
        GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
        if (r_timereport_active)
@@ -3932,8 +4180,8 @@ void R_Shadow_PrepareLights(void)
                        }
 
                        // set up the lighting pass fbo (diffuse + specular)
-                       r_shadow_prepasslightingfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
-                       R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
+                       r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
+                       R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
                        // render diffuse into one texture and specular into another,
                        // with depth and normalmap bound as textures,
                        // with depth bound as attachment as well
@@ -3949,6 +4197,25 @@ void R_Shadow_PrepareLights(void)
                                        r_shadow_usingdeferredprepass = false;
                                }
                        }
+
+                       // set up the lighting pass fbo (diffuse)
+                       r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
+                       R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
+                       // render diffuse into one texture,
+                       // with depth and normalmap bound as textures,
+                       // with depth bound as attachment as well
+                       if (qglDrawBuffersARB)
+                       {
+                               qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
+                               qglReadBuffer(GL_NONE);CHECKGLERROR
+                               status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
+                               if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+                               {
+                                       Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
+                                       Cvar_SetValueQuick(&r_shadow_deferred, 0);
+                                       r_shadow_usingdeferredprepass = false;
+                               }
+                       }
                }
                break;
        case RENDERPATH_GL13:
index c1911e0..161e1c6 100644 (file)
--- a/render.h
+++ b/render.h
@@ -449,6 +449,7 @@ void R_SetupShader_DepthOrShadow(void);
 void R_SetupShader_ShowDepth(void);
 void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *waterplane);
 void R_SetupShader_DeferredLight(const rtlight_t *rtlight);
+void R_SetupShader_DeferredBounceLight(void);
 
 typedef struct r_waterstate_waterplane_s
 {