X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=r_shadow.c;h=33c3005fe3c36385479a1143301b7ac09d3340e0;hb=c7b1d8b1697106c4a3616e0c09aef5e85ca7b39a;hp=92eaf99945716ac09d0a19932563ae590ceb52a7;hpb=ae7659147186f943237a932345fb9a2b88a8983e;p=xonotic%2Fdarkplaces.git diff --git a/r_shadow.c b/r_shadow.c index 92eaf999..33c3005f 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -180,6 +180,7 @@ r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_N qboolean r_shadow_usingshadowmaprect; qboolean r_shadow_usingshadowmap2d; qboolean r_shadow_usingshadowmapcube; +qboolean r_shadow_usingshadowmaportho; int r_shadow_shadowmapside; float r_shadow_shadowmap_texturescale[2]; float r_shadow_shadowmap_parameters[4]; @@ -200,6 +201,7 @@ qboolean r_shadow_shadowmapvsdct; qboolean r_shadow_shadowmapsampler; int r_shadow_shadowmappcf; int r_shadow_shadowmapborder; +matrix4x4_t r_shadow_shadowmapmatrix; int r_shadow_lightscissor[4]; qboolean r_shadow_usingdeferredprepass; @@ -286,7 +288,6 @@ cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdivid cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"}; cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"}; cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"}; -cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"}; cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"}; cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"}; cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"}; @@ -298,8 +299,8 @@ cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_ cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"}; cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"}; cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"}; -cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"}; -cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"}; +cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"}; +cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "0", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"}; cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"}; cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"}; cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "-1", "shadowmap texture types: -1 = auto-select, 0 = 2D, 1 = rectangle, 2 = cubemap"}; @@ -351,16 +352,6 @@ vec3_t r_editlights_cursorlocation; extern int con_vislines; -typedef struct cubemapinfo_s -{ - char basename[64]; - rtexture_t *texture; -} -cubemapinfo_t; - -static int numcubemaps; -static cubemapinfo_t cubemaps[MAX_CUBEMAPS]; - void R_Shadow_UncompileWorldLights(void); void R_Shadow_ClearWorldLights(void); void R_Shadow_SaveWorldLights(void); @@ -400,13 +391,13 @@ void R_Shadow_SetShadowMode(void) { if(r_shadow_shadowmapfilterquality < 0) { - if(strstr(gl_vendor, "NVIDIA")) + if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) + r_shadow_shadowmappcf = 1; + else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) { r_shadow_shadowmapsampler = vid.support.arb_shadow; r_shadow_shadowmappcf = 1; } - else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) - r_shadow_shadowmappcf = 1; else if(strstr(gl_vendor, "ATI")) r_shadow_shadowmappcf = 1; else @@ -451,6 +442,12 @@ void R_Shadow_SetShadowMode(void) r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D; break; } + // Cg has very little choice in depth texture sampling + if (vid.cgcontext) + { + r_shadow_shadowmapsampler = false; + r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D; + } } break; case RENDERPATH_GL13: @@ -460,6 +457,19 @@ void R_Shadow_SetShadowMode(void) } } +qboolean R_Shadow_ShadowMappingEnabled(void) +{ + switch (r_shadow_shadowmode) + { + case R_SHADOW_SHADOWMODE_SHADOWMAP2D: + case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE: + case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE: + return true; + default: + return false; + } +} + void R_Shadow_FreeShadowMaps(void) { int i; @@ -506,7 +516,6 @@ void R_Shadow_FreeShadowMaps(void) void r_shadow_start(void) { // allocate vertex processing arrays - numcubemaps = 0; r_shadow_attenuationgradienttexture = NULL; r_shadow_attenuation2dtexture = NULL; r_shadow_attenuation3dtexture = NULL; @@ -582,7 +591,6 @@ void r_shadow_shutdown(void) r_shadow_prepass_width = r_shadow_prepass_height = 0; CHECKGLERROR - numcubemaps = 0; r_shadow_attenuationgradienttexture = NULL; r_shadow_attenuation2dtexture = NULL; r_shadow_attenuation3dtexture = NULL; @@ -680,7 +688,6 @@ void R_Shadow_Init(void) Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale); Cvar_RegisterVariable(&r_shadow_lightintensityscale); Cvar_RegisterVariable(&r_shadow_lightradiusscale); - Cvar_RegisterVariable(&r_shadow_portallight); Cvar_RegisterVariable(&r_shadow_projectdistance); Cvar_RegisterVariable(&r_shadow_frontsidecasting); Cvar_RegisterVariable(&r_shadow_realtime_dlight); @@ -1332,7 +1339,6 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, r_refdef.stats.lights_shadowtriangles += tris; CHECKGLERROR R_Mesh_VertexPointer(shadowvertex3f, 0, 0); - GL_LockArrays(0, outverts); if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL) { // increment stencil if frontface is infront of depthbuffer @@ -1354,7 +1360,6 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR } R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0); - GL_LockArrays(0, 0); CHECKGLERROR } } @@ -1508,19 +1513,48 @@ int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border) } // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results // check if frustum corners/origin cross plane sides +#if 1 + // infinite version, assumes frustum corners merely give direction and extend to infinite distance + Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p); + dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn); + masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2)); + masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2)); + dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn); + masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4)); + masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4)); + dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn); + masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0)); + masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0)); + for (i = 0;i < 4;i++) + { + Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n); + VectorSubtract(n, p, n); + dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn); + if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2); + if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2); + dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn); + if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4); + if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4); + dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn); + if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0); + if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0); + } +#else + // finite version, assumes corners are a finite distance from origin dependent on far plane for (i = 0;i < 5;i++) { Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p); - dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn), + dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn); masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2)); masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2)); - dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn), + dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn); masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4)); masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4)); - dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn), + dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn); masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0)); masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0)); } +#endif return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5]; } @@ -1964,9 +1998,9 @@ void R_Shadow_RenderMode_Reset(void) qglDepthFunc(GL_LEQUAL);CHECKGLERROR GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR qglDisable(GL_STENCIL_TEST);CHECKGLERROR - qglStencilMask(~0);CHECKGLERROR + qglStencilMask(255);CHECKGLERROR qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR - qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR + qglStencilFunc(GL_ALWAYS, 128, 255);CHECKGLERROR r_refdef.view.cullface_front = r_shadow_cullface_front; r_refdef.view.cullface_back = r_shadow_cullface_back; GL_CullFace(r_refdef.view.cullface_back); @@ -1977,6 +2011,7 @@ void R_Shadow_RenderMode_Reset(void) r_shadow_usingshadowmaprect = false; r_shadow_usingshadowmapcube = false; r_shadow_usingshadowmap2d = false; + r_shadow_usingshadowmaportho = false; CHECKGLERROR } @@ -2018,20 +2053,20 @@ void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass) GL_CullFace(GL_NONE); qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR - qglStencilMask(~0);CHECKGLERROR + qglStencilMask(255);CHECKGLERROR qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR - qglStencilMask(~0);CHECKGLERROR + qglStencilMask(255);CHECKGLERROR qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR break; case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE: GL_CullFace(GL_NONE); qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR - qglStencilMask(~0);CHECKGLERROR + qglStencilMask(255);CHECKGLERROR qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR - qglStencilMask(~0);CHECKGLERROR + qglStencilMask(255);CHECKGLERROR qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR break; } @@ -2057,26 +2092,66 @@ static void R_Shadow_MakeVSDCT(void) r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL); } -void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size) +static void R_Shadow_MakeShadowMap(int side, int size) { int status; - int maxsize; + switch (r_shadow_shadowmode) + { + case R_SHADOW_SHADOWMODE_SHADOWMAP2D: + if (r_shadow_shadowmap2dtexture) return; + r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler); + qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR + qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR + qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR + break; + case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE: + if (r_shadow_shadowmaprectangletexture) return; + r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", size*2, size*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler); + qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR + qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR + qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR + break; + case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE: + if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) return; + r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler); + qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR + qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR + qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR + break; + default: + return; + } + // render depth into the fbo, do not render color at all + qglDrawBuffer(GL_NONE);CHECKGLERROR + qglReadBuffer(GL_NONE);CHECKGLERROR + status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR + if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer)) + { + Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status); + Cvar_SetValueQuick(&r_shadow_shadowmapping, 0); + Cvar_SetValueQuick(&r_shadow_deferred, 0); + } +} + +void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size) +{ float nearclip, farclip, bias; r_viewport_t viewport; + int flipped; GLuint fbo = 0; CHECKGLERROR - maxsize = r_shadow_shadowmapmaxsize; nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius; farclip = 1.0f; bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius; - r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip); - r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias; + r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias; + r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip); r_shadow_shadowmapside = side; r_shadow_shadowmapsize = size; - if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D) + switch (r_shadow_shadowmode) { + case R_SHADOW_SHADOWMODE_SHADOWMAP2D: r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder); - r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size; + r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size; R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL); if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done; @@ -2084,35 +2159,16 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size) if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture) R_Shadow_MakeVSDCT(); if (!r_shadow_shadowmap2dtexture) - { -#if 1 - int w = maxsize*2, h = vid.support.arb_texture_non_power_of_two ? maxsize*3 : maxsize*4; - r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler); - qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR - // render depth into the fbo, do not render color at all - qglDrawBuffer(GL_NONE);CHECKGLERROR - qglReadBuffer(GL_NONE);CHECKGLERROR - status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR - if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer)) - { - Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status); - Cvar_SetValueQuick(&r_shadow_shadowmapping, 0); - Cvar_SetValueQuick(&r_shadow_deferred, 0); - } -#endif - } + R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize); CHECKGLERROR if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d; r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture); r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture); r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D; - } - else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE) - { + break; + case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE: r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder); - r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size; + r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size; R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL); if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done; @@ -2120,62 +2176,30 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size) if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture) R_Shadow_MakeVSDCT(); if (!r_shadow_shadowmaprectangletexture) - { -#if 1 - r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler); - qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR - // render depth into the fbo, do not render color at all - qglDrawBuffer(GL_NONE);CHECKGLERROR - qglReadBuffer(GL_NONE);CHECKGLERROR - status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR - if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer)) - { - Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status); - Cvar_SetValueQuick(&r_shadow_shadowmapping, 0); - Cvar_SetValueQuick(&r_shadow_deferred, 0); - } -#endif - } + R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize); CHECKGLERROR if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle; r_shadow_shadowmap_texturescale[0] = 1.0f; r_shadow_shadowmap_texturescale[1] = 1.0f; r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE; - } - else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE) - { + break; + case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE: r_shadow_shadowmap_parameters[0] = 1.0f; - r_shadow_shadowmap_parameters[1] = 1.0f; + r_shadow_shadowmap_parameters[2] = 1.0f; R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL); if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done; // simple cube approach if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) - { - #if 1 - r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler); - qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR - // render depth into the fbo, do not render color at all - qglDrawBuffer(GL_NONE);CHECKGLERROR - qglReadBuffer(GL_NONE);CHECKGLERROR - status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR - if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer)) - { - Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status); - Cvar_SetValueQuick(&r_shadow_shadowmapping, 0); - Cvar_SetValueQuick(&r_shadow_deferred, 0); - } - #endif - } + R_Shadow_MakeShadowMap(side, size); CHECKGLERROR if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod]; r_shadow_shadowmap_texturescale[0] = 0.0f; r_shadow_shadowmap_texturescale[1] = 0.0f; r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE; + break; + default: + break; } R_Shadow_RenderMode_Reset(); @@ -2198,20 +2222,35 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size) init_done: R_SetViewport(&viewport); - GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height); - if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) + switch (r_shadow_rendermode) { - int flipped = (side&1)^(side>>2); + case R_SHADOW_RENDERMODE_SHADOWMAP2D: + case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE: + flipped = (side & 1) ^ (side >> 2); r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front; r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back; GL_CullFace(r_refdef.view.cullface_back); - } - else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) - { + if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask + { + // get tightest scissor rectangle that encloses all viewports in the clear mask + int x1 = clear & 0x15 ? 0 : size; + int x2 = clear & 0x2A ? 2 * size : size; + int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size); + int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size); + GL_Scissor(x1, y1, x2 - x1, y2 - y1); + GL_Clear(GL_DEPTH_BUFFER_BIT); + } + GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height); + break; + case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE: qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR + GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height); + if (clear) + GL_Clear(GL_DEPTH_BUFFER_BIT); + break; + default: + break; } - if (clear) - qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); CHECKGLERROR } @@ -2236,7 +2275,7 @@ void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qb qglEnable(GL_STENCIL_TEST);CHECKGLERROR // only draw light where this geometry was already rendered AND the // stencil is 128 (values other than this mean shadow) - qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR + qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR } r_shadow_rendermode = r_shadow_lightingrendermode; // do global setup needed for the chosen lighting mode @@ -2247,12 +2286,20 @@ void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qb } if (shadowmapping) { - if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D) + switch (r_shadow_shadowmode) + { + case R_SHADOW_SHADOWMODE_SHADOWMAP2D: r_shadow_usingshadowmap2d = true; - else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE) + break; + case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE: r_shadow_usingshadowmaprect = true; - else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE) + break; + case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE: r_shadow_usingshadowmapcube = true; + break; + default: + break; + } } R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0); CHECKGLERROR @@ -2297,17 +2344,25 @@ void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadow qglEnable(GL_STENCIL_TEST);CHECKGLERROR // only draw light where this geometry was already rendered AND the // stencil is 128 (values other than this mean shadow) - qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR + qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR } qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR if (shadowmapping) { - if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D) + switch (r_shadow_shadowmode) + { + case R_SHADOW_SHADOWMODE_SHADOWMAP2D: r_shadow_usingshadowmap2d = true; - else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE) + break; + case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE: r_shadow_usingshadowmaprect = true; - else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE) + break; + case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE: r_shadow_usingshadowmapcube = true; + break; + default: + break; + } } // render the lighting @@ -2356,7 +2411,7 @@ void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transpar if (stenciltest) { qglEnable(GL_STENCIL_TEST);CHECKGLERROR - qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR + qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR } r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING; } @@ -2684,14 +2739,6 @@ static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, { // ARB2 GLSL shader path (GFFX5200, Radeon 9500) R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT); - if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)) - R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset); - else - R_Mesh_ColorPointer(NULL, 0, 0); - R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); - R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset); - R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset); - R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset); if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) { qglDepthFunc(GL_EQUAL);CHECKGLERROR @@ -2717,7 +2764,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numve int maxtriangles = 4096; static int newelements[4096*3]; R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2); - for (renders = 0;renders < 64;renders++) + for (renders = 0;renders < 4;renders++) { stop = true; newfirstvertex = 0; @@ -2814,26 +2861,26 @@ static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertice diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2]; ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2]; diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2]; - R_Mesh_TexBind(0, R_GetTexture(basetexture)); + R_Mesh_TexBind(0, basetexture); R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix); R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); switch(r_shadow_rendermode) { case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN: - R_Mesh_TexBindAll(1, 0, R_GetTexture(r_shadow_attenuation3dtexture), 0, 0); + R_Mesh_TexBind(1, r_shadow_attenuation3dtexture); R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz); R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1); R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset); break; case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN: - R_Mesh_TexBind(2, R_GetTexture(r_shadow_attenuation2dtexture)); + R_Mesh_TexBind(2, r_shadow_attenuation2dtexture); R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz); R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1); R_Mesh_TexCoordPointer(2, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset); // fall through case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN: - R_Mesh_TexBind(1, R_GetTexture(r_shadow_attenuation2dtexture)); + R_Mesh_TexBind(1, r_shadow_attenuation2dtexture); R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz); R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1); R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset); @@ -2843,16 +2890,16 @@ static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertice default: break; } - //R_Mesh_TexBind(0, R_GetTexture(basetexture)); + //R_Mesh_TexBind(0, basetexture); R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase); if (dopants) { - R_Mesh_TexBind(0, R_GetTexture(pantstexture)); + R_Mesh_TexBind(0, pantstexture); R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants); } if (doshirt) { - R_Mesh_TexBind(0, R_GetTexture(shirttexture)); + R_Mesh_TexBind(0, shirttexture); R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt); } } @@ -3049,8 +3096,8 @@ void R_RTLight_Compile(rtlight_t *rtlight) if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i)) shadowtris++; - if (developer.integer >= 10) - Con_Printf("static light built: %f %f %f : %f %f %f box, %i light triangles, %i shadow triangles, %i zpass/%i zfail compiled shadow volume triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], lighttris, shadowtris, shadowzpasstris, shadowzfailtris); + if (developer_extra.integer) + Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i light triangles, %i shadow triangles, %i zpass/%i zfail compiled shadow volume triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], lighttris, shadowtris, shadowzpasstris, shadowzfailtris); } void R_RTLight_Uncompile(rtlight_t *rtlight) @@ -3313,7 +3360,6 @@ void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, co { r_refdef.stats.lights_shadowtriangles += mesh->numtriangles; R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f); - GL_LockArrays(0, mesh->numverts); if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL) { // increment stencil if frontface is infront of depthbuffer @@ -3335,7 +3381,6 @@ void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, co qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR } R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s); - GL_LockArrays(0, 0); } CHECKGLERROR } @@ -3372,12 +3417,17 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent) relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius; relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius; relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius; - if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) + switch (r_shadow_rendermode) { + case R_SHADOW_RENDERMODE_SHADOWMAP2D: + case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE: + case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE: ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs); - } - else + break; + default: ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs); + break; + } rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity } @@ -3392,7 +3442,7 @@ void R_Shadow_SetupEntityLight(const entity_render_t *ent) Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin); } -void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs) +void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs) { if (!r_refdef.scene.worldmodel->DrawLight) return; @@ -3405,7 +3455,7 @@ void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned c Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight); VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin); - r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs); + r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs); rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity } @@ -3429,7 +3479,10 @@ void R_Shadow_PrepareLight(rtlight_t *rtlight) float f; int numleafs, numsurfaces; int *leaflist, *surfacelist; - unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides; + unsigned char *leafpvs; + unsigned char *shadowtrispvs; + unsigned char *lighttrispvs; + //unsigned char *surfacesides; int numlightentities; int numlightentities_noselfshadow; int numshadowentities; @@ -3438,19 +3491,19 @@ void R_Shadow_PrepareLight(rtlight_t *rtlight) static entity_render_t *lightentities_noselfshadow[MAX_EDICTS]; static entity_render_t *shadowentities[MAX_EDICTS]; static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS]; + qboolean nolight; rtlight->draw = false; // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights) // skip lights that are basically invisible (color 0 0 0) - if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f)) - return; + nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f); // loading is done before visibility checks because loading should happen // all at once at the start of a level, not when it stalls gameplay. // (especially important to benchmarks) // compile light - if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer) + if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer) { if (rtlight->compiled) R_RTLight_Uncompile(rtlight); @@ -3458,7 +3511,7 @@ void R_Shadow_PrepareLight(rtlight_t *rtlight) } // load cubemap - rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube; + rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube; // look up the light style value at this time f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value; @@ -3475,6 +3528,10 @@ void R_Shadow_PrepareLight(rtlight_t *rtlight) if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f)) return; + // skip processing on corona-only lights + if (nolight) + return; + // if the light box is offscreen, skip it if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs)) return; @@ -3493,7 +3550,7 @@ void R_Shadow_PrepareLight(rtlight_t *rtlight) leafpvs = rtlight->static_leafpvs; numsurfaces = rtlight->static_numsurfaces; surfacelist = rtlight->static_surfacelist; - surfacesides = NULL; + //surfacesides = NULL; shadowtrispvs = rtlight->static_shadowtrispvs; lighttrispvs = rtlight->static_lighttrispvs; } @@ -3506,7 +3563,7 @@ void R_Shadow_PrepareLight(rtlight_t *rtlight) leaflist = r_shadow_buffer_leaflist; leafpvs = r_shadow_buffer_leafpvs; surfacelist = r_shadow_buffer_surfacelist; - surfacesides = r_shadow_buffer_surfacesides; + //surfacesides = r_shadow_buffer_surfacesides; shadowtrispvs = r_shadow_buffer_shadowtrispvs; lighttrispvs = r_shadow_buffer_lighttrispvs; // if the reduced leaf bounds are offscreen, skip it @@ -3521,7 +3578,7 @@ void R_Shadow_PrepareLight(rtlight_t *rtlight) leafpvs = NULL; numsurfaces = 0; surfacelist = NULL; - surfacesides = NULL; + //surfacesides = NULL; shadowtrispvs = NULL; lighttrispvs = NULL; } @@ -3807,7 +3864,7 @@ void R_Shadow_DrawLight(rtlight_t *rtlight) // render shadow casters into 6 sided depth texture for (side = 0;side < 6;side++) if (receivermask & (1 << side)) { - R_Shadow_RenderMode_ShadowMap(side, true, size); + R_Shadow_RenderMode_ShadowMap(side, receivermask, size); if (! (castermask & (1 << side))) continue; if (numsurfaces) R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides); @@ -3829,7 +3886,7 @@ void R_Shadow_DrawLight(rtlight_t *rtlight) { for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side)) { - R_Shadow_RenderMode_ShadowMap(side, false, size); + R_Shadow_RenderMode_ShadowMap(side, 0, size); for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side)) R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]); } @@ -4025,11 +4082,13 @@ void R_Shadow_PrepareLights(void) r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16)) R_Shadow_FreeShadowMaps(); + r_shadow_usingshadowmaportho = false; + switch (vid.renderpath) { case RENDERPATH_GL20: case RENDERPATH_CGGL: - if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || !vid.support.arb_texture_rectangle || vid.maxdrawbuffers < 2) + if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2) { r_shadow_usingdeferredprepass = false; if (r_shadow_prepass_width) @@ -4045,19 +4104,22 @@ void R_Shadow_PrepareLights(void) r_shadow_usingdeferredprepass = true; r_shadow_prepass_width = vid.width; r_shadow_prepass_height = vid.height; - r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false); - r_shadow_prepassgeometrynormalmaptexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL); - r_shadow_prepasslightingdiffusetexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL); - r_shadow_prepasslightingspeculartexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL); + r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false); + r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL); + r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL); + r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL); // set up the geometry pass fbo (depth + normalmap) qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR + qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR + qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR // render depth into one texture and normalmap into the other - qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR - qglReadBuffer(GL_NONE);CHECKGLERROR + if (qglDrawBuffersARB) + { + qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR + qglReadBuffer(GL_NONE);CHECKGLERROR + } status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { @@ -4069,14 +4131,17 @@ void R_Shadow_PrepareLights(void) // set up the lighting pass fbo (diffuse + specular) qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR + qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR + qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR + qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR // render diffuse into one texture and specular into another, // with depth and normalmap bound as textures, // with depth bound as attachment as well - qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR - qglReadBuffer(GL_NONE);CHECKGLERROR + if (qglDrawBuffersARB) + { + qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR + qglReadBuffer(GL_NONE);CHECKGLERROR + } status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { @@ -4176,6 +4241,243 @@ extern cvar_t r_shadows_drawafterrtlighting; extern cvar_t r_shadows_castfrombmodels; extern cvar_t r_shadows_throwdistance; extern cvar_t r_shadows_throwdirection; +extern cvar_t r_shadows_focus; +extern cvar_t r_shadows_shadowmapscale; + +void R_Shadow_PrepareModelShadows(void) +{ + int i; + float scale, size, radius, dot1, dot2; + vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs; + entity_render_t *ent; + + if (!r_refdef.scene.numentities) + return; + + switch (r_shadow_shadowmode) + { + case R_SHADOW_SHADOWMODE_SHADOWMAP2D: + case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE: + if (r_shadows.integer >= 2) + break; + // fall through + case R_SHADOW_SHADOWMODE_STENCIL: + for (i = 0;i < r_refdef.scene.numentities;i++) + { + ent = r_refdef.scene.entities[i]; + if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW)) + R_AnimCache_GetEntity(ent, false, false); + } + return; + default: + return; + } + + size = 2*r_shadow_shadowmapmaxsize; + scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value; + radius = 0.5f * size / scale; + + Math_atov(r_shadows_throwdirection.string, shadowdir); + VectorNormalize(shadowdir); + dot1 = DotProduct(r_refdef.view.forward, shadowdir); + dot2 = DotProduct(r_refdef.view.up, shadowdir); + if (fabs(dot1) <= fabs(dot2)) + VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward); + else + VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward); + VectorNormalize(shadowforward); + CrossProduct(shadowdir, shadowforward, shadowright); + Math_atov(r_shadows_focus.string, shadowfocus); + VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin); + VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin); + VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin); + VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin); + if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2]) + dot1 = 1; + VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin); + + shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0])); + shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1])); + shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2])); + shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0])); + shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1])); + shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2])); + + for (i = 0;i < r_refdef.scene.numentities;i++) + { + ent = r_refdef.scene.entities[i]; + if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs)) + continue; + // cast shadows from anything of the map (submodels are optional) + if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW)) + R_AnimCache_GetEntity(ent, false, false); + } +} + +void R_DrawModelShadowMaps(void) +{ + int i; + float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2; + entity_render_t *ent; + vec3_t relativelightorigin; + vec3_t relativelightdirection, relativeforward, relativeright; + vec3_t relativeshadowmins, relativeshadowmaxs; + vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus; + float m[12]; + matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix; + r_viewport_t viewport; + GLuint fbo = 0; + + if (!r_refdef.scene.numentities) + return; + + switch (r_shadow_shadowmode) + { + case R_SHADOW_SHADOWMODE_SHADOWMAP2D: + case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE: + break; + default: + return; + } + + CHECKGLERROR + R_ResetViewRendering3D(); + R_Shadow_RenderMode_Begin(); + R_Shadow_RenderMode_ActiveLight(NULL); + + switch (r_shadow_shadowmode) + { + case R_SHADOW_SHADOWMODE_SHADOWMAP2D: + if (!r_shadow_shadowmap2dtexture) + R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize); + fbo = r_shadow_fbo2d; + r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture); + r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture); + r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D; + break; + case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE: + if (!r_shadow_shadowmaprectangletexture) + R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize); + fbo = r_shadow_fborectangle; + r_shadow_shadowmap_texturescale[0] = 1.0f; + r_shadow_shadowmap_texturescale[1] = 1.0f; + r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE; + break; + default: + break; + } + + size = 2*r_shadow_shadowmapmaxsize; + scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size; + radius = 0.5f / scale; + nearclip = -r_shadows_throwdistance.value; + farclip = r_shadows_throwdistance.value; + bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size); + + r_shadow_shadowmap_parameters[0] = size; + r_shadow_shadowmap_parameters[1] = size; + r_shadow_shadowmap_parameters[2] = 1.0; + r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f); + + Math_atov(r_shadows_throwdirection.string, shadowdir); + VectorNormalize(shadowdir); + Math_atov(r_shadows_focus.string, shadowfocus); + VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin); + VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin); + VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin); + VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin); + dot1 = DotProduct(r_refdef.view.forward, shadowdir); + dot2 = DotProduct(r_refdef.view.up, shadowdir); + if (fabs(dot1) <= fabs(dot2)) + VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward); + else + VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward); + VectorNormalize(shadowforward); + VectorM(scale, shadowforward, &m[0]); + if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2]) + dot1 = 1; + m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]); + CrossProduct(shadowdir, shadowforward, shadowright); + VectorM(scale, shadowright, &m[4]); + m[7] = 0.5f - DotProduct(shadoworigin, &m[4]); + VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]); + m[11] = 0.5f - DotProduct(shadoworigin, &m[8]); + Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m); + Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix); + R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL); + + VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin); + +#if 0 + qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR + R_SetupShader_ShowDepth(); +#else + qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR + R_SetupShader_DepthOrShadow(); +#endif + CHECKGLERROR + GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value); + GL_DepthMask(true); + GL_DepthTest(true); + R_SetViewport(&viewport); + GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder); + qglClearDepth(1); +#if 0 + qglClearColor(1,1,1,1); + GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +#else + GL_Clear(GL_DEPTH_BUFFER_BIT); +#endif + GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder); + CHECKGLERROR + + for (i = 0;i < r_refdef.scene.numentities;i++) + { + ent = r_refdef.scene.entities[i]; + + // cast shadows from anything of the map (submodels are optional) + if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW)) + { + relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix); + Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin); + Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection); + Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward); + Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright); + relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0])); + relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1])); + relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2])); + relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0])); + relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1])); + relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2])); + RSurf_ActiveModelEntity(ent, false, false, false); + ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs); + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity + } + } + + R_Shadow_RenderMode_End(); + + Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix); + Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix); + Matrix4x4_CreateScale3(&scalematrix, size, -size, 1); + Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias); + Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix); + Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix); + + r_shadow_usingshadowmaportho = true; + switch (r_shadow_shadowmode) + { + case R_SHADOW_SHADOWMODE_SHADOWMAP2D: + r_shadow_usingshadowmap2d = true; + break; + case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE: + r_shadow_usingshadowmaprect = true; + break; + default: + break; + } +} + void R_DrawModelShadows(void) { int i; @@ -4186,7 +4488,7 @@ void R_DrawModelShadows(void) vec3_t relativeshadowmins, relativeshadowmaxs; vec3_t tmp, shadowdir; - if (!r_refdef.scene.numentities || !vid.stencil) + if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1)) return; CHECKGLERROR @@ -4226,26 +4528,34 @@ void R_DrawModelShadows(void) { if(ent->entitynumber != 0) { - // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities) - int entnum, entnum2, recursion; - entnum = entnum2 = ent->entitynumber; - for(recursion = 32; recursion > 0; --recursion) + if(ent->entitynumber >= MAX_EDICTS) // csqc entity { - entnum2 = cl.entities[entnum].state_current.tagentity; - if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2]) - entnum = entnum2; - else - break; + // FIXME handle this + VectorNegate(ent->modellight_lightdir, relativelightdirection); } - if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain + else { - VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection); - // transform into modelspace of OUR entity - Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp); - Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection); + // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities) + int entnum, entnum2, recursion; + entnum = entnum2 = ent->entitynumber; + for(recursion = 32; recursion > 0; --recursion) + { + entnum2 = cl.entities[entnum].state_current.tagentity; + if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2]) + entnum = entnum2; + else + break; + } + if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain + { + VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection); + // transform into modelspace of OUR entity + Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp); + Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection); + } + else + VectorNegate(ent->modellight_lightdir, relativelightdirection); } - else - VectorNegate(ent->modellight_lightdir, relativelightdirection); } else VectorNegate(ent->modellight_lightdir, relativelightdirection); @@ -4282,9 +4592,9 @@ void R_DrawModelShadows(void) //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); //qglDepthFunc(GL_ALWAYS);CHECKGLERROR qglEnable(GL_STENCIL_TEST);CHECKGLERROR - qglStencilMask(~0);CHECKGLERROR + qglStencilMask(255);CHECKGLERROR qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR - qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR + qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR // apply the blend to the shadowed areas R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); @@ -4479,140 +4789,6 @@ void R_Shadow_DrawCoronas(void) -//static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"}; -typedef struct suffixinfo_s -{ - char *suffix; - qboolean flipx, flipy, flipdiagonal; -} -suffixinfo_t; -static suffixinfo_t suffix[3][6] = -{ - { - {"px", false, false, false}, - {"nx", false, false, false}, - {"py", false, false, false}, - {"ny", false, false, false}, - {"pz", false, false, false}, - {"nz", false, false, false} - }, - { - {"posx", false, false, false}, - {"negx", false, false, false}, - {"posy", false, false, false}, - {"negy", false, false, false}, - {"posz", false, false, false}, - {"negz", false, false, false} - }, - { - {"rt", true, false, true}, - {"lf", false, true, true}, - {"ft", true, true, false}, - {"bk", false, false, false}, - {"up", true, false, true}, - {"dn", true, false, true} - } -}; - -static int componentorder[4] = {0, 1, 2, 3}; - -rtexture_t *R_Shadow_LoadCubemap(const char *basename) -{ - int i, j, cubemapsize; - unsigned char *cubemappixels, *image_buffer; - rtexture_t *cubemaptexture; - char name[256]; - // must start 0 so the first loadimagepixels has no requested width/height - cubemapsize = 0; - cubemappixels = NULL; - cubemaptexture = NULL; - // keep trying different suffix groups (posx, px, rt) until one loads - for (j = 0;j < 3 && !cubemappixels;j++) - { - // load the 6 images in the suffix group - for (i = 0;i < 6;i++) - { - // generate an image name based on the base and and suffix - dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix); - // load it - if ((image_buffer = loadimagepixelsbgra(name, false, false))) - { - // an image loaded, make sure width and height are equal - if (image_width == image_height && (!cubemappixels || image_width == cubemapsize)) - { - // if this is the first image to load successfully, allocate the cubemap memory - if (!cubemappixels && image_width >= 1) - { - cubemapsize = image_width; - // note this clears to black, so unavailable sides are black - cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4); - } - // copy the image with any flipping needed by the suffix (px and posx types don't need flipping) - if (cubemappixels) - Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder); - } - else - Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height); - // free the image - Mem_Free(image_buffer); - } - } - } - // if a cubemap loaded, upload it - if (cubemappixels) - { - if (developer_loading.integer) - Con_Printf("loading cubemap \"%s\"\n", basename); - - if (!r_shadow_filters_texturepool) - r_shadow_filters_texturepool = R_AllocTexturePool(); - cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL); - Mem_Free(cubemappixels); - } - else - { - Con_DPrintf("failed to load cubemap \"%s\"\n", basename); - if (developer_loading.integer) - { - Con_Printf("(tried tried images "); - for (j = 0;j < 3;j++) - for (i = 0;i < 6;i++) - Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix); - Con_Print(" and was unable to find any of them).\n"); - } - } - return cubemaptexture; -} - -rtexture_t *R_Shadow_Cubemap(const char *basename) -{ - int i; - for (i = 0;i < numcubemaps;i++) - if (!strcasecmp(cubemaps[i].basename, basename)) - return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube; - if (i >= MAX_CUBEMAPS) - return r_texture_whitecube; - numcubemaps++; - strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename)); - cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename); - return cubemaps[i].texture; -} - -void R_Shadow_FreeCubemaps(void) -{ - int i; - for (i = 0;i < numcubemaps;i++) - { - if (developer_loading.integer) - Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename); - if (cubemaps[i].texture) - R_FreeTexture(cubemaps[i].texture); - } - - numcubemaps = 0; - R_FreeTexturePool(&r_shadow_filters_texturepool); -} - dlight_t *R_Shadow_NewWorldLight(void) { return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray); @@ -4679,7 +4855,6 @@ void R_Shadow_ClearWorldLights(void) R_Shadow_FreeWorldLight(light); } r_shadow_selectedlight = NULL; - R_Shadow_FreeCubemaps(); } void R_Shadow_SelectLight(dlight_t *light) @@ -5021,7 +5196,14 @@ typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void) { - int entnum, style, islight, skin, pflags, effects, type, n; + int entnum; + int style; + int islight; + int skin; + int pflags; + //int effects; + int type; + int n; char *entfiledata; const char *data; float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4]; @@ -5055,7 +5237,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void) style = 0; skin = 0; pflags = 0; - effects = 0; + //effects = 0; islight = false; while (1) { @@ -5182,8 +5364,8 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void) skin = (int)atof(value); else if (!strcmp("pflags", key)) pflags = (int)atof(value); - else if (!strcmp("effects", key)) - effects = (int)atof(value); + //else if (!strcmp("effects", key)) + // effects = (int)atof(value); else if (cl.worldmodel->type == mod_brushq3) { if (!strcmp("scale", key)) @@ -5693,26 +5875,26 @@ void R_Shadow_EditLights_DrawSelectedLightProperties(void) lightnumber = lightindex; lightcount++; } - dpsnprintf(temp, sizeof(temp), "Cursor origin: %.0f %.0f %.0f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false);y += 8; - dpsnprintf(temp, sizeof(temp), "Total lights : %i active (%i total)", lightcount, (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false);y += 8; + dpsnprintf(temp, sizeof(temp), "Cursor origin: %.0f %.0f %.0f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Total lights : %i active (%i total)", lightcount, (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false, FONT_DEFAULT);y += 8; y += 8; if (r_shadow_selectedlight == NULL) return; - dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; - dpsnprintf(temp, sizeof(temp), "Origin : %.0f %.0f %.0f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; - dpsnprintf(temp, sizeof(temp), "Angles : %.0f %.0f %.0f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; - dpsnprintf(temp, sizeof(temp), "Color : %.2f %.2f %.2f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; - dpsnprintf(temp, sizeof(temp), "Radius : %.0f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; - dpsnprintf(temp, sizeof(temp), "Corona : %.0f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; - dpsnprintf(temp, sizeof(temp), "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; - dpsnprintf(temp, sizeof(temp), "Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; - dpsnprintf(temp, sizeof(temp), "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; - dpsnprintf(temp, sizeof(temp), "CoronaSize : %.2f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; - dpsnprintf(temp, sizeof(temp), "Ambient : %.2f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; - dpsnprintf(temp, sizeof(temp), "Diffuse : %.2f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; - dpsnprintf(temp, sizeof(temp), "Specular : %.2f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; - dpsnprintf(temp, sizeof(temp), "NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; - dpsnprintf(temp, sizeof(temp), "RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; + dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Origin : %.0f %.0f %.0f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Angles : %.0f %.0f %.0f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Color : %.2f %.2f %.2f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Radius : %.0f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Corona : %.0f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "CoronaSize : %.2f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Ambient : %.2f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Diffuse : %.2f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Specular : %.2f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; } void R_Shadow_EditLights_ToggleShadow_f(void)