X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;ds=sidebyside;f=r_shadow.c;h=058d5589b96c125b7e19b444ae747487b6b80f49;hb=d4ffce6349c1960f435b8877832d88c7c54e17ba;hp=de429d0b49711a8318b307d6a81de1a990529ef7;hpb=57252d1b300d96b2353bf9d564b0de281552d2c5;p=xonotic%2Fdarkplaces.git diff --git a/r_shadow.c b/r_shadow.c index de429d0b..058d5589 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -14,8 +14,6 @@ extern void R_Shadow_EditLights_Init(void); int r_shadowstage = SHADOWSTAGE_NONE; int r_shadow_reloadlights = false; -int r_shadow_lightingmode = 0; - mempool_t *r_shadow_mempool; int maxshadowelements; @@ -26,6 +24,9 @@ int *trianglefacinglightlist; int maxshadowvertices; float *shadowvertex3f; +int maxvertexupdate; +int *vertexupdate; +int vertexupdatenum; rtexturepool_t *r_shadow_texturepool; rtexture_t *r_shadow_normalcubetexture; @@ -38,13 +39,15 @@ rtexture_t *r_shadow_blankwhitetexture; cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"}; cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"}; cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"}; -cvar_t r_shadow_realtime = {0, "r_shadow_realtime", "0"}; +cvar_t r_shadow_realtime_world = {0, "r_shadow_realtime_world", "0"}; +cvar_t r_shadow_realtime_dlight = {0, "r_shadow_realtime_dlight", "0"}; +cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"}; cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"}; cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"}; cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"}; cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"}; cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"}; -cvar_t r_shadow_shadownudge = {0, "r_shadow_shadownudge", "1"}; +cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "-1"}; cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"}; cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "100000"}; cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"}; @@ -67,6 +70,9 @@ void r_shadow_start(void) shadowelements = NULL; maxshadowvertices = 0; shadowvertex3f = NULL; + maxvertexupdate = 0; + vertexupdate = NULL; + vertexupdatenum = 0; maxtrianglefacinglight = 0; trianglefacinglight = NULL; trianglefacinglightlist = NULL; @@ -96,6 +102,9 @@ void r_shadow_shutdown(void) shadowelements = NULL; maxshadowvertices = 0; shadowvertex3f = NULL; + maxvertexupdate = 0; + vertexupdate = NULL; + vertexupdatenum = 0; maxtrianglefacinglight = 0; trianglefacinglight = NULL; trianglefacinglightlist = NULL; @@ -113,13 +122,15 @@ void R_Shadow_Init(void) Cvar_RegisterVariable(&r_shadow_lightattenuationpower); Cvar_RegisterVariable(&r_shadow_lightattenuationscale); Cvar_RegisterVariable(&r_shadow_lightintensityscale); - Cvar_RegisterVariable(&r_shadow_realtime); + Cvar_RegisterVariable(&r_shadow_realtime_world); + Cvar_RegisterVariable(&r_shadow_realtime_dlight); + Cvar_RegisterVariable(&r_shadow_visiblevolumes); Cvar_RegisterVariable(&r_shadow_gloss); Cvar_RegisterVariable(&r_shadow_debuglight); Cvar_RegisterVariable(&r_shadow_scissor); Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap); Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture); - Cvar_RegisterVariable(&r_shadow_shadownudge); + Cvar_RegisterVariable(&r_shadow_polygonoffset); Cvar_RegisterVariable(&r_shadow_portallight); Cvar_RegisterVariable(&r_shadow_projectdistance); Cvar_RegisterVariable(&r_shadow_texture3d); @@ -127,21 +138,6 @@ void R_Shadow_Init(void) R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap); } -void R_Shadow_ProjectVertex3f(float *verts, int numverts, const float *relativelightorigin, float projectdistance) -{ - int i; - float *in, *out, diff[3]; - in = verts; - out = verts + numverts * 3; - for (i = 0;i < numverts;i++, in += 3, out += 3) - { - VectorSubtract(in, relativelightorigin, diff); - VectorNormalizeFast(diff); - VectorMA(in, projectdistance, diff, out); - VectorMA(in, r_shadow_shadownudge.value, diff, in); - } -} - int R_Shadow_MakeTriangleShadowFlags_Vertex3f(const int *elements, const float *vertex, int numtris, qbyte *facing, int *list, const float *relativelightorigin) { int i, tris = 0; @@ -163,10 +159,21 @@ int R_Shadow_MakeTriangleShadowFlags_Vertex3f(const int *elements, const float * return tris; } -int R_Shadow_BuildShadowVolumeTriangles(const int *elements, const int *neighbors, int numverts, const qbyte *facing, const int *facinglist, int numfacing, int *out) +int R_Shadow_BuildShadowVolume(const int *elements, const int *neighbors, int numverts, const qbyte *facing, const int *facinglist, int numfacing, int *out, float *vertices, const float *relativelightorigin, float projectdistance) { - int i, tris; + int i, j, tris, vertexpointeradjust = numverts * 3; const int *e, *n; + float *vin, *vout; + + if (maxvertexupdate < numverts) + { + maxvertexupdate = numverts; + if (vertexupdate) + Mem_Free(vertexupdate); + vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int)); + } + vertexupdatenum++; + // check each frontface for bordering backfaces, // and cast shadow polygons from those edges, // also create front and back caps for shadow volume @@ -184,6 +191,19 @@ int R_Shadow_BuildShadowVolumeTriangles(const int *elements, const int *neighbor for (i = 0;i < numfacing;i++) { e = elements + facinglist[i] * 3; + // generate vertices if needed + for (j = 0;j < 3;j++) + { + if (vertexupdate[e[j]] != vertexupdatenum) + { + vertexupdate[e[j]] = vertexupdatenum; + vin = vertices + e[j] * 3; + vout = vin + vertexpointeradjust; + vout[0] = relativelightorigin[0] + projectdistance * (vin[0] - relativelightorigin[0]); + vout[1] = relativelightorigin[1] + projectdistance * (vin[1] - relativelightorigin[1]); + vout[2] = relativelightorigin[2] + projectdistance * (vin[2] - relativelightorigin[2]); + } + } out[0] = e[2] + numverts; out[1] = e[1] + numverts; out[2] = e[0] + numverts; @@ -319,14 +339,13 @@ void R_Shadow_Volume(int numverts, int numtris, int *elements, int *neighbors, v if (!tris) return; - // output triangle elements - tris = R_Shadow_BuildShadowVolumeTriangles(elements, neighbors, numverts, trianglefacinglight, trianglefacinglightlist, tris, shadowelements); - if (!tris) - return; - // by clever use of elements we can construct the whole shadow from // the unprojected vertices and the projected vertices - R_Shadow_ProjectVertex3f(varray_vertex3f, numverts, relativelightorigin, projectdistance); + + // output triangle elements and vertices + tris = R_Shadow_BuildShadowVolume(elements, neighbors, numverts, trianglefacinglight, trianglefacinglightlist, tris, shadowelements, varray_vertex3f, relativelightorigin, projectdistance); + if (!tris) + return; if (r_shadowstage == SHADOWSTAGE_STENCIL) { @@ -517,6 +536,22 @@ void R_Shadow_Stage_Begin(void) || r_shadow_lightattenuationpower.value != r_shadow_attenpower || r_shadow_lightattenuationscale.value != r_shadow_attenscale) R_Shadow_MakeTextures(); + + memset(&m, 0, sizeof(m)); + m.blendfunc1 = GL_ONE; + m.blendfunc2 = GL_ZERO; + R_Mesh_State(&m); + GL_Color(0, 0, 0, 1); + qglDisable(GL_SCISSOR_TEST); + r_shadowstage = SHADOWSTAGE_NONE; + + c_rt_lights = c_rt_clears = c_rt_scissored = 0; + c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0; + c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0; +} + +void R_Shadow_LoadWorldLightsIfNeeded(void) +{ if (r_shadow_reloadlights && cl.worldmodel) { R_Shadow_ClearWorldLights(); @@ -529,17 +564,6 @@ void R_Shadow_Stage_Begin(void) R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(); } } - - memset(&m, 0, sizeof(m)); - m.blendfunc1 = GL_ONE; - m.blendfunc2 = GL_ZERO; - R_Mesh_State(&m); - GL_Color(0, 0, 0, 1); - r_shadowstage = SHADOWSTAGE_NONE; - - c_rt_lights = c_rt_clears = c_rt_scissored = 0; - c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0; - c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0; } void R_Shadow_Stage_ShadowVolumes(void) @@ -793,7 +817,9 @@ int R_Shadow_ScissorForBBox(const float *mins, const float *maxs) if (!r_shadow_scissor.integer) return false; // if view is inside the box, just say yes it's visible - if (BoxesOverlap(r_origin, r_origin, mins, maxs)) + // LordHavoc: for some odd reason scissor seems broken without stencil + // (?!? seems like a driver bug) so abort if gl_stencil is false + if (!gl_stencil || BoxesOverlap(r_origin, r_origin, mins, maxs)) { qglDisable(GL_SCISSOR_TEST); return false; @@ -815,8 +841,7 @@ int R_Shadow_ScissorForBBox(const float *mins, const float *maxs) if (DotProduct(vpn, v2) <= f) { // entirely behind nearclip plane - qglDisable(GL_SCISSOR_TEST); - return false; + return true; } if (DotProduct(vpn, v) >= f) { @@ -955,19 +980,28 @@ int R_Shadow_ScissorForBBox(const float *mins, const float *maxs) return false; } -void R_Shadow_VertexLighting(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const float *relativelightorigin, float lightradius) +void R_Shadow_VertexLighting(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m) { float *color4f = varray_color4f; - float dist, dot, intensity, iradius = 1.0f / lightradius, radius2 = lightradius * lightradius, v[3]; + float dist, dot, intensity, v[3], n[3]; for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4) { - VectorSubtract(vertex3f, relativelightorigin, v); - if ((dot = DotProduct(normal3f, v)) > 0 && (dist = DotProduct(v, v)) < radius2) + Matrix4x4_Transform(m, vertex3f, v); + if ((dist = DotProduct(v, v)) < 1) { - dist = sqrt(dist); - intensity = pow(1 - (dist * iradius), r_shadow_attenpower) * r_shadow_attenscale * dot / dist; - VectorScale(lightcolor, intensity, color4f); - color4f[3] = 1; + Matrix4x4_Transform3x3(m, normal3f, n); + if ((dot = DotProduct(n, v)) > 0) + { + dist = sqrt(dist); + intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale * dot / sqrt(DotProduct(n,n)); + VectorScale(lightcolor, intensity, color4f); + color4f[3] = 1; + } + else + { + VectorClear(color4f); + color4f[3] = 1; + } } else { @@ -977,18 +1011,27 @@ void R_Shadow_VertexLighting(int numverts, const float *vertex3f, const float *n } } -void R_Shadow_VertexLightingWithXYAttenuationTexture(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const float *relativelightorigin, float lightradius, const float *zdir) +void R_Shadow_VertexLightingWithXYAttenuationTexture(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m) { float *color4f = varray_color4f; - float dist, dot, intensity, iradius = 1.0f / lightradius, v[3]; + float dist, dot, intensity, v[3], n[3]; for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4) { - VectorSubtract(vertex3f, relativelightorigin, v); - if ((dot = DotProduct(normal3f, v)) > 0 && (dist = fabs(DotProduct(zdir, v))) < lightradius) + Matrix4x4_Transform(m, vertex3f, v); + if ((dist = fabs(v[2])) < 1) { - intensity = pow(1 - (dist * iradius), r_shadow_attenpower) * r_shadow_attenscale * dot / sqrt(DotProduct(v,v)); - VectorScale(lightcolor, intensity, color4f); - color4f[3] = 1; + Matrix4x4_Transform3x3(m, normal3f, n); + if ((dot = DotProduct(n, v)) > 0) + { + intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale * dot / sqrt(DotProduct(n,n)); + VectorScale(lightcolor, intensity, color4f); + color4f[3] = 1; + } + else + { + VectorClear(color4f); + color4f[3] = 1; + } } else { @@ -1360,7 +1403,7 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element R_Mesh_CopyVertex3f(vertex3f, numverts); R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts); R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz); - R_Shadow_VertexLightingWithXYAttenuationTexture(numverts, vertex3f, normal3f, color2, relativelightorigin, lightradius, matrix_modeltofilter->m[2]); + R_Shadow_VertexLightingWithXYAttenuationTexture(numverts, vertex3f, normal3f, color, matrix_modeltofilter); R_Mesh_Draw(numverts, numtriangles, elements); } } @@ -1388,8 +1431,7 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element R_Mesh_GetSpace(numverts); R_Mesh_CopyVertex3f(vertex3f, numverts); R_Mesh_CopyTexCoord2f(0, texcoord2f, numverts); - VectorScale(lightcolor, r_colorscale * r_shadow_lightintensityscale.value, color); - R_Shadow_VertexLighting(numverts, vertex3f, normal3f, color, relativelightorigin, lightradius); + R_Shadow_VertexLighting(numverts, vertex3f, normal3f, color, matrix_modeltofilter); R_Mesh_Draw(numverts, numtriangles, elements); } } @@ -1412,13 +1454,15 @@ void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elemen { if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare! { - // 2/0/0/0/1/2 3D combine blendsquare path + // 2/0/0/1/2 3D combine blendsquare path m.tex[0] = R_GetTexture(bumptexture); m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture); m.texcombinergb[1] = GL_DOT3_RGBA_ARB; R_Mesh_TextureState(&m); qglColorMask(0,0,0,1); - qglDisable(GL_BLEND); + // this squares the result + qglEnable(GL_BLEND); + qglBlendFunc(GL_SRC_ALPHA, GL_ZERO); GL_Color(1,1,1,1); R_Mesh_GetSpace(numverts); R_Mesh_CopyVertex3f(vertex3f, numverts); @@ -1434,12 +1478,11 @@ void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elemen R_Mesh_TextureState(&m); // square alpha in framebuffer a few times to make it shiny qglBlendFunc(GL_ZERO, GL_DST_ALPHA); - qglEnable(GL_BLEND); // these comments are a test run through this math for intensity 0.5 - // 0.5 * 0.5 = 0.25 - // 0.25 * 0.25 = 0.0625 - // 0.0625 * 0.0625 = 0.00390625 - for (renders = 0;renders < 3;renders++) + // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier) + // 0.25 * 0.25 = 0.0625 (this is another pass) + // 0.0625 * 0.0625 = 0.00390625 (this is another pass) + for (renders = 0;renders < 2;renders++) { R_Mesh_GetSpace(numverts); R_Mesh_CopyVertex3f(vertex3f, numverts); @@ -1484,13 +1527,15 @@ void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elemen } else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare! { - // 2/0/0/0/2 3D combine blendsquare path + // 2/0/0/2 3D combine blendsquare path m.tex[0] = R_GetTexture(bumptexture); m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture); m.texcombinergb[1] = GL_DOT3_RGBA_ARB; R_Mesh_TextureState(&m); qglColorMask(0,0,0,1); - qglDisable(GL_BLEND); + // this squares the result + qglEnable(GL_BLEND); + qglBlendFunc(GL_SRC_ALPHA, GL_ZERO); GL_Color(1,1,1,1); R_Mesh_GetSpace(numverts); R_Mesh_CopyVertex3f(vertex3f, numverts); @@ -1506,12 +1551,11 @@ void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elemen R_Mesh_TextureState(&m); // square alpha in framebuffer a few times to make it shiny qglBlendFunc(GL_ZERO, GL_DST_ALPHA); - qglEnable(GL_BLEND); // these comments are a test run through this math for intensity 0.5 - // 0.5 * 0.5 = 0.25 - // 0.25 * 0.25 = 0.0625 - // 0.0625 * 0.0625 = 0.00390625 - for (renders = 0;renders < 3;renders++) + // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier) + // 0.25 * 0.25 = 0.0625 (this is another pass) + // 0.0625 * 0.0625 = 0.00390625 (this is another pass) + for (renders = 0;renders < 2;renders++) { R_Mesh_GetSpace(numverts); R_Mesh_CopyVertex3f(vertex3f, numverts); @@ -1548,13 +1592,15 @@ void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elemen } else if (r_textureunits.integer >= 2 /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare! { - // 2/0/0/0/2/2 2D combine blendsquare path + // 2/0/0/2/2 2D combine blendsquare path m.tex[0] = R_GetTexture(bumptexture); m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture); m.texcombinergb[1] = GL_DOT3_RGBA_ARB; R_Mesh_TextureState(&m); qglColorMask(0,0,0,1); - qglDisable(GL_BLEND); + // this squares the result + qglEnable(GL_BLEND); + qglBlendFunc(GL_SRC_ALPHA, GL_ZERO); GL_Color(1,1,1,1); R_Mesh_GetSpace(numverts); R_Mesh_CopyVertex3f(vertex3f, numverts); @@ -1570,12 +1616,11 @@ void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elemen R_Mesh_TextureState(&m); // square alpha in framebuffer a few times to make it shiny qglBlendFunc(GL_ZERO, GL_DST_ALPHA); - qglEnable(GL_BLEND); // these comments are a test run through this math for intensity 0.5 - // 0.5 * 0.5 = 0.25 - // 0.25 * 0.25 = 0.0625 - // 0.0625 * 0.0625 = 0.00390625 - for (renders = 0;renders < 3;renders++) + // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier) + // 0.25 * 0.25 = 0.0625 (this is another pass) + // 0.0625 * 0.0625 = 0.00390625 (this is another pass) + for (renders = 0;renders < 2;renders++) { R_Mesh_GetSpace(numverts); R_Mesh_CopyVertex3f(vertex3f, numverts); @@ -1811,9 +1856,8 @@ void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style // now that we have the buffers big enough, construct shadow volume mesh memcpy(vertex3f, castmesh->vertex3f, castmesh->numverts * sizeof(float[3])); - R_Shadow_ProjectVertex3f(vertex3f, castmesh->numverts, e->origin, r_shadow_projectdistance.value);//, e->lightradius); tris = R_Shadow_MakeTriangleShadowFlags_Vertex3f(castmesh->element3i, vertex3f, castmesh->numtriangles, trianglefacinglight, trianglefacinglightlist, e->origin); - tris = R_Shadow_BuildShadowVolumeTriangles(castmesh->element3i, castmesh->neighbor3i, castmesh->numverts, trianglefacinglight, trianglefacinglightlist, tris, shadowelements); + tris = R_Shadow_BuildShadowVolume(castmesh->element3i, castmesh->neighbor3i, castmesh->numverts, trianglefacinglight, trianglefacinglightlist, tris, shadowelements, vertex3f, e->origin, r_shadow_projectdistance.value); // add the constructed shadow volume mesh Mod_ShadowMesh_AddMesh(r_shadow_mempool, e->shadowvolume, castmesh->numverts, vertex3f, tris, shadowelements); } @@ -2254,18 +2298,6 @@ void R_Shadow_SetCursorLocationForView(void) r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value; } -void R_Shadow_UpdateLightingMode(void) -{ - r_shadow_lightingmode = 0; - if (r_shadow_realtime.integer) - { - if (r_shadow_worldlightchain) - r_shadow_lightingmode = 2; - else - r_shadow_lightingmode = 1; - } -} - void R_Shadow_UpdateWorldLightSelection(void) { R_Shadow_SetCursorLocationForView();