// The ambientCache is on the stack, so we don't want to leave a reference to it that would try to be freed later. Create the ambientCache immediately. static void R_FinishDeform(DrawSurf drawSurf, SrfTriangles newTri, DrawVert *ac) { if (newTri == null) { return; } // generate current normals, tangents, and bitangents We might want to support the possibility of deform functions generating // explicit normals, and we might also want to allow the cached deformInfo optimization for these. // FIXME: this doesn't work, because the deformed surface is just the ambient one, and there isn't an opportunity to generate light interactions if (drawSurf.material.ReceivesLighting) { newTri.verts = ac; R_DeriveTangents(newTri, false); newTri.verts = null; } newTri.ambientCache = vertexCache.AllocFrameTemp(ac, newTri.numVerts * DrawVert.SizeOf, false); fixed(void *newTri_indexes_ = newTri.indexes) newTri.indexCache = vertexCache.AllocFrameTemp(newTri_indexes_, newTri.numIndexes * sizeof(GlIndex), true); drawSurf.geoFrontEnd = newTri; drawSurf.ambientCache = newTri.ambientCache; drawSurf.indexCache = newTri.indexCache; drawSurf.numIndexes = newTri.numIndexes; drawSurf.numShadowIndexesNoFrontCaps = newTri.numShadowIndexesNoFrontCaps; drawSurf.numShadowIndexesNoCaps = newTri.numShadowIndexesNoCaps; drawSurf.shadowCapPlaneBits = newTri.shadowCapPlaneBits; }
public RenderModelDecal() { tri = new(); tri.verts = verts; tri.indexes = indexes; material = null; nextDecal = null; }
// are dangling edges that are outside the light frustum still making planes? public static SrfTriangles R_CreateVertexProgramTurboShadowVolume(IRenderEntity ent, SrfTriangles tri, IRenderLight light, ref SrfCullInfo cullInfo) { int i, j; SrfTriangles newTri; GlIndex[] indexes; byte *facing; var tri_indexes = tri.indexes; var tri_silEdges = tri.silEdges; R_CalcInteractionFacing(ent, tri, light, ref cullInfo); if (r_useShadowProjectedCull.Bool) { R_CalcInteractionCullBits(ent, tri, light, ref cullInfo); } var numFaces = tri.numIndexes / 3; var numShadowingFaces = 0; facing = cullInfo.facing; // if all the triangles are inside the light frustum if (cullInfo.cullBits == Interaction.LIGHT_CULL_ALL_FRONT || !r_useShadowProjectedCull.Bool) { // count the number of shadowing faces for (i = 0; i < numFaces; i++) { numShadowingFaces += facing[i]; } numShadowingFaces = numFaces - numShadowingFaces; } else { // make all triangles that are outside the light frustum "facing", so they won't cast shadows indexes = tri_indexes; var modifyFacing = cullInfo.facing; var cullBits = cullInfo.cullBits; for (j = i = 0; i < tri.numIndexes; i += 3, j++) { if (modifyFacing[j] == 0) { var i1 = indexes[i + 0]; var i2 = indexes[i + 1]; var i3 = indexes[i + 2]; if ((cullBits[i1] & cullBits[i2] & cullBits[i3]) != 0) { modifyFacing[j] = 1; } else { numShadowingFaces++; } } } } // no faces are inside the light frustum and still facing the right way if (numShadowingFaces == 0) { return(null); } // shadowVerts will be NULL on these surfaces, so the shadowVerts will be taken from the ambient surface newTri = R_AllocStaticTriSurf(); newTri.numVerts = tri.numVerts * 2; // alloc the max possible size #if USE_TRI_DATA_ALLOCATOR R_AllocStaticTriSurfIndexes(newTri, (numShadowingFaces + tri.numSilEdges) * 6); GlIndex tempIndexes = newTri.indexes; GlIndex shadowIndexes = newTri.indexes; #else GlIndex *tempIndexes = stackalloc GlIndex[tri.numSilEdges * 6 + intX.ALLOC16]; tempIndexes = (GlIndex *)_alloca16(tempIndexes); GlIndex *shadowIndexes = tempIndexes; #endif // create new triangles along sil planes SilEdge sil; for (sil = tri_silEdges, i = tri.numSilEdges; i > 0; i--, sil++) { int f1 = facing[sil.p1], f2 = facing[sil.p2]; if ((f1 ^ f2) == 0) { continue; } int v1 = sil.v1 << 1, v2 = sil.v2 << 1; // set the two triangle winding orders based on facing without using a poorly-predictable branch shadowIndexes[0] = v1; shadowIndexes[1] = v2 ^ f1; shadowIndexes[2] = v2 ^ f2; shadowIndexes[3] = v1 ^ f2; shadowIndexes[4] = v1 ^ f1; shadowIndexes[5] = v2 ^ 1; shadowIndexes += 6; } int numShadowIndexes = shadowIndexes - tempIndexes; // we aren't bothering to separate front and back caps on these newTri.numIndexes = newTri.numShadowIndexesNoFrontCaps = numShadowIndexes + numShadowingFaces * 6; newTri.numShadowIndexesNoCaps = numShadowIndexes; newTri.shadowCapPlaneBits = SHADOW_CAP_INFINITE; #if USE_TRI_DATA_ALLOCATOR // decrease the size of the memory block to only store the used indexes R_ResizeStaticTriSurfIndexes(newTri, newTri.numIndexes); #else // allocate memory for the indexes R_AllocStaticTriSurfIndexes(newTri, newTri.numIndexes); // copy the indexes we created for the sil planes Simd.Memcpy(newTri.indexes, tempIndexes, numShadowIndexes * sizeof(GlIndex)); #endif // these have no effect, because they extend to infinity newTri.bounds.Clear(); // put some faces on the model and some on the distant projection indexes = tri_indexes; shadowIndexes = newTri.indexes + numShadowIndexes; for (i = 0, j = 0; i < tri.numIndexes; i += 3, j++) { if (facing[j] != 0) { continue; } var i0 = indexes[i + 0] << 1; shadowIndexes[2] = i0; shadowIndexes[3] = i0 ^ 1; var i1 = indexes[i + 1] << 1; shadowIndexes[1] = i1; shadowIndexes[4] = i1 ^ 1; var i2 = indexes[i + 2] << 1; shadowIndexes[0] = i2; shadowIndexes[5] = i2 ^ 1; shadowIndexes += 6; } return(newTri); }
// If we know that we are "off to the side" of an infinite shadow volume, we can draw it without caps in zpass mode static bool R_PotentiallyInsideInfiniteShadow(SrfTriangles occluder, in Vector3 localView, in Vector3 localLight)
// Calculates two axis for the surface sutch that a point dotted against the axis will give a 0.0 to 1.0 range in S and T when inside the gui surface public static void R_SurfaceToTextureAxis(SrfTriangles tri, ref Vector3 origin, Vector3 *axis) { float *d0 = stackalloc float[5], d1 = stackalloc float[5]; var bounds = stackalloc (float x, float y)[2];
public void DrawTrail(int index, RenderEntity ent, SrfTriangles tri, float globalAlpha);
// If we resort the vertexes so all silverts come first, we can save some work here. public unsafe static LocalTrace R_LocalTrace(Vector3 start, Vector3 end, float radius, SrfTriangles tri) { int i, j; Plane * planes = stackalloc Plane[4]; LocalTrace hit = new(); int c_testEdges, c_testPlanes, c_intersect; Vector3 startDir; byte totalOr; float radiusSqr; var tri_verts = tri.verts.Value; var tri_indexes = tri.indexes.Value; var tri_facePlanes = tri.facePlanes.Value; #if TEST_TRACE Stopwatch trace_timer = new(); trace_timer.Start(); #endif hit.fraction = 1f; // create two planes orthogonal to each other that intersect along the trace startDir = end - start; startDir.Normalize(); startDir.NormalVectors(out planes[0].Normal, out planes[1].Normal); planes[0].d = -start * planes[0].Normal; planes[1].d = -start * planes[1].Normal; // create front and end planes so the trace is on the positive sides of both planes[2] = startDir; planes[2].d = -start * planes[2].Normal; planes[3] = -startDir; planes[3].d = -end * planes[3].Normal; // catagorize each point against the four planes var cullBits = stackalloc byte[tri.numVerts]; fixed(DrawVert *vertsD = tri_verts) Simd.TracePointCull(cullBits, out totalOr, radius, planes, vertsD, tri.numVerts); // if we don't have points on both sides of both the ray planes, no intersection if (((totalOr ^ (totalOr >> 4)) & 3) != 0) /*common.Printf("nothing crossed the trace planes\n");*/ return { (hit); } // if we don't have any points between front and end, no intersection if (((totalOr ^ (totalOr >> 1)) & 4) != 0) /*common.Printf("trace didn't reach any triangles\n");*/ return { (hit); } // scan for triangles that cross both planes c_testPlanes = c_testEdges = c_intersect = 0; radiusSqr = MathX.Square(radius); startDir = end - start; if (tri.facePlanes == null || !tri.facePlanesCalculated) { R_DeriveFacePlanes(tri); } for (i = 0, j = 0; i < tri.numIndexes; i += 3, j++) { float d1, d2, f, d, edgeLengthSqr; byte triOr; Vector3 cross, edge; Vector3[] dir = new Vector3[3]; // get sidedness info for the triangle triOr = cullBits[tri_indexes[i + 0]]; triOr |= cullBits[tri_indexes[i + 1]]; triOr |= cullBits[tri_indexes[i + 2]]; // if we don't have points on both sides of both the ray planes, no intersection if (((triOr ^ (triOr >> 4)) & 3) != 0) { continue; } // if we don't have any points between front and end, no intersection if (((triOr ^ (triOr >> 1)) & 4) != 0) { continue; } c_testPlanes++; ref Plane plane = ref tri_facePlanes[j]; d1 = plane.Distance(start); d2 = plane.Distance(end); if (d1 <= d2) { continue; // comning at it from behind or parallel } if (d1 < 0f) { continue; // starts past it } if (d2 > 0f) { continue; // finishes in front of it } f = d1 / (d1 - d2); if (f < 0f) { continue; // shouldn't happen } if (f >= hit.fraction) { continue; // have already hit something closer } c_testEdges++; // find the exact point of impact with the plane var point = start + f * startDir; // see if the point is within the three edges if radius > 0 the triangle is expanded with a circle in the triangle plane dir[0] = tri_verts[tri_indexes[i + 0]].xyz - point; dir[1] = tri_verts[tri_indexes[i + 1]].xyz - point; cross = dir[0].Cross(dir[1]); d = plane.Normal * cross; if (d > 0f) { if (radiusSqr <= 0f) { continue; } edge = tri_verts[tri_indexes[i + 0]].xyz - tri_verts[tri_indexes[i + 1]].xyz; edgeLengthSqr = edge.LengthSqr; if (cross.LengthSqr > edgeLengthSqr * radiusSqr) { continue; } d = edge * dir[0]; if (d < 0f) { edge = tri_verts[tri_indexes[i + 0]].xyz - tri_verts[tri_indexes[i + 2]].xyz; d = edge * dir[0]; if (d < 0f && dir[0].LengthSqr > radiusSqr) { continue; } } else if (d > edgeLengthSqr) { edge = tri_verts[tri_indexes[i + 1]].xyz - tri_verts[tri_indexes[i + 2]].xyz; d = edge * dir[1]; if (d < 0f && dir[1].LengthSqr > radiusSqr) { continue; } } } dir[2] = tri_verts[tri_indexes[i + 2]].xyz - point; cross = dir[1].Cross(dir[2]); d = plane.Normal * cross; if (d > 0f) { if (radiusSqr <= 0f) { continue; } edge = tri_verts[tri_indexes[i + 1]].xyz - tri_verts[tri_indexes[i + 2]].xyz; edgeLengthSqr = edge.LengthSqr; if (cross.LengthSqr > edgeLengthSqr * radiusSqr) { continue; } d = edge * dir[1]; if (d < 0f) { edge = tri_verts[tri_indexes[i + 1]].xyz - tri_verts[tri_indexes[i + 0]].xyz; d = edge * dir[1]; if (d < 0f && dir[1].LengthSqr > radiusSqr) { continue; } } else if (d > edgeLengthSqr) { edge = tri_verts[tri_indexes[i + 2]].xyz - tri_verts[tri_indexes[i + 0]].xyz; d = edge * dir[2]; if (d < 0f && dir[2].LengthSqr > radiusSqr) { continue; } } } cross = dir[2].Cross(dir[0]); d = plane.Normal * cross; if (d > 0f) { if (radiusSqr <= 0f) { continue; } edge = tri_verts[tri_indexes[i + 2]].xyz - tri_verts[tri_indexes[i + 0]].xyz; edgeLengthSqr = edge.LengthSqr; if (cross.LengthSqr > edgeLengthSqr * radiusSqr) { continue; } d = edge * dir[2]; if (d < 0f) { edge = tri_verts[tri_indexes[i + 2]].xyz - tri_verts[tri_indexes[i + 1]].xyz; d = edge * dir[2]; if (d < 0f && dir[2].LengthSqr > radiusSqr) { continue; } } else if (d > edgeLengthSqr) { edge = tri_verts[tri_indexes[i + 0]].xyz - tri_verts[tri_indexes[i + 1]].xyz; d = edge * dir[0]; if (d < 0f && dir[0].LengthSqr > radiusSqr) { continue; } } } // we hit it c_intersect++; hit.fraction = f; hit.normal = plane.Normal; hit.point = point; hit.indexes[0] = tri_indexes[i]; hit.indexes[1] = tri_indexes[i + 1]; hit.indexes[2] = tri_indexes[i + 2]; }