shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts)
{
shadowmesh_t *mesh;
-#define ALLOCMESHINPIECES 0
-#if ALLOCMESHINPIECES
- mesh = Mem_Alloc(mempool, sizeof(shadowmesh_t));
-#else
- mesh = Mem_Alloc(mempool, sizeof(shadowmesh_t) + maxverts * sizeof(float[4]) + maxverts * sizeof(int[3]) + maxverts * sizeof(int[3]));
-#endif
+ mesh = Mem_Alloc(mempool, sizeof(shadowmesh_t) + maxverts * sizeof(float[4]) + maxverts * sizeof(int[3]) + maxverts * sizeof(int[3]) + SHADOWMESHVERTEXHASH * sizeof(shadowmeshvertexhash_t *) + maxverts * sizeof(shadowmeshvertexhash_t));
mesh->maxverts = maxverts;
mesh->maxtriangles = maxverts;
mesh->numverts = 0;
mesh->numtriangles = 0;
-#if ALLOCMESHINPIECES
- mesh->verts = Mem_Alloc(mempool, maxverts * sizeof(float[4]));
- mesh->elements = Mem_Alloc(mempool, maxverts * sizeof(int[3]));
- mesh->neighbors = Mem_Alloc(mempool, maxverts * sizeof(int[3]));
-#else
mesh->verts = (float *)(mesh + 1);
mesh->elements = (int *)(mesh->verts + mesh->maxverts * 4);
mesh->neighbors = (int *)(mesh->elements + mesh->maxtriangles * 3);
-#endif
+ mesh->vertexhashtable = (shadowmeshvertexhash_t **)(mesh->neighbors + mesh->maxtriangles * 3);
+ mesh->vertexhashentries = (shadowmeshvertexhash_t *)(mesh->vertexhashtable + SHADOWMESHVERTEXHASH);
return mesh;
}
shadowmesh_t *Mod_ShadowMesh_ReAlloc(mempool_t *mempool, shadowmesh_t *oldmesh)
{
shadowmesh_t *newmesh;
-#if ALLOCMESHINPIECES
- newmesh = Mem_Alloc(mempool, sizeof(shadowmesh_t));
-#else
newmesh = Mem_Alloc(mempool, sizeof(shadowmesh_t) + oldmesh->numverts * sizeof(float[4]) + oldmesh->numtriangles * sizeof(int[3]) + oldmesh->numtriangles * sizeof(int[3]));
-#endif
newmesh->maxverts = newmesh->numverts = oldmesh->numverts;
newmesh->maxtriangles = newmesh->numtriangles = oldmesh->numtriangles;
-#if ALLOCMESHINPIECES
- newmesh->verts = Mem_Alloc(mempool, newmesh->maxverts * sizeof(float[4]));
- newmesh->elements = Mem_Alloc(mempool, newmesh->numtriangles * sizeof(int[3]));
- newmesh->neighbors = Mem_Alloc(mempool, newmesh->numtriangles * sizeof(int[3]));
-#else
newmesh->verts = (float *)(newmesh + 1);
newmesh->elements = (int *)(newmesh->verts + newmesh->maxverts * 4);
newmesh->neighbors = (int *)(newmesh->elements + newmesh->maxtriangles * 3);
-#endif
memcpy(newmesh->verts, oldmesh->verts, newmesh->numverts * sizeof(float[4]));
memcpy(newmesh->elements, oldmesh->elements, newmesh->numtriangles * sizeof(int[3]));
memcpy(newmesh->neighbors, oldmesh->neighbors, newmesh->numtriangles * sizeof(int[3]));
int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, float *v)
{
- int j;
- float *m, temp[3];
- for (j = 0, m = mesh->verts;j < mesh->numverts;j++, m += 4)
+ int hashindex;
+ float *m;
+ shadowmeshvertexhash_t *hash;
+ // this uses prime numbers intentionally
+ hashindex = (int) (v[0] * 3 + v[1] * 5 + v[2] * 7) % SHADOWMESHVERTEXHASH;
+ for (hash = mesh->vertexhashtable[hashindex];hash;hash = hash->next)
{
- VectorSubtract(v, m, temp);
- if (DotProduct(temp, temp) < 0.1)
- return j;
+ m = mesh->verts + (hash - mesh->vertexhashentries) * 4;
+ if (m[0] == v[0] && m[1] == v[1] && m[2] == v[2])
+ return hash - mesh->vertexhashentries;
}
- mesh->numverts++;
+ hash = mesh->vertexhashentries + mesh->numverts;
+ hash->next = mesh->vertexhashtable[hashindex];
+ mesh->vertexhashtable[hashindex] = hash;
+ m = mesh->verts + (hash - mesh->vertexhashentries) * 4;
VectorCopy(v, m);
- return j;
+ mesh->numverts++;
+ return mesh->numverts - 1;
}
void Mod_ShadowMesh_AddTriangle(mempool_t *mempool, shadowmesh_t *mesh, float *vert0, float *vert1, float *vert2)
//Con_Printf("mesh\n");
//for (i = 0;i < newmesh->numtriangles;i++)
// Con_Printf("tri %d %d %d\n", newmesh->elements[i * 3 + 0], newmesh->elements[i * 3 + 1], newmesh->elements[i * 3 + 2]);
+ Mod_ValidateElements(newmesh->elements, newmesh->numtriangles, newmesh->numverts, __FILE__, __LINE__);
Mod_BuildTriangleNeighbors(newmesh->neighbors, newmesh->elements, newmesh->numtriangles);
}
Mem_Free(mesh);
#else
shadowmesh_t *mesh;
for (mesh = firstmesh;mesh;mesh = mesh->next)
+ {
+ Mod_ValidateElements(mesh->elements, mesh->numtriangles, mesh->numverts, __FILE__, __LINE__);
Mod_BuildTriangleNeighbors(mesh->neighbors, mesh->elements, mesh->numtriangles);
+ }
#endif
return firstmesh;
}
for (;mesh;mesh = nextmesh)
{
nextmesh = mesh->next;
-#if ALLOCMESHINPIECES
- Mem_Free(mesh->verts);
- Mem_Free(mesh->elements);
- Mem_Free(mesh->neighbors);
-#endif
Mem_Free(mesh);
}
}
cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "2"};
cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
cvar_t r_shadow_realtime = {0, "r_shadow_realtime", "0"};
-cvar_t r_shadow_erasebydrawing = {0, "r_shadow_erasebydrawing", "0"};
cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "0"};
cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"};
cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
cvar_t r_shadow_bumpscale = {0, "r_shadow_bumpscale", "4"};
+cvar_t r_shadow_shadownudge = {0, "r_shadow_shadownudge", "1"};
void R_Shadow_ClearWorldLights(void);
void R_Shadow_SaveWorldLights(void);
Cvar_RegisterVariable(&r_shadow_texture3d);
Cvar_RegisterVariable(&r_shadow_gloss);
Cvar_RegisterVariable(&r_shadow_debuglight);
- Cvar_RegisterVariable(&r_shadow_erasebydrawing);
Cvar_RegisterVariable(&r_shadow_scissor);
Cvar_RegisterVariable(&r_shadow_bumpscale);
+ Cvar_RegisterVariable(&r_shadow_shadownudge);
R_Shadow_EditLights_Init();
R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
}
-void R_Shadow_ProjectVertices(const float *in, float *out, int numverts, const float *relativelightorigin, float projectdistance)
+void R_Shadow_ProjectVertices(float *verts, int numverts, const float *relativelightorigin, float projectdistance)
{
int i;
+ float *in, *out, diff[4];
+ in = verts;
+ out = verts + numverts * 4;
for (i = 0;i < numverts;i++, in += 4, out += 4)
{
-#if 1
- out[0] = in[0] + 1000000.0f * (in[0] - relativelightorigin[0]);
- out[1] = in[1] + 1000000.0f * (in[1] - relativelightorigin[1]);
- out[2] = in[2] + 1000000.0f * (in[2] - relativelightorigin[2]);
-#elif 0
- VectorSubtract(in, relativelightorigin, temp);
- f = lightradius / sqrt(DotProduct(temp,temp));
- if (f < 1)
- f = 1;
- VectorMA(relativelightorigin, f, temp, out);
-#else
- VectorSubtract(in, relativelightorigin, temp);
- f = projectdistance / sqrt(DotProduct(temp,temp));
- VectorMA(in, f, temp, out);
-#endif
+ VectorSubtract(in, relativelightorigin, diff);
+ VectorNormalizeFast(diff);
+ VectorMA(in, projectdistance, diff, out);
+ VectorMA(in, r_shadow_shadownudge.value, diff, in);
}
}
if (maxshadowelements < numtris * 24)
R_Shadow_ResizeShadowElements(numtris);
+ // check which triangles are facing the light
+ R_Shadow_MakeTriangleShadowFlags(elements, varray_vertex, numtris, trianglefacinglight, relativelightorigin, lightradius);
+
// generate projected vertices
// by clever use of elements we'll construct the whole shadow from
// the unprojected vertices and these projected vertices
- R_Shadow_ProjectVertices(varray_vertex, varray_vertex + numverts * 4, numverts, relativelightorigin, projectdistance);
-
- // check which triangles are facing the light
- R_Shadow_MakeTriangleShadowFlags(elements, varray_vertex, numtris, trianglefacinglight, relativelightorigin, lightradius);
+ R_Shadow_ProjectVertices(varray_vertex, numverts, relativelightorigin, projectdistance);
// output triangle elements
tris = R_Shadow_BuildShadowVolumeTriangles(elements, neighbors, numtris, numverts, trianglefacinglight, shadowelements);
qglDepthFunc(GL_LESS);
qglEnable(GL_STENCIL_TEST);
qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- qglStencilFunc(GL_ALWAYS, 0, 0xFF);
+ qglStencilFunc(GL_ALWAYS, 128, 0xFF);
qglEnable(GL_CULL_FACE);
qglEnable(GL_DEPTH_TEST);
r_shadowstage = SHADOWSTAGE_STENCIL;
- if (!r_shadow_erasebydrawing.integer)
- qglClear(GL_STENCIL_BUFFER_BIT);
+ qglClear(GL_STENCIL_BUFFER_BIT);
}
void R_Shadow_Stage_Light(void)
qglEnable(GL_STENCIL_TEST);
qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
// only draw light where this geometry was already rendered AND the
- // stencil is 0 (non-zero means shadow)
- qglStencilFunc(GL_EQUAL, 0, 0xFF);
+ // stencil is 128 (values other than this mean shadow)
+ qglStencilFunc(GL_EQUAL, 128, 0xFF);
qglEnable(GL_CULL_FACE);
qglEnable(GL_DEPTH_TEST);
r_shadowstage = SHADOWSTAGE_LIGHT;
}
-int R_Shadow_Stage_EraseShadowVolumes(void)
-{
- if (r_shadow_erasebydrawing.integer)
- {
- rmeshstate_t m;
- memset(&m, 0, sizeof(m));
- R_Mesh_TextureState(&m);
- GL_Color(1, 1, 1, 1);
- qglColorMask(0, 0, 0, 0);
- qglDisable(GL_BLEND);
- qglDepthMask(0);
- qglDepthFunc(GL_LESS);
- qglEnable(GL_STENCIL_TEST);
- qglStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
- qglStencilFunc(GL_ALWAYS, 0, 0xFF);
- qglDisable(GL_CULL_FACE);
- qglDisable(GL_DEPTH_TEST);
- r_shadowstage = SHADOWSTAGE_ERASESTENCIL;
- return true;
- }
- else
- return false;
-}
-
void R_Shadow_Stage_End(void)
{
rmeshstate_t m;
qglDepthFunc(GL_LEQUAL);
qglDisable(GL_STENCIL_TEST);
qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- qglStencilFunc(GL_ALWAYS, 0, 0xFF);
+ qglStencilFunc(GL_ALWAYS, 128, 0xFF);
qglEnable(GL_CULL_FACE);
qglEnable(GL_DEPTH_TEST);
// force mesh state to reset by using various combinations of features
}
}
-#define PRECOMPUTEDSHADOWVOLUMES 1
void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light)
{
-#if PRECOMPUTEDSHADOWVOLUMES
R_Mesh_Matrix(matrix);
R_Shadow_RenderShadowMeshVolume(light->shadowvolume);
-#else
- shadowmesh_t *mesh;
- R_Mesh_Matrix(matrix);
- for (mesh = light->shadowvolume;mesh;mesh = mesh->next)
- {
- R_Mesh_ResizeCheck(mesh->numverts * 2);
- memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
- R_Shadow_Volume(mesh->numverts, mesh->numtriangles, varray_vertex, mesh->elements, mesh->neighbors, light->origin, light->lightradius, light->lightradius);
- }
-#endif
}
cvar_t r_editlights = {0, "r_editlights", "0"};
static int castshadowcount = 1;
void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style, const char *cubemapname)
{
- int i, j, k, l, maxverts, *mark;
- float *verts, *v, *v0, *v1, f, projectdistance, temp[3], temp2[3], temp3[3], radius2;
+ int i, j, k, l, maxverts, *mark, tris;
+ float *verts, *v, f, temp[3], radius2;
+ //float projectdistance, *v0, *v1, temp2[3], temp3[3];
worldlight_t *e;
- shadowmesh_t *mesh;
+ shadowmesh_t *mesh, *castmesh;
mleaf_t *leaf;
msurface_t *surf;
qbyte *pvs;
+ surfmesh_t *surfmesh;
e = Mem_Alloc(r_shadow_mempool, sizeof(worldlight_t));
VectorCopy(origin, e->origin);
f = -f;
if (f > 0 && f < e->lightradius)
{
- VectorSubtract(e->origin, surf->poly_center, temp);
- if (DotProduct(temp, temp) - surf->poly_radius2 < e->lightradius * e->lightradius)
+ temp[0] = bound(surf->poly_mins[0], e->origin[0], surf->poly_maxs[0]) - e->origin[0];
+ temp[1] = bound(surf->poly_mins[1], e->origin[1], surf->poly_maxs[1]) - e->origin[1];
+ temp[2] = bound(surf->poly_mins[2], e->origin[2], surf->poly_maxs[2]) - e->origin[2];
+ if (DotProduct(temp, temp) < e->lightradius * e->lightradius)
surf->castshadow = castshadowcount;
}
}
}
}
e->shadowvolume = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768);
-#if !PRECOMPUTEDSHADOWVOLUMES
- // make a mesh to cast a shadow volume from
- for (j = 0;j < e->numsurfaces;j++)
- if (e->surfaces[j]->castshadow == castshadowcount)
- Mod_ShadowMesh_AddPolygon(r_shadow_mempool, e->shadowvolume, e->surfaces[j]->poly_numverts, e->surfaces[j]->poly_verts);
-#else
-#if 1
- {
- int tris;
- shadowmesh_t *castmesh, *mesh;
- surfmesh_t *surfmesh;
// make a mesh to cast a shadow volume from
castmesh = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768);
for (j = 0;j < e->numsurfaces;j++)
// now that we have the buffers big enough, construct shadow volume mesh
memcpy(verts, castmesh->verts, castmesh->numverts * sizeof(float[4]));
- R_Shadow_ProjectVertices(verts, verts + castmesh->numverts * 4, castmesh->numverts, e->origin, e->lightradius);
+ R_Shadow_ProjectVertices(verts, castmesh->numverts, e->origin, 1000000.0f);//, e->lightradius);
R_Shadow_MakeTriangleShadowFlags(castmesh->elements, verts, castmesh->numtriangles, trianglefacinglight, e->origin, e->lightradius);
tris = R_Shadow_BuildShadowVolumeTriangles(castmesh->elements, castmesh->neighbors, castmesh->numtriangles, castmesh->numverts, trianglefacinglight, shadowelements);
// add the constructed shadow volume mesh
}
// we're done with castmesh now
Mod_ShadowMesh_Free(castmesh);
- }
-#else
- // make a shadow volume mesh
- if (verts == NULL && maxverts > 0)
- verts = Mem_Alloc(r_shadow_mempool, maxverts * sizeof(float[4]));
- for (j = 0;j < e->numsurfaces;j++)
- {
- surf = e->surfaces[j];
- if (surf->castshadow != castshadowcount)
- continue;
- projectdistance = 1000000.0f;//e->lightradius;
- // copy the original polygon, for the front cap of the volume
- for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
- VectorCopy(v0, v1);
- Mod_ShadowMesh_AddPolygon(r_shadow_mempool, e->shadowvolume, surf->poly_numverts, verts);
- // project the original polygon, reversed, for the back cap of the volume
- for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
- {
- VectorSubtract(v0, e->origin, temp);
- //VectorNormalize(temp);
- VectorMA(v0, projectdistance, temp, v1);
- }
- Mod_ShadowMesh_AddPolygon(r_shadow_mempool, e->shadowvolume, surf->poly_numverts, verts);
- // project the shadow volume sides
- for (l = surf->poly_numverts - 1, k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;l = k, k++, v0 = v1, v1 += 3)
- {
- if (surf->neighborsurfaces == NULL || surf->neighborsurfaces[l] == NULL || surf->neighborsurfaces[l]->castshadow != castshadowcount)
- {
- VectorCopy(v1, &verts[0]);
- VectorCopy(v0, &verts[3]);
- VectorCopy(v0, &verts[6]);
- VectorCopy(v1, &verts[9]);
- VectorSubtract(&verts[6], e->origin, temp);
- //VectorNormalize(temp);
- VectorMA(&verts[6], projectdistance, temp, &verts[6]);
- VectorSubtract(&verts[9], e->origin, temp);
- //VectorNormalize(temp);
- VectorMA(&verts[9], projectdistance, temp, &verts[9]);
-
-#if 0
- VectorSubtract(&verts[0], &verts[3], temp);
- VectorSubtract(&verts[6], &verts[3], temp2);
- CrossProduct(temp, temp2, temp3);
- VectorNormalize(temp3);
- if (DotProduct(surf->poly_center, temp3) > DotProduct(&verts[0], temp3))
- {
- VectorCopy(v0, &verts[0]);
- VectorCopy(v1, &verts[3]);
- VectorCopy(v1, &verts[6]);
- VectorCopy(v0, &verts[9]);
- VectorSubtract(&verts[6], e->origin, temp);
- //VectorNormalize(temp);
- VectorMA(&verts[6], projectdistance, temp, &verts[6]);
- VectorSubtract(&verts[9], e->origin, temp);
- //VectorNormalize(temp);
- VectorMA(&verts[9], projectdistance, temp, &verts[9]);
- Con_Printf("flipped shadow volume edge %8p %i\n", surf, l);
- }
-#endif
-
- Mod_ShadowMesh_AddPolygon(r_shadow_mempool, e->shadowvolume, 4, verts);
- }
- }
- }
-#endif
-#endif
e->shadowvolume = Mod_ShadowMesh_Finish(r_shadow_mempool, e->shadowvolume);
for (l = 0, mesh = e->shadowvolume;mesh;mesh = mesh->next)
l += mesh->numtriangles;
void R_Shadow_SelectLightInView(void)
{
- float bestrating, rating, temp[3], dist;
+ float bestrating, temp[3], dist;
worldlight_t *best, *light;
best = NULL;
bestrating = 1e30;
void R_Shadow_LoadLightsFile(void)
{
int n, a, style;
- char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
+ char name[MAX_QPATH], *lightsstring, *s, *t;
float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
COM_StripExtension(cl.worldmodel->name, name);
strcat(name, ".lights");