From bdbd009f72846eafb32d1efe43c521c22ca65fda Mon Sep 17 00:00:00 2001 From: havoc Date: Tue, 2 Mar 2004 20:29:58 +0000 Subject: [PATCH] temporarily disabled compiled rtlights (they'll make a comeback after dynamic rtlight optimizations are finished) dynamic rtlight shadow volumes for bmodels are now generated from a single mesh for the entire model, in which only some ranges of triangles are marked, this finally cured the performance problems with dlight s git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3956 d7cf8633-e32d-0410-b094-e92efae38249 --- gl_models.c | 4 +- gl_rsurf.c | 85 ++++++++- model_brush.c | 30 +++- model_brush.h | 3 + model_shared.h | 6 + r_shadow.c | 473 ++++++++++++++++++------------------------------- r_shadow.h | 14 +- todo | 8 +- 8 files changed, 309 insertions(+), 314 deletions(-) diff --git a/gl_models.c b/gl_models.c index ca8bdb7d..d829e9ff 100644 --- a/gl_models.c +++ b/gl_models.c @@ -308,7 +308,7 @@ void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightor float projectdistance; if (ent->effects & EF_ADDITIVE || ent->alpha < 1) return; - projectdistance = lightradius + ent->model->radius - sqrt(DotProduct(relativelightorigin, relativelightorigin)); + projectdistance = lightradius + ent->model->radius;// - sqrt(DotProduct(relativelightorigin, relativelightorigin)); if (projectdistance > 0.1) { R_Mesh_Matrix(&ent->matrix); @@ -318,7 +318,7 @@ void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightor if (skin->flags & ALIASSKIN_TRANSPARENT) continue; R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_VERTEX, varray_vertex3f); - R_Shadow_Volume(mesh->num_vertices, mesh->num_triangles, varray_vertex3f, mesh->data_element3i, mesh->data_neighbor3i, relativelightorigin, lightradius, projectdistance); + R_Shadow_VolumeFromSphere(mesh->num_vertices, mesh->num_triangles, varray_vertex3f, mesh->data_element3i, mesh->data_neighbor3i, relativelightorigin, projectdistance, lightradius); } } } diff --git a/gl_rsurf.c b/gl_rsurf.c index 8b0fd081..5fdbd9c7 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -1822,6 +1822,7 @@ void R_Model_Brush_Draw(entity_render_t *ent) void R_Model_Brush_DrawShadowVolume (entity_render_t *ent, vec3_t relativelightorigin, float lightradius) { +#if 0 int i; msurface_t *surf; float projectdistance, f, temp[3], lightradius2; @@ -1830,7 +1831,8 @@ void R_Model_Brush_DrawShadowVolume (entity_render_t *ent, vec3_t relativelighto R_Mesh_Matrix(&ent->matrix); lightradius2 = lightradius * lightradius; R_UpdateTextureInfo(ent); - projectdistance = 1000000000.0f;//lightradius + ent->model->radius; + projectdistance = lightradius + ent->model->radius;//projectdistance = 1000000000.0f;//lightradius + ent->model->radius; + //projectdistance = 1000000000.0f;//lightradius + ent->model->radius; for (i = 0, surf = ent->model->brushq1.surfaces + ent->model->brushq1.firstmodelsurface;i < ent->model->brushq1.nummodelsurfaces;i++, surf++) { if (surf->texinfo->texture->rendertype == SURFRENDER_OPAQUE && surf->flags & SURF_SHADOWCAST) @@ -1845,10 +1847,46 @@ void R_Model_Brush_DrawShadowVolume (entity_render_t *ent, vec3_t relativelighto temp[1] = bound(surf->poly_mins[1], relativelightorigin[1], surf->poly_maxs[1]) - relativelightorigin[1]; temp[2] = bound(surf->poly_mins[2], relativelightorigin[2], surf->poly_maxs[2]) - relativelightorigin[2]; if (DotProduct(temp, temp) < lightradius2) - R_Shadow_Volume(surf->mesh.num_vertices, surf->mesh.num_triangles, surf->mesh.data_vertex3f, surf->mesh.data_element3i, surf->mesh.data_neighbor3i, relativelightorigin, lightradius, projectdistance); + R_Shadow_VolumeFromSphere(surf->mesh.num_vertices, surf->mesh.num_triangles, surf->mesh.data_vertex3f, surf->mesh.data_element3i, surf->mesh.data_neighbor3i, relativelightorigin, projectdistance, lightradius); } } } +#else + int i, j, t; + const int *e; + msurface_t *surf; + float projectdistance; + const float *v[3]; + vec3_t lightmins, lightmaxs; + if (ent->model == NULL) + return; + R_Mesh_Matrix(&ent->matrix); + R_UpdateTextureInfo(ent); + projectdistance = lightradius + ent->model->radius;//projectdistance = 1000000000.0f;//lightradius + ent->model->radius; + //projectdistance = 1000000000.0f;//lightradius + ent->model->radius; + lightmins[0] = relativelightorigin[0] - lightradius; + lightmins[1] = relativelightorigin[1] - lightradius; + lightmins[2] = relativelightorigin[2] - lightradius; + lightmaxs[0] = relativelightorigin[0] + lightradius; + lightmaxs[1] = relativelightorigin[1] + lightradius; + lightmaxs[2] = relativelightorigin[2] + lightradius; + R_Shadow_PrepareShadowMark(ent->model->brush.shadowmesh->numtriangles); + for (i = 0, surf = ent->model->brushq1.surfaces + ent->model->brushq1.firstmodelsurface;i < ent->model->brushq1.nummodelsurfaces;i++, surf++) + { + if (BoxesOverlap(lightmins, lightmaxs, surf->poly_mins, surf->poly_maxs) && surf->texinfo->texture->rendertype == SURFRENDER_OPAQUE && (surf->flags & SURF_SHADOWCAST)) + { + for (j = 0, t = surf->num_firstshadowmeshtriangle, e = ent->model->brush.shadowmesh->element3i + t * 3;j < surf->mesh.num_triangles;j++, t++, e += 3) + { + v[0] = ent->model->brush.shadowmesh->vertex3f + e[0] * 3; + v[1] = ent->model->brush.shadowmesh->vertex3f + e[1] * 3; + v[2] = ent->model->brush.shadowmesh->vertex3f + e[2] * 3; + if (PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2]) && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2]))) + shadowmarklist[numshadowmark++] = t; + } + } + } + R_Shadow_VolumeFromList(ent->model->brush.shadowmesh->numverts, ent->model->brush.shadowmesh->numtriangles, ent->model->brush.shadowmesh->vertex3f, ent->model->brush.shadowmesh->element3i, ent->model->brush.shadowmesh->neighbor3i, relativelightorigin, projectdistance, numshadowmark, shadowmarklist); +#endif } void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap) @@ -2369,12 +2407,13 @@ void R_Q3BSP_Draw(entity_render_t *ent) void R_Q3BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius) { +#if 0 int i; q3mface_t *face; vec3_t modelorg, lightmins, lightmaxs; model_t *model; float projectdistance; - projectdistance = 1000000000.0f;//lightradius + ent->model->radius; + projectdistance = lightradius + ent->model->radius;//projectdistance = 1000000000.0f;//lightradius + ent->model->radius; if (r_drawcollisionbrushes.integer < 2) { model = ent->model; @@ -2391,8 +2430,46 @@ void R_Q3BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, //else for (i = 0, face = model->brushq3.data_thismodel->firstface;i < model->brushq3.data_thismodel->numfaces;i++, face++) if (BoxesOverlap(lightmins, lightmaxs, face->mins, face->maxs)) - R_Shadow_Volume(face->num_vertices, face->num_triangles, face->data_vertex3f, face->data_element3i, face->data_neighbor3i, relativelightorigin, lightradius, projectdistance); + R_Shadow_VolumeFromSphere(face->num_vertices, face->num_triangles, face->data_vertex3f, face->data_element3i, face->data_neighbor3i, relativelightorigin, projectdistance, lightradius); } +#else + int i, j, t; + const int *e; + q3mface_t *face; + vec3_t modelorg, lightmins, lightmaxs; + model_t *model; + float projectdistance; + projectdistance = lightradius + ent->model->radius;//projectdistance = 1000000000.0f;//lightradius + ent->model->radius; + if (r_drawcollisionbrushes.integer < 2) + { + model = ent->model; + R_Mesh_Matrix(&ent->matrix); + Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg); + lightmins[0] = relativelightorigin[0] - lightradius; + lightmins[1] = relativelightorigin[1] - lightradius; + lightmins[2] = relativelightorigin[2] - lightradius; + lightmaxs[0] = relativelightorigin[0] + lightradius; + lightmaxs[1] = relativelightorigin[1] + lightradius; + lightmaxs[2] = relativelightorigin[2] + lightradius; + R_Shadow_PrepareShadowMark(model->brush.shadowmesh->numtriangles); + for (i = 0, face = model->brushq3.data_thismodel->firstface;i < model->brushq3.data_thismodel->numfaces;i++, face++) + { + if (BoxesOverlap(lightmins, lightmaxs, face->mins, face->maxs)) + { + for (j = 0, t = face->num_firstshadowmeshtriangle, e = model->brush.shadowmesh->element3i + t * 3;j < face->num_triangles;j++, t++, e += 3) + { + const float *v[3]; + v[0] = model->brush.shadowmesh->vertex3f + e[0] * 3; + v[1] = model->brush.shadowmesh->vertex3f + e[1] * 3; + v[2] = model->brush.shadowmesh->vertex3f + e[2] * 3; + if (PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2]) && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2]))) + shadowmarklist[numshadowmark++] = t; + } + } + } + R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, projectdistance, numshadowmark, shadowmarklist); + } +#endif } void R_Q3BSP_DrawFaceLight(entity_render_t *ent, q3mface_t *face, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap) diff --git a/model_brush.c b/model_brush.c index 0b7bd5ca..e9bcca80 100644 --- a/model_brush.c +++ b/model_brush.c @@ -2828,6 +2828,7 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer) model_t *originalloadmodel; float dist, modelyawradius, modelradius, *vec; msurface_t *surf; + int numshadowmeshtriangles; mod->type = mod_brush; @@ -2903,6 +2904,19 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer) Mod_Q1BSP_LoadLightList(); originalloadmodel = loadmodel; + // make a single combined shadow mesh to allow optimized shadow volume creation + numshadowmeshtriangles = 0; + for (j = 0, surf = loadmodel->brushq1.surfaces;j < loadmodel->brushq1.numsurfaces;j++, surf++) + { + surf->num_firstshadowmeshtriangle = numshadowmeshtriangles; + numshadowmeshtriangles += surf->mesh.num_triangles; + } + loadmodel->brush.shadowmesh = Mod_ShadowMesh_Begin(loadmodel->mempool, numshadowmeshtriangles * 3, numshadowmeshtriangles, NULL, NULL, NULL, false, false, true); + for (j = 0, surf = loadmodel->brushq1.surfaces;j < loadmodel->brushq1.numsurfaces;j++, surf++) + Mod_ShadowMesh_AddMesh(loadmodel->mempool, loadmodel->brush.shadowmesh, NULL, NULL, NULL, surf->mesh.data_vertex3f, NULL, NULL, NULL, NULL, surf->mesh.num_triangles, surf->mesh.data_element3i); + loadmodel->brush.shadowmesh = Mod_ShadowMesh_Finish(loadmodel->mempool, loadmodel->brush.shadowmesh, false, true); + Mod_BuildTriangleNeighbors(loadmodel->brush.shadowmesh->neighbor3i, loadmodel->brush.shadowmesh->element3i, loadmodel->brush.shadowmesh->numtriangles); + // // set up the submodels(FIXME: this is confusing) // @@ -5293,9 +5307,10 @@ extern void R_Q3BSP_DrawShadowVolume(struct entity_render_s *ent, vec3_t relativ extern void R_Q3BSP_DrawLight(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap); void Mod_Q3BSP_Load(model_t *mod, void *buffer) { - int i, j; + int i, j, numshadowmeshtriangles; q3dheader_t *header; float corner[3], yawradius, modelradius; + q3mface_t *face; mod->type = mod_brushq3; mod->numframes = 1; @@ -5352,6 +5367,19 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer) Mod_Q3BSP_LoadPVS(&header->lumps[Q3LUMP_PVS]); loadmodel->brush.numsubmodels = loadmodel->brushq3.num_models; + // make a single combined shadow mesh to allow optimized shadow volume creation + numshadowmeshtriangles = 0; + for (j = 0, face = loadmodel->brushq3.data_faces;j < loadmodel->brushq3.num_faces;j++, face++) + { + face->num_firstshadowmeshtriangle = numshadowmeshtriangles; + numshadowmeshtriangles += face->num_triangles; + } + loadmodel->brush.shadowmesh = Mod_ShadowMesh_Begin(loadmodel->mempool, numshadowmeshtriangles * 3, numshadowmeshtriangles, NULL, NULL, NULL, false, false, true); + for (j = 0, face = loadmodel->brushq3.data_faces;j < loadmodel->brushq3.num_faces;j++, face++) + Mod_ShadowMesh_AddMesh(loadmodel->mempool, loadmodel->brush.shadowmesh, NULL, NULL, NULL, face->data_vertex3f, NULL, NULL, NULL, NULL, face->num_triangles, face->data_element3i); + loadmodel->brush.shadowmesh = Mod_ShadowMesh_Finish(loadmodel->mempool, loadmodel->brush.shadowmesh, false, true); + Mod_BuildTriangleNeighbors(loadmodel->brush.shadowmesh->neighbor3i, loadmodel->brush.shadowmesh->element3i, loadmodel->brush.shadowmesh->numtriangles); + for (i = 0;i < loadmodel->brushq3.num_models;i++) { if (i == 0) diff --git a/model_brush.h b/model_brush.h index f812fdb8..b4f76ac0 100644 --- a/model_brush.h +++ b/model_brush.h @@ -220,6 +220,9 @@ typedef struct msurface_s int poly_numverts; float *poly_verts; + // index into model->brush.shadowmesh + int num_firstshadowmeshtriangle; + // neighboring surfaces (one per poly_numverts) //struct msurface_s **neighborsurfaces; // currently used only for generating static shadow volumes diff --git a/model_shared.h b/model_shared.h index 1cd9d5ba..b16ee206 100644 --- a/model_shared.h +++ b/model_shared.h @@ -175,6 +175,9 @@ typedef struct model_brush_s //pvschain = model->brush.data_pvsclusters + mycluster * model->brush.num_pvsclusterbytes; //if (pvschain[thatcluster >> 3] & (1 << (thatcluster & 7))) + // a mesh containing all shadow casting geometry for the whole model (including submodels), portions of this are referenced by each surface's num_firstshadowmeshtriangle + shadowmesh_t *shadowmesh; + // common functions int (*SuperContentsFromNativeContents)(struct model_s *model, int nativecontents); int (*NativeContentsFromSuperContents)(struct model_s *model, int supercontents); @@ -445,6 +448,9 @@ typedef struct q3mface_s int *data_element3i; int *data_neighbor3i; + // index into model->brush.shadowmesh + int num_firstshadowmeshtriangle; + // temporary use by light processing int lighttemp_castshadow; } diff --git a/r_shadow.c b/r_shadow.c index c1f41eee..a9440ac8 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -131,9 +131,12 @@ mempool_t *r_shadow_mempool; int maxshadowelements; int *shadowelements; -int maxtrianglefacinglight; -qbyte *trianglefacinglight; -int *trianglefacinglightlist; + +int maxshadowmark; +int numshadowmark; +int *shadowmark; +int *shadowmarklist; +int shadowmarkcount; int maxvertexupdate; int *vertexupdate; @@ -197,9 +200,11 @@ void r_shadow_start(void) vertexupdate = NULL; vertexremap = NULL; vertexupdatenum = 0; - maxtrianglefacinglight = 0; - trianglefacinglight = NULL; - trianglefacinglightlist = NULL; + maxshadowmark = 0; + numshadowmark = 0; + shadowmark = NULL; + shadowmarklist = NULL; + shadowmarkcount = 0; r_shadow_normalcubetexture = NULL; r_shadow_attenuation2dtexture = NULL; r_shadow_attenuation3dtexture = NULL; @@ -230,9 +235,11 @@ void r_shadow_shutdown(void) vertexupdate = NULL; vertexremap = NULL; vertexupdatenum = 0; - maxtrianglefacinglight = 0; - trianglefacinglight = NULL; - trianglefacinglightlist = NULL; + maxshadowmark = 0; + numshadowmark = 0; + shadowmark = NULL; + shadowmarklist = NULL; + shadowmarkcount = 0; Mem_FreePool(&r_shadow_mempool); } @@ -331,23 +338,6 @@ matrix4x4_t matrix_attenuationz = } }; -void R_Shadow_ResizeTriangleFacingLight(int numtris) -{ - // make sure trianglefacinglight is big enough for this volume - // ameks ru ertaignelaficgnilhg tsib gie ongu hof rhtsiv lomu e - // m4k3 5ur3 7r14ng13f4c1n5115h7 15 b15 3n0u5h f0r 7h15 v01um3 - if (maxtrianglefacinglight < numtris) - { - maxtrianglefacinglight = numtris; - if (trianglefacinglight) - Mem_Free(trianglefacinglight); - if (trianglefacinglightlist) - Mem_Free(trianglefacinglightlist); - trianglefacinglight = Mem_Alloc(r_shadow_mempool, maxtrianglefacinglight); - trianglefacinglightlist = Mem_Alloc(r_shadow_mempool, sizeof(int) * maxtrianglefacinglight); - } -} - int *R_Shadow_ResizeShadowElements(int numtris) { // make sure shadowelements is big enough for this volume @@ -361,68 +351,36 @@ int *R_Shadow_ResizeShadowElements(int numtris) return shadowelements; } -/* -// readable version of some code found below -//if ((t >= trianglerange_start && t < trianglerange_end) ? (t < i && !trianglefacinglight[t]) : (t < 0 || (te = inelement3i + t * 3, v[0] = invertex3f + te[0] * 3, v[1] = invertex3f + te[1] * 3, v[2] = invertex3f + te[2] * 3, !PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2])))) -int PointInfrontOfTriangle(const float *p, const float *a, const float *b, const float *c) -{ - float dir0[3], dir1[3], normal[3]; - - // calculate two mostly perpendicular edge directions - VectorSubtract(a, b, dir0); - VectorSubtract(c, b, dir1); - - // we have two edge directions, we can calculate a third vector from - // them, which is the direction of the surface normal (it's magnitude - // is not 1 however) - CrossProduct(dir0, dir1, normal); - - // compare distance of light along normal, with distance of any point - // of the triangle along the same normal (the triangle is planar, - // I.E. flat, so all points give the same answer) - return DotProduct(p, normal) > DotProduct(a, normal); -} -int checkcastshadowfromedge(int t, int i) +void R_Shadow_PrepareShadowMark(int numtris) { - int *te; - float *v[3]; - if (t >= trianglerange_start && t < trianglerange_end) + // make sure shadowmark is big enough for this volume + if (maxshadowmark < numtris) { - if (t < i && !trianglefacinglight[t]) - return true; - else - return false; + maxshadowmark = numtris; + if (shadowmark) + Mem_Free(shadowmark); + if (shadowmarklist) + Mem_Free(shadowmarklist); + shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark)); + shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist)); + shadowmarkcount = 0; } - else + shadowmarkcount++; + // if shadowmarkcount wrapped we clear the array and adjust accordingly + if (shadowmarkcount == 0) { - if (t < 0) - return true; - else - { - te = inelement3i + t * 3; - v[0] = invertex3f + te[0] * 3; - v[1] = invertex3f + te[1] * 3; - v[2] = invertex3f + te[2] * 3; - if (!PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2])))) - return true; - else - return false; - } + shadowmarkcount = 1; + memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark)); } + numshadowmark = 0; } -*/ -int R_Shadow_ConstructShadowVolume(int innumvertices, int trianglerange_start, int trianglerange_end, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *relativelightorigin, float projectdistance) +int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, float projectdistance, int numshadowmarktris, const int *shadowmarktris) { - int i, j, tris = 0, numfacing = 0, vr[3], t, outvertices = 0; - const float *v[3]; - const int *e, *n, *te; + int i, j, tris = 0, vr[3], t, outvertices = 0; + const int *e, *n; float f, temp[3]; - // make sure trianglefacinglight is big enough for this volume - if (maxtrianglefacinglight < trianglerange_end) - R_Shadow_ResizeTriangleFacingLight(trianglerange_end); - if (maxvertexupdate < innumvertices) { maxvertexupdate = innumvertices; @@ -432,220 +390,91 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int trianglerange_start, i Mem_Free(vertexremap); vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int)); vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int)); + vertexupdatenum = 0; } vertexupdatenum++; - - if (r_shadow_singlepassvolumegeneration.integer) + if (vertexupdatenum == 0) { - // one pass approach (identify lit/dark faces and generate sides while doing so) - for (i = trianglerange_start, e = inelement3i + i * 3, n = inneighbor3i + i * 3;i < trianglerange_end;i++, e += 3, n += 3) - { - // calculate triangle facing flag - v[0] = invertex3f + e[0] * 3; - v[1] = invertex3f + e[1] * 3; - v[2] = invertex3f + e[2] * 3; - if((trianglefacinglight[i] = PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2]))) - { - // make sure the vertices are created - for (j = 0;j < 3;j++) - { - if (vertexupdate[e[j]] != vertexupdatenum) - { - vertexupdate[e[j]] = vertexupdatenum; - vertexremap[e[j]] = outvertices; - VectorCopy(v[j], outvertex3f); - VectorSubtract(v[j], relativelightorigin, temp); - f = projectdistance / VectorLength(temp); - VectorMA(relativelightorigin, f, temp, (outvertex3f + 3)); - outvertex3f += 6; - outvertices += 2; - } - } - // output the front and back triangles - vr[0] = vertexremap[e[0]]; - vr[1] = vertexremap[e[1]]; - vr[2] = vertexremap[e[2]]; - outelement3i[0] = vr[0]; - outelement3i[1] = vr[1]; - outelement3i[2] = vr[2]; - outelement3i[3] = vr[2] + 1; - outelement3i[4] = vr[1] + 1; - outelement3i[5] = vr[0] + 1; - outelement3i += 6; - tris += 2; - // output the sides (facing outward from this triangle) - t = n[0]; - if ((t >= trianglerange_start && t < trianglerange_end) ? (t < i && !trianglefacinglight[t]) : (t < 0 || (te = inelement3i + t * 3, v[0] = invertex3f + te[0] * 3, v[1] = invertex3f + te[1] * 3, v[2] = invertex3f + te[2] * 3, !PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2])))) - { - outelement3i[0] = vr[1]; - outelement3i[1] = vr[0]; - outelement3i[2] = vr[0] + 1; - outelement3i[3] = vr[1]; - outelement3i[4] = vr[0] + 1; - outelement3i[5] = vr[1] + 1; - outelement3i += 6; - tris += 2; - } - t = n[1]; - if ((t >= trianglerange_start && t < trianglerange_end) ? (t < i && !trianglefacinglight[t]) : (t < 0 || (te = inelement3i + t * 3, v[0] = invertex3f + te[0] * 3, v[1] = invertex3f + te[1] * 3, v[2] = invertex3f + te[2] * 3, !PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2])))) - { - outelement3i[0] = vr[2]; - outelement3i[1] = vr[1]; - outelement3i[2] = vr[1] + 1; - outelement3i[3] = vr[2]; - outelement3i[4] = vr[1] + 1; - outelement3i[5] = vr[2] + 1; - outelement3i += 6; - tris += 2; - } - t = n[2]; - if ((t >= trianglerange_start && t < trianglerange_end) ? (t < i && !trianglefacinglight[t]) : (t < 0 || (te = inelement3i + t * 3, v[0] = invertex3f + te[0] * 3, v[1] = invertex3f + te[1] * 3, v[2] = invertex3f + te[2] * 3, !PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2])))) - { - outelement3i[0] = vr[0]; - outelement3i[1] = vr[2]; - outelement3i[2] = vr[2] + 1; - outelement3i[3] = vr[0]; - outelement3i[4] = vr[2] + 1; - outelement3i[5] = vr[0] + 1; - outelement3i += 6; - tris += 2; - } - } - else - { - // this triangle is not facing the light - // output the sides (facing inward to this triangle) - t = n[0]; - if (t < i && t >= trianglerange_start && t < trianglerange_end && trianglefacinglight[t]) - { - vr[0] = vertexremap[e[0]]; - vr[1] = vertexremap[e[1]]; - outelement3i[0] = vr[1]; - outelement3i[1] = vr[0] + 1; - outelement3i[2] = vr[0]; - outelement3i[3] = vr[1]; - outelement3i[4] = vr[1] + 1; - outelement3i[5] = vr[0] + 1; - outelement3i += 6; - tris += 2; - } - t = n[1]; - if (t < i && t >= trianglerange_start && t < trianglerange_end && trianglefacinglight[t]) - { - vr[1] = vertexremap[e[1]]; - vr[2] = vertexremap[e[2]]; - outelement3i[0] = vr[2]; - outelement3i[1] = vr[1] + 1; - outelement3i[2] = vr[1]; - outelement3i[3] = vr[2]; - outelement3i[4] = vr[2] + 1; - outelement3i[5] = vr[1] + 1; - outelement3i += 6; - tris += 2; - } - t = n[2]; - if (t < i && t >= trianglerange_start && t < trianglerange_end && trianglefacinglight[t]) - { - vr[0] = vertexremap[e[0]]; - vr[2] = vertexremap[e[2]]; - outelement3i[0] = vr[0]; - outelement3i[1] = vr[2] + 1; - outelement3i[2] = vr[2]; - outelement3i[3] = vr[0]; - outelement3i[4] = vr[0] + 1; - outelement3i[5] = vr[2] + 1; - outelement3i += 6; - tris += 2; - } - } - } + vertexupdatenum = 1; + memset(vertexupdate, 0, maxvertexupdate * sizeof(int)); + memset(vertexremap, 0, maxvertexupdate * sizeof(int)); } - else + + for (i = 0;i < numshadowmarktris;i++) { - // two pass approach (identify lit/dark faces and then generate sides) - for (i = trianglerange_start, e = inelement3i + i * 3, numfacing = 0;i < trianglerange_end;i++, e += 3) + t = shadowmarktris[i]; + shadowmark[t] = shadowmarkcount; + e = inelement3i + t * 3; + // make sure the vertices are created + for (j = 0;j < 3;j++) { - // calculate triangle facing flag - v[0] = invertex3f + e[0] * 3; - v[1] = invertex3f + e[1] * 3; - v[2] = invertex3f + e[2] * 3; - if((trianglefacinglight[i] = PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2]))) + if (vertexupdate[e[j]] != vertexupdatenum) { - trianglefacinglightlist[numfacing++] = i; - // make sure the vertices are created - for (j = 0;j < 3;j++) - { - if (vertexupdate[e[j]] != vertexupdatenum) - { - vertexupdate[e[j]] = vertexupdatenum; - vertexremap[e[j]] = outvertices; - VectorSubtract(v[j], relativelightorigin, temp); - f = projectdistance / VectorLength(temp); - VectorCopy(v[j], outvertex3f); - VectorMA(relativelightorigin, f, temp, (outvertex3f + 3)); - outvertex3f += 6; - outvertices += 2; - } - } - // output the front and back triangles - outelement3i[0] = vertexremap[e[0]]; - outelement3i[1] = vertexremap[e[1]]; - outelement3i[2] = vertexremap[e[2]]; - outelement3i[3] = vertexremap[e[2]] + 1; - outelement3i[4] = vertexremap[e[1]] + 1; - outelement3i[5] = vertexremap[e[0]] + 1; - outelement3i += 6; - tris += 2; + vertexupdate[e[j]] = vertexupdatenum; + vertexremap[e[j]] = outvertices; + VectorSubtract(invertex3f + e[j] * 3, projectorigin, temp); + f = projectdistance / VectorLength(temp); + VectorCopy(invertex3f + e[j] * 3, outvertex3f); + VectorMA(projectorigin, f, temp, (outvertex3f + 3)); + outvertex3f += 6; + outvertices += 2; } } - for (i = 0;i < numfacing;i++) - { - t = trianglefacinglightlist[i]; - e = inelement3i + t * 3; - n = inneighbor3i + t * 3; - // output the sides (facing outward from this triangle) - t = n[0]; - if ((t >= trianglerange_start && t < trianglerange_end) ? (!trianglefacinglight[t]) : (t < 0 || (te = inelement3i + t * 3, v[0] = invertex3f + te[0] * 3, v[1] = invertex3f + te[1] * 3, v[2] = invertex3f + te[2] * 3, !PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2])))) - { - vr[0] = vertexremap[e[0]]; - vr[1] = vertexremap[e[1]]; - outelement3i[0] = vr[1]; - outelement3i[1] = vr[0]; - outelement3i[2] = vr[0] + 1; - outelement3i[3] = vr[1]; - outelement3i[4] = vr[0] + 1; - outelement3i[5] = vr[1] + 1; - outelement3i += 6; - tris += 2; - } - t = n[1]; - if ((t >= trianglerange_start && t < trianglerange_end) ? (!trianglefacinglight[t]) : (t < 0 || (te = inelement3i + t * 3, v[0] = invertex3f + te[0] * 3, v[1] = invertex3f + te[1] * 3, v[2] = invertex3f + te[2] * 3, !PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2])))) - { - vr[1] = vertexremap[e[1]]; - vr[2] = vertexremap[e[2]]; - outelement3i[0] = vr[2]; - outelement3i[1] = vr[1]; - outelement3i[2] = vr[1] + 1; - outelement3i[3] = vr[2]; - outelement3i[4] = vr[1] + 1; - outelement3i[5] = vr[2] + 1; - outelement3i += 6; - tris += 2; - } - t = n[2]; - if ((t >= trianglerange_start && t < trianglerange_end) ? (!trianglefacinglight[t]) : (t < 0 || (te = inelement3i + t * 3, v[0] = invertex3f + te[0] * 3, v[1] = invertex3f + te[1] * 3, v[2] = invertex3f + te[2] * 3, !PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2])))) - { - vr[0] = vertexremap[e[0]]; - vr[2] = vertexremap[e[2]]; - outelement3i[0] = vr[0]; - outelement3i[1] = vr[2]; - outelement3i[2] = vr[2] + 1; - outelement3i[3] = vr[0]; - outelement3i[4] = vr[2] + 1; - outelement3i[5] = vr[0] + 1; - outelement3i += 6; - tris += 2; - } + // output the front and back triangles + outelement3i[0] = vertexremap[e[0]]; + outelement3i[1] = vertexremap[e[1]]; + outelement3i[2] = vertexremap[e[2]]; + outelement3i[3] = vertexremap[e[2]] + 1; + outelement3i[4] = vertexremap[e[1]] + 1; + outelement3i[5] = vertexremap[e[0]] + 1; + outelement3i += 6; + tris += 2; + } + + for (i = 0;i < numshadowmarktris;i++) + { + t = shadowmarktris[i]; + e = inelement3i + t * 3; + n = inneighbor3i + t * 3; + // output the sides (facing outward from this triangle) + if (shadowmark[n[0]] != shadowmarkcount) + { + vr[0] = vertexremap[e[0]]; + vr[1] = vertexremap[e[1]]; + outelement3i[0] = vr[1]; + outelement3i[1] = vr[0]; + outelement3i[2] = vr[0] + 1; + outelement3i[3] = vr[1]; + outelement3i[4] = vr[0] + 1; + outelement3i[5] = vr[1] + 1; + outelement3i += 6; + tris += 2; + } + if (shadowmark[n[1]] != shadowmarkcount) + { + vr[1] = vertexremap[e[1]]; + vr[2] = vertexremap[e[2]]; + outelement3i[0] = vr[2]; + outelement3i[1] = vr[1]; + outelement3i[2] = vr[1] + 1; + outelement3i[3] = vr[2]; + outelement3i[4] = vr[1] + 1; + outelement3i[5] = vr[2] + 1; + outelement3i += 6; + tris += 2; + } + if (shadowmark[n[2]] != shadowmarkcount) + { + vr[0] = vertexremap[e[0]]; + vr[2] = vertexremap[e[2]]; + outelement3i[0] = vr[0]; + outelement3i[1] = vr[2]; + outelement3i[2] = vr[2] + 1; + outelement3i[3] = vr[0]; + outelement3i[4] = vr[2] + 1; + outelement3i[5] = vr[0] + 1; + outelement3i += 6; + tris += 2; } } if (outnumvertices) @@ -655,7 +484,7 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int trianglerange_start, i float varray_vertex3f2[65536*3]; -void R_Shadow_Volume(int numverts, int numtris, const float *invertex3f, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance) +void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, int nummarktris, const int *marktris) { int tris, outverts; if (projectdistance < 0.1) @@ -663,36 +492,68 @@ void R_Shadow_Volume(int numverts, int numtris, const float *invertex3f, int *el Con_Printf("R_Shadow_Volume: projectdistance %f\n"); return; } - if (!numverts) + if (!numverts || !nummarktris) return; - // make sure shadowelements is big enough for this volume - if (maxshadowelements < numtris * 24) - R_Shadow_ResizeShadowElements(numtris); + if (maxshadowelements < nummarktris * 24) + R_Shadow_ResizeShadowElements((nummarktris + 256) * 24); + tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris); + R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements); +} - // check which triangles are facing the light, and then output +void R_Shadow_VolumeFromBox(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, const vec3_t mins, const vec3_t maxs) +{ + int i; + const float *v[3]; + + // check which triangles are facing the , and then output // triangle elements and vertices... by clever use of elements we // can construct the whole shadow from the unprojected vertices and // the projected vertices - if ((tris = R_Shadow_ConstructShadowVolume(numverts, 0, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, relativelightorigin, r_shadow_projectdistance.value/*projectdistance*/))) + + // identify lit faces within the bounding box + R_Shadow_PrepareShadowMark(numtris); + for (i = 0;i < numtris;i++) { - GL_VertexPointer(varray_vertex3f2); - if (r_shadowstage == SHADOWSTAGE_STENCIL) - { - // decrement stencil if frontface is behind depthbuffer - qglCullFace(GL_FRONT); // quake is backwards, this culls back faces - qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP); - R_Mesh_Draw(outverts, tris, shadowelements); - c_rt_shadowmeshes++; - c_rt_shadowtris += numtris; - // increment stencil if backface is behind depthbuffer - qglCullFace(GL_BACK); // quake is backwards, this culls front faces - qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP); - } - R_Mesh_Draw(outverts, tris, shadowelements); + v[0] = invertex3f + elements[i*3+0] * 3; + v[1] = invertex3f + elements[i*3+1] * 3; + v[2] = invertex3f + elements[i*3+2] * 3; + if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]) && maxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && mins[0] < max(v[0][0], max(v[1][0], v[2][0])) && maxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && mins[1] < max(v[0][1], max(v[1][1], v[2][1])) && maxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && mins[2] < max(v[0][2], max(v[1][2], v[2][2]))) + shadowmarklist[numshadowmark++] = i; + } + R_Shadow_VolumeFromList(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, numshadowmark, shadowmarklist); +} + +void R_Shadow_VolumeFromSphere(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, float radius) +{ + vec3_t mins, maxs; + mins[0] = projectorigin[0] - radius; + mins[1] = projectorigin[1] - radius; + mins[2] = projectorigin[2] - radius; + maxs[0] = projectorigin[0] + radius; + maxs[1] = projectorigin[1] + radius; + maxs[2] = projectorigin[2] + radius; + R_Shadow_VolumeFromBox(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, mins, maxs); +} + +void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i) +{ + GL_VertexPointer(vertex3f); + if (r_shadowstage == SHADOWSTAGE_STENCIL) + { + // decrement stencil if frontface is behind depthbuffer + qglCullFace(GL_FRONT); // quake is backwards, this culls back faces + qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP); + R_Mesh_Draw(numvertices, numtriangles, element3i); c_rt_shadowmeshes++; - c_rt_shadowtris += numtris; + c_rt_shadowtris += numtriangles; + // increment stencil if backface is behind depthbuffer + qglCullFace(GL_BACK); // quake is backwards, this culls front faces + qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP); } + R_Mesh_Draw(numvertices, numtriangles, element3i); + c_rt_shadowmeshes++; + c_rt_shadowtris += numtriangles; } void R_Shadow_RenderShadowMeshVolume(shadowmesh_t *firstmesh) @@ -1837,6 +1698,7 @@ void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int i // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls) void R_RTLight_Compile(rtlight_t *rtlight) { +#if 0 int i, j, k, l, maxverts = 256, tris; float *vertex3f = NULL, mins[3], maxs[3]; shadowmesh_t *mesh, *castmesh = NULL; @@ -2068,6 +1930,7 @@ void R_RTLight_Compile(rtlight_t *rtlight) for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next) l += mesh->numtriangles; Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles, %i light triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], k, l); +#endif } void R_RTLight_Uncompile(rtlight_t *rtlight) diff --git a/r_shadow.h b/r_shadow.h index 3af580fe..580e67d3 100644 --- a/r_shadow.h +++ b/r_shadow.h @@ -16,11 +16,14 @@ extern cvar_t r_shadow_worldshadows; extern cvar_t r_shadow_dlightshadows; void R_Shadow_Init(void); -void R_Shadow_Volume(int numverts, int numtris, const float *invertex3f, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance); +void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, int nummarktris, const int *marktris); +void R_Shadow_VolumeFromBox(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, const vec3_t mins, const vec3_t maxs); +void R_Shadow_VolumeFromSphere(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, float radius); void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *elements, const float *vertices, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, const float *lightcolor, const matrix4x4_t *matrix_worldtolight, const matrix4x4_t *matrix_worldtoattenuationxyz, const matrix4x4_t *matrix_worldtoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *lightcubemap); void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elements, const float *vertices, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, const float *relativeeyeorigin, const float *lightcolor, const matrix4x4_t *matrix_worldtolight, const matrix4x4_t *matrix_worldtoattenuationxyz, const matrix4x4_t *matrix_worldtoattenuationz, rtexture_t *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap); void R_Shadow_ClearStencil(void); +void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i); void R_Shadow_RenderShadowMeshVolume(shadowmesh_t *mesh); void R_Shadow_Stage_Begin(void); void R_Shadow_LoadWorldLightsIfNeeded(void); @@ -46,4 +49,13 @@ void R_RTLight_Uncompile(rtlight_t *rtlight); void R_ShadowVolumeLighting(int visiblevolumes); +int *R_Shadow_ResizeShadowElements(int numtris); + +extern int maxshadowmark; +extern int numshadowmark; +extern int *shadowmark; +extern int *shadowmarklist; +extern int shadowmarkcount; +void R_Shadow_PrepareShadowMark(int numtris); + #endif diff --git a/todo b/todo index 0cc3f437..b98d5adf 100644 --- a/todo +++ b/todo @@ -36,6 +36,12 @@ d darkplaces: revert noclip movement to match nq for compatibility with mods tha -n darkplaces: typing ip in join game menu should show 'trying' and 'no response' after a while, or 'no network' if networking is not initialized (yummyluv) d darkplaces: make light_lev dlights from qc require PFLAGS_FULLDYNAMIC flag d darkplaces: improve tenebrae compatibility by handling EF_FULLDYNAMIC flag in tenebrae mode, also make all sprites render additive +3 darkplaces: figure out BoxOnPlaneSide crash that happens in dpmod dpdm2 deathmatch 7 occasionally +2 darkplaces: add q2 sprite support sometime +0 dpmod: fix tilted corpse bug +0 dpmod: figure out why the dbsg isn't selectable +0 dpmod: fix the plasma wave doing excessive damage at low framerates +0 dpmod: fix the 'shell casing spawning at wrong player' bug somehow 0 darkplaces: figure out why bmodels aren't receiving lightmap dlights d darkplaces: fixed SV_TouchAreaGrid to not crash if SV_IncreaseEdicts is called during a touch function, by making a list of edicts to touch and then running through the list afterward (KGB|romi) d darkplaces: moved R_ShadowVolumeLighting to r_shadow.c @@ -90,7 +96,7 @@ d darkplaces: add tenebrae light entity properties, like cubemap and style and s d darkplaces: add r_shadow_realtime_world_lightmaps cvar to control lightmap brightness (Mitchell) -n darkplaces: add gl_lightmaps cvar to disable texturing except lightmaps for testing (Vic) 0 hmap2: release hmap2 (Vic, Supajoe) -4 darkplaces: add capability for qc entities to act as bones in a model, and send them as compressed origins in the parent entity's updates, with perhaps a limit of 16 bones, this would allow some simple serverside ragdoll (Mitchell) +4 darkplaces: add capability for qc entities to act as bones in a model, and send them as compressed origins in the parent entity's updates, with perhaps a limit of 16 bones, this would allow some simple serverside ragdoll (Mitchell, Deej) d darkplaces: worked around Intel precision bug with view blends (they were not covering one line of the screen, due to being so huge that it had precision problems, on ATI and NVIDIA) (Sajt) 0 darkplaces: release darkplaces build 0 darkplaces: fix loadsky;r_restart;r_restart crash, again (sajt) -- 2.39.2