From 7fd79071d59a0cd0cd40ba401235643f578c8ecc Mon Sep 17 00:00:00 2001 From: havoc Date: Mon, 21 Feb 2011 10:57:49 +0000 Subject: [PATCH] implemented r_shadow_particletrace cvar which enables an exceptionally 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 | 2 + client.h | 15 +++ dpsoftrast.c | 20 +++- dpsoftrast.h | 1 + gl_backend.c | 214 +++++++++++++++++++++++++++++++++++++ gl_backend.h | 5 + gl_rmain.c | 88 ++++++++++++++++ mathlib.h | 4 + model_shared.h | 9 ++ r_shadow.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++-- render.h | 1 + 11 files changed, 632 insertions(+), 8 deletions(-) diff --git a/cl_screen.c b/cl_screen.c index f52b143f..25e2f2e2 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -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); diff --git a/client.h b/client.h index dd063fff..3df39a7e 100644 --- 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; diff --git a/dpsoftrast.c b/dpsoftrast.c index f8785982..1d1c9ba0 100644 --- a/dpsoftrast.c +++ b/dpsoftrast.c @@ -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) diff --git a/dpsoftrast.h b/dpsoftrast.h index 28d72cab..a3e01039 100644 --- a/dpsoftrast.h +++ b/dpsoftrast.h @@ -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; diff --git a/gl_backend.c b/gl_backend.c index a9b01118..b32cbc80 100644 --- a/gl_backend.c +++ b/gl_backend.c @@ -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; + } +} diff --git a/gl_backend.h b/gl_backend.h index fb634492..76ff5ba3 100644 --- a/gl_backend.h +++ b/gl_backend.h @@ -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 diff --git a/gl_rmain.c b/gl_rmain.c index 59693c3b..90e49a7c 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -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 diff --git a/mathlib.h b/mathlib.h index d8a902d4..b3a9f7ea 100644 --- 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 diff --git a/model_shared.h b/model_shared.h index 3247d0f9..9950b0fe 100644 --- a/model_shared.h +++ b/model_shared.h @@ -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 diff --git a/r_shadow.c b/r_shadow.c index ba4ca14a..f7549cf6 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -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: diff --git a/render.h b/render.h index c1911e08..161e1c6a 100644 --- 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 { -- 2.39.2