+ //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;
+ }
+ }
+ }
+ }
+ 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]))
+ {
+ 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;
+ }
+ }
+ }
+ }
+ }
+ 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))
+ {
+ 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;
+ }
+ }
+ }
+ }
+ 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))
+ {
+ 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;
+ }
+ }
+ }
+ }
+ }
+ return surfacemask;
+}
+
+void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, const int *elements, int numsidetris, const int *sidetotals, const unsigned char *sides, const int *sidetris)
+{
+ int i, j, outtriangles = 0;
+ int *outelement3i[6];
+ if (!numverts || !numsidetris || !r_shadow_compilingrtlight)