-static int R_Shadow_ConstructShadowVolume_ZFail(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
-{
- int i, j;
- int outtriangles = 0, outvertices = 0;
- const int *element;
- const float *vertex;
- float ratio, direction[3], projectvector[3];
-
- if (projectdirection)
- VectorScale(projectdirection, projectdistance, projectvector);
- else
- VectorClear(projectvector);
-
- // create the vertices
- if (projectdirection)
- {
- for (i = 0;i < numshadowmarktris;i++)
- {
- element = inelement3i + shadowmarktris[i] * 3;
- for (j = 0;j < 3;j++)
- {
- if (vertexupdate[element[j]] != vertexupdatenum)
- {
- vertexupdate[element[j]] = vertexupdatenum;
- vertexremap[element[j]] = outvertices;
- vertex = invertex3f + element[j] * 3;
- // project one copy of the vertex according to projectvector
- VectorCopy(vertex, outvertex3f);
- VectorAdd(vertex, projectvector, (outvertex3f + 3));
- outvertex3f += 6;
- outvertices += 2;
- }
- }
- }
- }
- else
- {
- for (i = 0;i < numshadowmarktris;i++)
- {
- element = inelement3i + shadowmarktris[i] * 3;
- for (j = 0;j < 3;j++)
- {
- if (vertexupdate[element[j]] != vertexupdatenum)
- {
- vertexupdate[element[j]] = vertexupdatenum;
- vertexremap[element[j]] = outvertices;
- vertex = invertex3f + element[j] * 3;
- // project one copy of the vertex to the sphere radius of the light
- // (FIXME: would projecting it to the light box be better?)
- VectorSubtract(vertex, projectorigin, direction);
- ratio = projectdistance / VectorLength(direction);
- VectorCopy(vertex, outvertex3f);
- VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
- outvertex3f += 6;
- outvertices += 2;
- }
- }
- }
- }
-
- if (r_shadow_frontsidecasting.integer)
- {
- for (i = 0;i < numshadowmarktris;i++)
- {
- int remappedelement[3];
- int markindex;
- const int *neighbortriangle;
-
- markindex = shadowmarktris[i] * 3;
- element = inelement3i + markindex;
- neighbortriangle = inneighbor3i + markindex;
- // output the front and back triangles
- outelement3i[0] = vertexremap[element[0]];
- outelement3i[1] = vertexremap[element[1]];
- outelement3i[2] = vertexremap[element[2]];
- outelement3i[3] = vertexremap[element[2]] + 1;
- outelement3i[4] = vertexremap[element[1]] + 1;
- outelement3i[5] = vertexremap[element[0]] + 1;
-
- outelement3i += 6;
- outtriangles += 2;
- // output the sides (facing outward from this triangle)
- if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
- {
- remappedelement[0] = vertexremap[element[0]];
- remappedelement[1] = vertexremap[element[1]];
- outelement3i[0] = remappedelement[1];
- outelement3i[1] = remappedelement[0];
- outelement3i[2] = remappedelement[0] + 1;
- outelement3i[3] = remappedelement[1];
- outelement3i[4] = remappedelement[0] + 1;
- outelement3i[5] = remappedelement[1] + 1;
-
- outelement3i += 6;
- outtriangles += 2;
- }
- if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
- {
- remappedelement[1] = vertexremap[element[1]];
- remappedelement[2] = vertexremap[element[2]];
- outelement3i[0] = remappedelement[2];
- outelement3i[1] = remappedelement[1];
- outelement3i[2] = remappedelement[1] + 1;
- outelement3i[3] = remappedelement[2];
- outelement3i[4] = remappedelement[1] + 1;
- outelement3i[5] = remappedelement[2] + 1;
-
- outelement3i += 6;
- outtriangles += 2;
- }
- if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
- {
- remappedelement[0] = vertexremap[element[0]];
- remappedelement[2] = vertexremap[element[2]];
- outelement3i[0] = remappedelement[0];
- outelement3i[1] = remappedelement[2];
- outelement3i[2] = remappedelement[2] + 1;
- outelement3i[3] = remappedelement[0];
- outelement3i[4] = remappedelement[2] + 1;
- outelement3i[5] = remappedelement[0] + 1;
-
- outelement3i += 6;
- outtriangles += 2;
- }
- }
- }
- else
- {
- for (i = 0;i < numshadowmarktris;i++)
- {
- int remappedelement[3];
- int markindex;
- const int *neighbortriangle;
-
- markindex = shadowmarktris[i] * 3;
- element = inelement3i + markindex;
- neighbortriangle = inneighbor3i + markindex;
- // output the front and back triangles
- outelement3i[0] = vertexremap[element[2]];
- outelement3i[1] = vertexremap[element[1]];
- outelement3i[2] = vertexremap[element[0]];
- outelement3i[3] = vertexremap[element[0]] + 1;
- outelement3i[4] = vertexremap[element[1]] + 1;
- outelement3i[5] = vertexremap[element[2]] + 1;
-
- outelement3i += 6;
- outtriangles += 2;
- // output the sides (facing outward from this triangle)
- if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
- {
- remappedelement[0] = vertexremap[element[0]];
- remappedelement[1] = vertexremap[element[1]];
- outelement3i[0] = remappedelement[0];
- outelement3i[1] = remappedelement[1];
- outelement3i[2] = remappedelement[1] + 1;
- outelement3i[3] = remappedelement[0];
- outelement3i[4] = remappedelement[1] + 1;
- outelement3i[5] = remappedelement[0] + 1;
-
- outelement3i += 6;
- outtriangles += 2;
- }
- if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
- {
- remappedelement[1] = vertexremap[element[1]];
- remappedelement[2] = vertexremap[element[2]];
- outelement3i[0] = remappedelement[1];
- outelement3i[1] = remappedelement[2];
- outelement3i[2] = remappedelement[2] + 1;
- outelement3i[3] = remappedelement[1];
- outelement3i[4] = remappedelement[2] + 1;
- outelement3i[5] = remappedelement[1] + 1;
-
- outelement3i += 6;
- outtriangles += 2;
- }
- if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
- {
- remappedelement[0] = vertexremap[element[0]];
- remappedelement[2] = vertexremap[element[2]];
- outelement3i[0] = remappedelement[2];
- outelement3i[1] = remappedelement[0];
- outelement3i[2] = remappedelement[0] + 1;
- outelement3i[3] = remappedelement[2];
- outelement3i[4] = remappedelement[0] + 1;
- outelement3i[5] = remappedelement[2] + 1;
-
- outelement3i += 6;
- outtriangles += 2;
- }
- }
- }
- if (outnumvertices)
- *outnumvertices = outvertices;
- return outtriangles;
-}
-
-static int R_Shadow_ConstructShadowVolume_ZPass(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
-{
- int i, j, k;
- int outtriangles = 0, outvertices = 0;
- const int *element;
- const float *vertex;
- float ratio, direction[3], projectvector[3];
- qboolean side[4];
-
- if (projectdirection)
- VectorScale(projectdirection, projectdistance, projectvector);
- else
- VectorClear(projectvector);
-
- for (i = 0;i < numshadowmarktris;i++)
- {
- int remappedelement[3];
- int markindex;
- const int *neighbortriangle;
-
- markindex = shadowmarktris[i] * 3;
- neighbortriangle = inneighbor3i + markindex;
- side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
- side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
- side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
- if (side[0] + side[1] + side[2] == 0)
- continue;
-
- side[3] = side[0];
- element = inelement3i + markindex;
-
- // create the vertices
- for (j = 0;j < 3;j++)
- {
- if (side[j] + side[j+1] == 0)
- continue;
- k = element[j];
- if (vertexupdate[k] != vertexupdatenum)
- {
- vertexupdate[k] = vertexupdatenum;
- vertexremap[k] = outvertices;
- vertex = invertex3f + k * 3;
- VectorCopy(vertex, outvertex3f);
- if (projectdirection)
- {
- // project one copy of the vertex according to projectvector
- VectorAdd(vertex, projectvector, (outvertex3f + 3));
- }
- else
- {
- // project one copy of the vertex to the sphere radius of the light
- // (FIXME: would projecting it to the light box be better?)
- VectorSubtract(vertex, projectorigin, direction);
- ratio = projectdistance / VectorLength(direction);
- VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
- }
- outvertex3f += 6;
- outvertices += 2;
- }
- }
-
- // output the sides (facing outward from this triangle)
- if (!side[0])
- {
- remappedelement[0] = vertexremap[element[0]];
- remappedelement[1] = vertexremap[element[1]];
- outelement3i[0] = remappedelement[1];
- outelement3i[1] = remappedelement[0];
- outelement3i[2] = remappedelement[0] + 1;
- outelement3i[3] = remappedelement[1];
- outelement3i[4] = remappedelement[0] + 1;
- outelement3i[5] = remappedelement[1] + 1;
-
- outelement3i += 6;
- outtriangles += 2;
- }
- if (!side[1])
- {
- remappedelement[1] = vertexremap[element[1]];
- remappedelement[2] = vertexremap[element[2]];
- outelement3i[0] = remappedelement[2];
- outelement3i[1] = remappedelement[1];
- outelement3i[2] = remappedelement[1] + 1;
- outelement3i[3] = remappedelement[2];
- outelement3i[4] = remappedelement[1] + 1;
- outelement3i[5] = remappedelement[2] + 1;
-
- outelement3i += 6;
- outtriangles += 2;
- }
- if (!side[2])
- {
- remappedelement[0] = vertexremap[element[0]];
- remappedelement[2] = vertexremap[element[2]];
- outelement3i[0] = remappedelement[0];
- outelement3i[1] = remappedelement[2];
- outelement3i[2] = remappedelement[2] + 1;
- outelement3i[3] = remappedelement[0];
- outelement3i[4] = remappedelement[2] + 1;
- outelement3i[5] = remappedelement[0] + 1;
-
- outelement3i += 6;
- outtriangles += 2;
- }
- }
- if (outnumvertices)
- *outnumvertices = outvertices;
- return outtriangles;
-}
-
-void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, 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 t, tend;
- const int *e;
- const float *v[3];
- float normal[3];
- if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
- return;
- 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)
- {
- TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
- if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
- 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;
- }
- }
- }
-}
-
-static 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 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
- {
- tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
- R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
- R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
- }
- 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;
- if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
- {
- // increment stencil if frontface is infront of depthbuffer
- GL_CullFace(r_refdef.view.cullface_front);
- R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
- R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
- // decrement stencil if backface is infront of depthbuffer
- GL_CullFace(r_refdef.view.cullface_back);
- R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
- }
- else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
- {
- // decrement stencil if backface is behind depthbuffer
- GL_CullFace(r_refdef.view.cullface_front);
- R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
- R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
- // increment stencil if frontface is behind depthbuffer
- GL_CullFace(r_refdef.view.cullface_back);
- R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
- }
- R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
- R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
- }
-}
-