- shadowmarklist[numshadowmark++] = t;
- }
- }
- else
- {
- for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
- if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
- shadowmarklist[numshadowmark++] = t;
- }
- }
- else
- {
- // surface box not entirely inside light box, cull each triangle
- if (projectdirection)
- {
- for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
- {
- v[0] = invertex3f + e[0] * 3;
- v[1] = invertex3f + e[1] * 3;
- v[2] = invertex3f + e[2] * 3;
- TriangleNormal(v[0], v[1], v[2], normal);
- if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
- && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
- shadowmarklist[numshadowmark++] = t;
- }
- }
- else
- {
- for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
- {
- v[0] = invertex3f + e[0] * 3;
- v[1] = invertex3f + e[1] * 3;
- v[2] = invertex3f + e[2] * 3;
- if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
- && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
- shadowmarklist[numshadowmark++] = t;
- }
- }
- }
-}
-
-qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
-{
-#if 1
- return false;
-#else
- if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
- return false;
- // check if the shadow volume intersects the near plane
- //
- // a ray between the eye and light origin may intersect the caster,
- // indicating that the shadow may touch the eye location, however we must
- // test the near plane (a polygon), not merely the eye location, so it is
- // easiest to enlarge the caster bounding shape slightly for this.
- // TODO
- return true;
-#endif
-}
-
-void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris, vec3_t trismins, vec3_t trismaxs)
-{
- int i, tris, outverts;
- if (projectdistance < 0.1)
- {
- Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
- return;
- }
- if (!numverts || !nummarktris)
- return;
- // make sure shadowelements is big enough for this volume
- if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
- R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
-
- if (maxvertexupdate < numverts)
- {
- maxvertexupdate = numverts;
- if (vertexupdate)
- Mem_Free(vertexupdate);
- if (vertexremap)
- Mem_Free(vertexremap);
- vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
- vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
- vertexupdatenum = 0;
- }
- vertexupdatenum++;
- if (vertexupdatenum == 0)
- {
- vertexupdatenum = 1;
- memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
- memset(vertexremap, 0, maxvertexupdate * sizeof(int));
- }
-
- for (i = 0;i < nummarktris;i++)
- shadowmark[marktris[i]] = shadowmarkcount;
-
- if (r_shadow_compilingrtlight)
- {
- // if we're compiling an rtlight, capture the mesh
- //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
- //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
- tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
- Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
- }
- else
- {
- // decide which type of shadow to generate and set stencil mode
- R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
- // generate the sides or a solid volume, depending on type
- if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
- tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
- else
- tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
- r_refdef.stats.lights_dynamicshadowtriangles += tris;
- 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
- GL_CullFace(r_refdef.view.cullface_front);
- qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
- R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
- // decrement stencil if backface is infront of depthbuffer
- GL_CullFace(r_refdef.view.cullface_back);
- qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
- }
- else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
- {
- // decrement stencil if backface is behind depthbuffer
- GL_CullFace(r_refdef.view.cullface_front);
- qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
- R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
- // increment stencil if frontface is behind depthbuffer
- GL_CullFace(r_refdef.view.cullface_back);
- qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
- }
- R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
- GL_LockArrays(0, 0);
- CHECKGLERROR
- }
-}
-
-int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
-{
- // p1, p2, p3 are in the cubemap's local coordinate system
- // bias = border/(size - border)
- int mask = 0x3F;
-
- float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
- dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
- dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
- if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
- mask &= (3<<4)
- | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
- | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
- | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
- if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
- mask &= (3<<4)
- | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
- | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
- | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
-
- dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
- dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
- dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
- if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
- mask &= (3<<0)
- | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
- | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
- | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
- if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
- mask &= (3<<0)
- | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
- | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
- | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
-
- dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
- dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
- dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
- if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
- mask &= (3<<2)
- | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
- | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
- | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
- if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
- mask &= (3<<2)
- | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
- | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
- | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
-
- return mask;
-}
-
-int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
-{
- vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
- float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
- int mask = 0x3F;
-
- VectorSubtract(maxs, mins, radius);
- VectorScale(radius, 0.5f, radius);
- VectorAdd(mins, radius, center);
- Matrix4x4_Transform(worldtolight, center, lightcenter);
- Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
- VectorSubtract(lightcenter, lightradius, pmin);
- VectorAdd(lightcenter, lightradius, pmax);
-
- dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
- dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
- if(ap1 > bias*an1 && ap2 > bias*an2)
- mask &= (3<<4)
- | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
- | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
- if(an1 > bias*ap1 && an2 > bias*ap2)
- mask &= (3<<4)
- | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
- | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
-
- dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
- dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
- if(ap1 > bias*an1 && ap2 > bias*an2)
- mask &= (3<<0)
- | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
- | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
- if(an1 > bias*ap1 && an2 > bias*ap2)
- mask &= (3<<0)
- | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
- | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
-
- dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
- dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
- if(ap1 > bias*an1 && ap2 > bias*an2)
- mask &= (3<<2)
- | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
- | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
- if(an1 > bias*ap1 && an2 > bias*ap2)
- mask &= (3<<2)
- | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
- | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
-
- return mask;
-}
-
-#define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
-
-int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
-{
- // p is in the cubemap's local coordinate system
- // bias = border/(size - border)
- float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
- float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
- float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
- int mask = 0x3F;
- if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
- if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
- if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
- if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
- if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
- if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
- return mask;
-}
-
-int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
-{
- int i;
- vec3_t p, n;
- int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
- float scale = (size - 2*border)/size, len;
- float bias = border / (float)(size - border), dp, dn, ap, an;
- // check if cone enclosing side would cross frustum plane
- scale = 2 / (scale*scale + 2);
- for (i = 0;i < 5;i++)
- {
- if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
- continue;
- Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
- len = scale*VectorLength2(n);
- if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
- if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
- if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
- }
- if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
- {
- Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
- len = scale*VectorLength(n);
- if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
- if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
- if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
- }
- // 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
- 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),
- 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));
- }
- return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
-}
-
-int R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals)
-{
- int t, tend;
- const int *e;
- const float *v[3];
- float normal[3];
- vec3_t p[3];
- float bias;
- int mask, surfacemask = 0;
- if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
- return 0;
- bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
- tend = firsttriangle + numtris;
- if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
- {
- // surface box entirely inside light box, no box cull
- if (projectdirection)
- {
- for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
- {
- v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
- TriangleNormal(v[0], v[1], v[2], normal);
- if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
- {
- Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
- mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
- surfacemask |= mask;
- if(totals)
- {
- totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
- shadowsides[numshadowsides] = mask;
- shadowsideslist[numshadowsides++] = t;
- }
- }