// Determines which triangles of the surface are facing towards the light origin. // The facing array should be allocated with one extra index than the number of surface triangles, which will be used to handle dangling edge silhouettes. static void R_CalcInteractionFacing(IRenderEntity ent, SrfTriangles tri, IRenderLight light, ref SrfCullInfo cullInfo) { if (cullInfo.facing != null) { return; } Vector3 localLightOrigin; R_GlobalPointToLocal(ent.modelMatrix, light.globalLightOrigin, out localLightOrigin); var numFaces = tri.numIndexes / 3; if (tri.facePlanes == null || !tri.facePlanesCalculated) { R_DeriveFacePlanes(tri); } cullInfo.facing = (byte *)R_StaticAlloc((numFaces + 1) * sizeof(byte)); // calculate back face culling var planeSide = stackalloc float[numFaces + floatX.ALLOC16]; planeSide = (float *)_alloca16(planeSide); // exact geometric cull against face fixed(Plane *facePlanesP = tri.facePlanes) Simd.Dotcp(planeSide, localLightOrigin, facePlanesP, numFaces); Simd.CmpGE(cullInfo.facing, planeSide, 0f, numFaces); cullInfo.facing[numFaces] = 1; // for dangling edges to reference }
// We want to cull a little on the sloppy side, because the pre-clipping of geometry to the lights in dmap will give many cases that are right // at the border we throw things out on the border, because if any one vertex is clearly inside, the entire triangle will be accepted. static void R_CalcInteractionCullBits(IRenderEntity ent, SrfTriangles tri, IRenderLight light, ref SrfCullInfo cullInfo) { int i, frontBits; if (cullInfo.cullBits != null) { return; } frontBits = 0; // cull the triangle surface bounding box for (i = 0; i < 6; i++) { R_GlobalPlaneToLocal(ent.modelMatrix, -light.frustum[i], out cullInfo.localClipPlanes[i]); // get front bits for the whole surface if (tri.bounds.PlaneDistance(cullInfo.localClipPlanes[i]) >= IInteraction.LIGHT_CLIP_EPSILON) { frontBits |= 1 << i; } } // if the surface is completely inside the light frustum if (frontBits == ((1 << 6) - 1)) { cullInfo.cullBits = IInteraction.LIGHT_CULL_ALL_FRONT; return; } cullInfo.cullBits = (byte *)R_StaticAlloc(tri.numVerts * sizeof(byte)); Simd.Memset(cullInfo.cullBits, 0, tri.numVerts * sizeof(byte)); var planeSide = stackalloc float[tri.numVerts + floatX.ALLOC16]; planeSide = (float *)_alloca16(planeSide); for (i = 0; i < 6; i++) { // if completely infront of this clipping plane if ((frontBits & (1 << i)) != 0) { continue; fixed(DrawVert *vertsD = tri.verts) Simd.Dotpd(planeSide, cullInfo.localClipPlanes[i], vertsD, tri.numVerts); Simd.CmpLTb(cullInfo.cullBits, (byte)i, planeSide, IInteraction.LIGHT_CLIP_EPSILON, tri.numVerts); } }