From 1740f737276f086c2f19758f72881a20e5070b57 Mon Sep 17 00:00:00 2001 From: havoc Date: Mon, 30 Sep 2002 14:55:28 +0000 Subject: [PATCH] bmodel shadow volumes static lights (in maps with .lights files) now cast shadow volumes (this combined with the above makes dpdm1 and dpdm2 unplayably slow - need to do precomputed world shadow volumes) (note: like the previous shadow volume commits, this is still just visible volumes when you use r_shadows 2, purely experimental still) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@2485 d7cf8633-e32d-0410-b094-e92efae38249 --- gl_backend.c | 20 ---------- gl_backend.h | 2 - gl_draw.c | 2 +- gl_models.c | 51 ++++++++++++++++++------ gl_rmain.c | 18 +++++---- gl_rsurf.c | 86 ++++++++++++++++++++++++++++++++++++++++ glquake.h | 7 ++++ model_brush.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++---- model_brush.h | 10 +++++ r_shadow.c | 72 +++++++++++++++++++++++++++------ r_shadow.h | 5 ++- r_sky.c | 2 +- vid_shared.c | 2 + 13 files changed, 319 insertions(+), 65 deletions(-) diff --git a/gl_backend.c b/gl_backend.c index 16088141..2ec09f0b 100644 --- a/gl_backend.c +++ b/gl_backend.c @@ -583,26 +583,6 @@ void R_Mesh_Finish(void) qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR } -void GL_DepthFunc(int value) -{ - if (!r_render.integer) - return; - - qglDepthFunc (value); - CHECKGLERROR -} - -void GL_ClearDepth(void) -{ - BACKENDACTIVECHECK - - if (!r_render.integer) - return; - - qglClear(GL_DEPTH_BUFFER_BIT); - CHECKGLERROR -} - void R_Mesh_Matrix(const matrix4x4_t *matrix) { if (memcmp(matrix, &backend_modelmatrix, sizeof(matrix4x4_t))) diff --git a/gl_backend.h b/gl_backend.h index cd4b85cb..6a652013 100644 --- a/gl_backend.h +++ b/gl_backend.h @@ -16,8 +16,6 @@ void GL_SetupView_Mode_Perspective (double aspect, double fovx, double fovy, dou void GL_SetupView_Mode_Ortho (double x1, double y1, double x2, double y2, double zNear, double zFar); void GL_UseColorArray(void); void GL_Color(float cr, float cg, float cb, float ca); -void GL_DepthFunc(int value); -void GL_ClearDepth(void); extern cvar_t gl_lockarrays; diff --git a/gl_draw.c b/gl_draw.c index 598d9026..717f0b89 100644 --- a/gl_draw.c +++ b/gl_draw.c @@ -397,7 +397,7 @@ void R_DrawQueue(void) } GL_SetupView_ViewPort(vid.realx, vid.realy, vid.realwidth, vid.realheight); GL_SetupView_Mode_Ortho(0, 0, vid.conwidth, vid.conheight, -10, 100); - GL_DepthFunc(GL_LEQUAL); + qglDepthFunc(GL_LEQUAL); R_Mesh_Start(); R_Mesh_Matrix(&r_identitymatrix); diff --git a/gl_models.c b/gl_models.c index c56ee35a..4d5a876f 100644 --- a/gl_models.c +++ b/gl_models.c @@ -488,30 +488,57 @@ void R_DrawQ1Q2AliasModelFakeShadow (entity_render_t *ent) rmeshstate_t m; model_t *model; float *v, planenormal[3], planedist, dist, projection[3], floororigin[3], surfnormal[3], lightdirection[3], v2[3]; + mlight_t *sl; + rdlight_t *rd; if (r_shadows.integer > 1) { - float f; + float f, lightscale, lightcolor[3]; vec3_t temp; - for (i = 0;i < r_numdlights;i++) + memset(&m, 0, sizeof(m)); + m.blendfunc1 = GL_ONE; + m.blendfunc2 = GL_ONE; + R_Mesh_State(&m); + R_Mesh_Matrix(&ent->matrix); + for (i = 0, sl = cl.worldmodel->lights;i < cl.worldmodel->numlights;i++, sl++) + { + if (d_lightstylevalue[sl->style] > 0) + { + VectorSubtract(ent->origin, sl->origin, temp); + f = DotProduct(temp,temp); + if (f < (ent->model->radius2 + sl->cullradius2)) + { + model = ent->model; + R_Mesh_ResizeCheck(model->numverts * 2); + R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm); + Matrix4x4_Transform(&ent->inversematrix, sl->origin, temp); + GL_Color(0.1 * r_colorscale, 0.025 * r_colorscale, 0.0125 * r_colorscale, 1); + R_Shadow_Volume(model->numverts, model->numtris, model->mdlmd2data_indices, model->mdlmd2data_triangleneighbors, temp, sl->cullradius + model->radius - sqrt(f), true); + GL_UseColorArray(); + lightscale = d_lightstylevalue[sl->style] * (1.0f / 65536.0f); + VectorScale(sl->light, lightscale, lightcolor); + R_Shadow_VertexLight(model->numverts, aliasvertnorm, temp, sl->cullradius2, sl->distbias, sl->subtract, lightcolor); + R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices); + } + } + } + for (i = 0, rd = r_dlight;i < r_numdlights;i++, rd++) { - if (ent != r_dlight[i].ent) + if (ent != rd->ent) { - VectorSubtract(ent->origin, r_dlight[i].origin, temp); + VectorSubtract(ent->origin, rd->origin, temp); f = DotProduct(temp,temp); - if (f < (ent->model->radius2 + r_dlight[i].cullradius2)) + if (f < (ent->model->radius2 + rd->cullradius2)) { model = ent->model; R_Mesh_ResizeCheck(model->numverts * 2); - memset(&m, 0, sizeof(m)); - m.blendfunc1 = GL_ONE; - m.blendfunc2 = GL_ONE; - R_Mesh_State(&m); - R_Mesh_Matrix(&ent->matrix); R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm); + Matrix4x4_Transform(&ent->inversematrix, rd->origin, temp); GL_Color(0.1 * r_colorscale, 0.025 * r_colorscale, 0.0125 * r_colorscale, 1); - Matrix4x4_Transform(&ent->inversematrix, r_dlight[i].origin, temp); - R_ShadowVolume(model->numverts, model->numtris, model->mdlmd2data_indices, model->mdlmd2data_triangleneighbors, temp, r_dlight[i].cullradius + model->radius - sqrt(f), true); + R_Shadow_Volume(model->numverts, model->numtris, model->mdlmd2data_indices, model->mdlmd2data_triangleneighbors, temp, rd->cullradius + model->radius - sqrt(f), true); + GL_UseColorArray(); + R_Shadow_VertexLight(model->numverts, aliasvertnorm, temp, rd->cullradius2, LIGHTOFFSET, rd->subtract, rd->light); + R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices); } } } diff --git a/gl_rmain.c b/gl_rmain.c index dc4bd184..184af307 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -544,7 +544,7 @@ void R_DrawModels (void) } } -void R_DrawModelFakeShadows (void) +void R_DrawFakeShadows (void) { int i; entity_render_t *ent; @@ -552,6 +552,9 @@ void R_DrawModelFakeShadows (void) if (!r_drawentities.integer) return; + ent = &cl_entities[0].render; + if (ent->model && ent->model->DrawFakeShadow) + ent->model->DrawFakeShadow(ent); for (i = 0;i < r_refdef.numentities;i++) { ent = r_refdef.entities[i]; @@ -676,7 +679,7 @@ void R_RenderView (void) GL_SetupView_ViewPort(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height); GL_SetupView_Mode_Perspective((double) r_refdef.height / r_refdef.width, r_refdef.fov_x, r_refdef.fov_y, 1.0f, r_farclip); GL_SetupView_Orientation_FromEntity (r_refdef.vieworg, r_refdef.viewangles); - GL_DepthFunc(GL_LEQUAL); + qglDepthFunc(GL_LEQUAL); R_Mesh_Start(); R_MeshQueue_BeginScene(); @@ -692,12 +695,6 @@ void R_RenderView (void) if (!intimerefresh && !r_speeds.integer) S_ExtraUpdate (); - if (r_shadows.integer) - { - R_DrawModelFakeShadows(); - R_TimeReport("fakeshadows"); - } - R_DrawModels(); R_TimeReport("models"); @@ -721,6 +718,11 @@ void R_RenderView (void) R_MeshQueue_Render(); R_MeshQueue_EndScene(); + if (r_shadows.integer) + { + R_DrawFakeShadows(); + R_TimeReport("fakeshadows"); + } R_Mesh_Finish(); R_TimeReport("meshfinish"); } diff --git a/gl_rsurf.c b/gl_rsurf.c index 314429c0..9448717d 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // r_surf.c: surface-related refresh code #include "quakedef.h" +#include "r_shadow.h" #define MAX_LIGHTMAP_SIZE 256 @@ -774,6 +775,9 @@ static void RSurfShader_Sky(const entity_render_t *ent, const texture_t *texture memset(&m, 0, sizeof(m)); if (skyrendermasked) { + qglColorMask(0,0,0,0); + // just to make sure that braindead drivers don't draw anything + // despite that colormask... m.blendfunc1 = GL_ZERO; m.blendfunc2 = GL_ONE; } @@ -795,6 +799,7 @@ static void RSurfShader_Sky(const entity_render_t *ent, const texture_t *texture R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index); } } + qglColorMask(1,1,1,1); } static void RSurfShader_Water_Callback(const void *calldata1, int calldata2) @@ -1825,6 +1830,87 @@ void R_DrawBrushModelNormal (entity_render_t *ent) R_DrawBrushModel(ent, false, true); } +void R_DrawBrushModelShadowVolumes (entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume) +{ + int i, numsurfaces; + msurface_t *surf; + float projectdistance, f, temp[3], lightradius2; + surfmesh_t *mesh; + numsurfaces = ent->model->nummodelsurfaces; + lightradius2 = lightradius * lightradius; + for (i = 0, surf = ent->model->surfaces + ent->model->firstmodelsurface;i < numsurfaces;i++, surf++) + { + VectorSubtract(relativelightorigin, surf->poly_center, temp); + if (DotProduct(temp, temp) < (surf->poly_radius2 + lightradius2)) + { + f = PlaneDiff(relativelightorigin, surf->plane); + if (surf->flags & SURF_PLANEBACK) + f = -f; + // draw shadows only for backfaces + if (f < 0) + { + projectdistance = lightradius + f; + if (projectdistance > 0) + { + for (mesh = surf->mesh;mesh;mesh = mesh->chain) + { + R_Mesh_ResizeCheck(mesh->numverts * 2); + memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4])); + R_Shadow_Volume(mesh->numverts, mesh->numtriangles, mesh->index, mesh->triangleneighbors, relativelightorigin, projectdistance, visiblevolume); + } + } + } + } + } +} + +extern cvar_t r_shadows; +void R_DrawBrushModelFakeShadow (entity_render_t *ent) +{ + int i; + vec3_t relativelightorigin; + rmeshstate_t m; + mlight_t *sl; + rdlight_t *rd; + + if (r_shadows.integer < 2) + return; + + memset(&m, 0, sizeof(m)); + m.blendfunc1 = GL_ONE; + m.blendfunc2 = GL_ONE; + R_Mesh_State(&m); + R_Mesh_Matrix(&ent->matrix); + GL_Color(0.0125 * r_colorscale, 0.025 * r_colorscale, 0.1 * r_colorscale, 1); + for (i = 0, sl = cl.worldmodel->lights;i < cl.worldmodel->numlights;i++, sl++) + { + if (d_lightstylevalue[sl->style] > 0 + && ent->maxs[0] >= sl->origin[0] - sl->cullradius + && ent->mins[0] <= sl->origin[0] + sl->cullradius + && ent->maxs[1] >= sl->origin[1] - sl->cullradius + && ent->mins[1] <= sl->origin[1] + sl->cullradius + && ent->maxs[2] >= sl->origin[2] - sl->cullradius + && ent->mins[2] <= sl->origin[2] + sl->cullradius) + { + Matrix4x4_Transform(&ent->inversematrix, sl->origin, relativelightorigin); + R_DrawBrushModelShadowVolumes (ent, relativelightorigin, sl->cullradius, true); + } + } + for (i = 0, rd = r_dlight;i < r_numdlights;i++, rd++) + { + if (ent->maxs[0] >= rd->origin[0] - rd->cullradius + && ent->mins[0] <= rd->origin[0] + rd->cullradius + && ent->maxs[1] >= rd->origin[1] - rd->cullradius + && ent->mins[1] <= rd->origin[1] + rd->cullradius + && ent->maxs[2] >= rd->origin[2] - rd->cullradius + && ent->mins[2] <= rd->origin[2] + rd->cullradius) + { + Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin); + R_DrawBrushModelShadowVolumes (ent, relativelightorigin, rd->cullradius, true); + } + } +} + static void gl_surf_start(void) { } diff --git a/glquake.h b/glquake.h index 18e75d9e..e2832595 100644 --- a/glquake.h +++ b/glquake.h @@ -195,6 +195,12 @@ typedef double GLclampd; #define GL_ACCUM_BUFFER_BIT 0x00000200 #define GL_STENCIL_BUFFER_BIT 0x00000400 #define GL_COLOR_BUFFER_BIT 0x00004000 + +#define GL_STENCIL_TEST 0x0B90 +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 #endif // GL_ARB_multitexture @@ -312,6 +318,7 @@ extern void (GLAPIENTRY *qglClearDepth)(GLclampd depth); extern void (GLAPIENTRY *qglDepthFunc)(GLenum func); extern void (GLAPIENTRY *qglDepthMask)(GLboolean flag); extern void (GLAPIENTRY *qglDepthRange)(GLclampd near_val, GLclampd far_val); +extern void (GLAPIENTRY *qglColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); extern void (GLAPIENTRY *qglDrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); extern void (GLAPIENTRY *qglDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); diff --git a/model_brush.c b/model_brush.c index 51538971..51fc0c79 100644 --- a/model_brush.c +++ b/model_brush.c @@ -662,6 +662,56 @@ void Mod_LoadLightList(void) } } +void Mod_ProcessLightList(void) +{ + int i, j, k, *mark; + mlight_t *e; + msurface_t *surf; + float dist; + mleaf_t *l; + qbyte *pvs; + for (i = 0, e = loadmodel->lights;i < loadmodel->numlights;i++, e++) + { + e->cullradius2 = DotProduct(e->light, e->light) * (1.0f / (8192.0f * 8192.0f)) / (e->falloff * e->falloff) + 4096.0f; + if (e->cullradius2 > 4096.0f * 4096.0f) + e->cullradius2 = 4096.0f * 4096.0f; + e->cullradius = sqrt(e->cullradius2); + l = Mod_PointInLeaf(e->origin, loadmodel); + if (l->compressed_vis) + pvs = Mod_DecompressVis (l->compressed_vis, loadmodel); + else + pvs = mod_novis; + for (j = 0, l = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++) + { + if (pvs[j >> 3] & (1 << (j & 7))) + { + for (k = 0, mark = l->firstmarksurface;k < l->nummarksurfaces;k++, mark++) + { + surf = loadmodel->surfaces + *mark; + dist = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist; + if (surf->flags & SURF_PLANEBACK) + dist = -dist; + if (dist > 0 && dist < e->cullradius) + loadmodel->surfacevisframes[j] = i - 1000000; + } + } + } + e->numsurfaces = 0; + for (j = 0;j < loadmodel->nummodelsurfaces;j++) + if (loadmodel->surfacevisframes[j] == i - 1000000) + e->numsurfaces++; + e->surfaces = NULL; + if (e->numsurfaces > 0) + { + e->surfaces = Mem_Alloc(loadmodel->mempool, sizeof(msurface_t *) * e->numsurfaces); + e->numsurfaces = 0; + for (j = 0;j < loadmodel->nummodelsurfaces;j++) + if (loadmodel->surfacevisframes[j] == i - 1000000) + e->surfaces[e->numsurfaces++] = loadmodel->surfaces + loadmodel->firstmodelsurface + j; + } + } +} + /* ================= @@ -1111,8 +1161,8 @@ void Mod_GenerateWarpMesh (msurface_t *surf) void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly) { - int i, iu, iv, *index, smax, tmax; - float *in, s, t, u, v, ubase, vbase, uscale, vscale; + int i, iu, iv, *index, *n, smax, tmax; + float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3]; surfmesh_t *mesh; smax = surf->extents[0] >> 4; @@ -1145,7 +1195,7 @@ void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly) vscale = (vscale - vbase) * 16.0 / ((surf->extents[1] & ~15) + 16); } - surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[3]) + surf->poly_numverts * (4 + 2 + 2 + 2 + 1) * sizeof(float)); + surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[6]) + surf->poly_numverts * (4 + 2 + 2 + 2 + 1 + 3) * sizeof(float)); mesh->numverts = surf->poly_numverts; mesh->numtriangles = surf->poly_numverts - 2; mesh->verts = (float *)(mesh + 1); @@ -1154,15 +1204,24 @@ void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly) mesh->ab = mesh->uv + mesh->numverts * 2; mesh->lightmapoffsets = (int *)(mesh->ab + mesh->numverts * 2); mesh->index = mesh->lightmapoffsets + mesh->numverts; + mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3; + mesh->normals = (float *)(mesh->triangleneighbors + mesh->numtriangles * 3); index = mesh->index; + n = mesh->triangleneighbors; for (i = 0;i < mesh->numtriangles;i++) { *index++ = 0; *index++ = i + 1; *index++ = i + 2; + *n++ = i - 1; + *n++ = -1; + *n++ = i + 1; } + VectorCopy(surf->plane->normal, normal); + if (surf->flags & SURF_PLANEBACK) + VectorNegate(normal, normal); for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3) { s = DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]; @@ -1187,34 +1246,46 @@ void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly) mesh->ab[i * 2 + 0] = s * (1.0f / 16.0f); mesh->ab[i * 2 + 1] = t * (1.0f / 16.0f); mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3); + mesh->normals[i * 3 + 0] = normal[0]; + mesh->normals[i * 3 + 1] = normal[1]; + mesh->normals[i * 3 + 2] = normal[2]; } } void Mod_GenerateVertexMesh (msurface_t *surf) { - int i, *index; - float *in, s, t; + int i, *index, *n; + float *in, s, t, normal[3]; surfmesh_t *mesh; surf->lightmaptexturestride = 0; surf->lightmaptexture = NULL; - surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[3]) + surf->poly_numverts * (4 + 2 + 2) * sizeof(float)); + surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[6]) + surf->poly_numverts * (4 + 2 + 2 + 3) * sizeof(float)); mesh->numverts = surf->poly_numverts; mesh->numtriangles = surf->poly_numverts - 2; mesh->verts = (float *)(mesh + 1); mesh->st = mesh->verts + mesh->numverts * 4; mesh->ab = mesh->st + mesh->numverts * 2; mesh->index = (int *)(mesh->ab + mesh->numverts * 2); + mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3; + mesh->normals = (float *)(mesh->triangleneighbors + mesh->numtriangles * 3); index = mesh->index; + n = mesh->triangleneighbors; for (i = 0;i < mesh->numtriangles;i++) { *index++ = 0; *index++ = i + 1; *index++ = i + 2; + *n++ = -1; + *n++ = -1; + *n++ = i + 1; } + VectorCopy(surf->plane->normal, normal); + if (surf->flags & SURF_PLANEBACK) + VectorNegate(normal, normal); for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3) { s = (DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]); @@ -1226,13 +1297,16 @@ void Mod_GenerateVertexMesh (msurface_t *surf) mesh->st[i * 2 + 1] = t / surf->texinfo->texture->height; mesh->ab[i * 2 + 0] = s * (1.0f / 16.0f); mesh->ab[i * 2 + 1] = t * (1.0f / 16.0f); + mesh->normals[i * 3 + 0] = normal[0]; + mesh->normals[i * 3 + 1] = normal[1]; + mesh->normals[i * 3 + 2] = normal[2]; } } void Mod_GenerateSurfacePolygon (msurface_t *surf) { int i, lindex; - float *vec, *vert, mins[3], maxs[3]; + float *vec, *vert, mins[3], maxs[3], temp[3], dist; // convert edges back to a normal polygon surf->poly_numverts = surf->numedges; @@ -1263,6 +1337,17 @@ void Mod_GenerateSurfacePolygon (msurface_t *surf) surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f; surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f; surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f; + surf->poly_radius2 = 0; + vert = surf->poly_verts; + for (i = 0;i < surf->poly_numverts;i++) + { + VectorSubtract(vert, surf->poly_center, temp); + dist = DotProduct(temp, temp); + if (surf->poly_radius2 < dist) + surf->poly_radius2 = dist; + vert += 3; + } + surf->poly_radius = sqrt(surf->poly_radius2); } /* @@ -2339,6 +2424,7 @@ static void Mod_MakePortals(void) Mod_LoadBrushModel ================= */ +extern void R_DrawBrushModelFakeShadow (entity_render_t *ent); void Mod_LoadBrushModel (model_t *mod, void *buffer) { int i, j; @@ -2346,6 +2432,7 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) dmodel_t *bm; mempool_t *mainmempool; char *loadname; + model_t *originalloadmodel; mod->type = mod_brush; @@ -2398,6 +2485,7 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) loadname = mod->name; Mod_LoadLightList (); + originalloadmodel = loadmodel; // // set up the submodels (FIXME: this is confusing) @@ -2479,7 +2567,7 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) mod->numleafs = bm->visleafs; mod->Draw = R_DrawBrushModelNormal; - mod->DrawFakeShadow = NULL; + mod->DrawFakeShadow = R_DrawBrushModelFakeShadow; // LordHavoc: only register submodels if it is the world // (prevents bsp models from replacing world submodels) @@ -2497,5 +2585,8 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) mod = loadmodel; } } + + loadmodel = originalloadmodel; + Mod_ProcessLightList (); } diff --git a/model_brush.h b/model_brush.h index 80756e39..f109b1d9 100644 --- a/model_brush.h +++ b/model_brush.h @@ -143,11 +143,13 @@ typedef struct surfmesh_s int numverts; int numtriangles; float *verts; + float *normals; int *lightmapoffsets; float *st; float *uv; float *ab; int *index; + int *triangleneighbors; } surfmesh_t; @@ -200,6 +202,8 @@ typedef struct msurface_s float *poly_verts; // bounding box for onscreen checks, and center for sorting vec3_t poly_mins, poly_maxs, poly_center; + // bounding sphere radius (around poly_center) + float poly_radius, poly_radius2; // these are regenerated every frame // lighting info @@ -315,6 +319,12 @@ typedef struct mlight_s float distbias; // light style controlling this light int style; + // maximum extent of the light for various purposes + float cullradius; + float cullradius2; + // surfaces this shines on + int numsurfaces; + msurface_t **surfaces; // used only for loading calculations, number of leafs this shines on //int numleafs; } diff --git a/r_shadow.c b/r_shadow.c index 153867fd..c33d04f0 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -36,7 +36,7 @@ void R_Shadow_Init(void) R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap); } -void R_ShadowVolume(int numverts, int numtris, int *elements, int *neighbors, vec3_t relativelightorigin, float projectdistance, int visiblevolume) +void R_Shadow_Volume(int numverts, int numtris, int *elements, int *neighbors, vec3_t relativelightorigin, float projectdistance, int visiblevolume) { int i, *e, *n, *out, tris; float *v0, *v1, *v2, dir0[3], dir1[3], temp[3], f; @@ -128,7 +128,7 @@ void R_ShadowVolume(int numverts, int numtris, int *elements, int *neighbors, ve out += 6; tris += 2; // check the edges - if (trianglefacinglight[n[0]]) + if (n[0] < 0 || trianglefacinglight[n[0]]) { out[0] = e[0]; out[1] = e[1]; @@ -139,7 +139,7 @@ void R_ShadowVolume(int numverts, int numtris, int *elements, int *neighbors, ve out += 6; tris += 2; } - if (trianglefacinglight[n[1]]) + if (n[1] < 0 || trianglefacinglight[n[1]]) { out[0] = e[1]; out[1] = e[2]; @@ -150,7 +150,7 @@ void R_ShadowVolume(int numverts, int numtris, int *elements, int *neighbors, ve out += 6; tris += 2; } - if (trianglefacinglight[n[2]]) + if (n[2] < 0 || trianglefacinglight[n[2]]) { out[0] = e[2]; out[1] = e[0]; @@ -172,16 +172,64 @@ void R_ShadowVolume(int numverts, int numtris, int *elements, int *neighbors, ve } else { - qglCullFace(GL_FRONT); - //qglStencilFunc( + qglColorMask(0,0,0,0); + qglEnable(GL_STENCIL_TEST); + // 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(numverts * 2, tris, shadowelements); + // decrement stencil if frontface is infront of depthbuffer + qglCullFace(GL_FRONT); // quake is backwards, this culls back faces + qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP); + R_Mesh_Draw(numverts * 2, tris, shadowelements); + // restore to normal quake rendering + qglDisable(GL_STENCIL_TEST); + qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + qglColorMask(1,1,1,1); + } +} + +void R_Shadow_VertexLight(int numverts, float *normals, vec3_t relativelightorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor) +{ + int i; + float *n, *v, *c, f, dist, temp[3]; + // calculate vertex colors + for (i = 0, v = varray_vertex, c = varray_color, n = normals;i < numverts;i++, v += 4, c += 4, n += 3) + { + VectorSubtract(relativelightorigin, v, temp); + c[0] = 0; + c[1] = 0; + c[2] = 0; + c[3] = 1; + f = DotProduct(n, temp); + if (f > 0) + { + dist = DotProduct(temp, temp); + if (dist < lightradius2) + { + f = ((1.0f / (dist + lightdistbias)) - lightsubtract) * (f / sqrt(dist)); + c[0] = f * lightcolor[0]; + c[1] = f * lightcolor[1]; + c[2] = f * lightcolor[2]; + } + } } } -void R_Shadow_BeginScene(void) +void R_Shadow_RenderLightThroughStencil(int numverts, int numtris, int *elements, vec3_t relativelightorigin, float *normals) +{ + // only draw light where this geometry was already rendered AND the + // stencil is 0 (non-zero means shadow) + qglDepthFunc(GL_EQUAL); + qglEnable(GL_STENCIL_TEST); + qglStencilFunc(GL_EQUAL, 0, 0xFF); + R_Mesh_Draw(numverts, numtris, elements); + qglDisable(GL_STENCIL_TEST); + qglDepthFunc(GL_LEQUAL); +} + +void R_Shadow_ClearStencil(void) { - rmeshstate_t m; - memset(&m, 0, sizeof(m)); - m.blendfunc1 = GL_ONE; - m.blendfunc2 = GL_ZERO; - R_Mesh_State(&m); + qglClearStencil(0); + qglClear(GL_STENCIL_BUFFER_BIT); } diff --git a/r_shadow.h b/r_shadow.h index 42e80ba1..470d96d7 100644 --- a/r_shadow.h +++ b/r_shadow.h @@ -3,6 +3,9 @@ #define R_SHADOW_H void R_Shadow_Init(void); -void R_ShadowVolume(int numverts, int numtris, int *elements, int *neighbors, vec3_t relativelightorigin, float projectdistance, int visiblevolume); +void R_Shadow_Volume(int numverts, int numtris, int *elements, int *neighbors, vec3_t relativelightorigin, float projectdistance, int visiblevolume); +void R_Shadow_VertexLight(int numverts, float *normals, vec3_t relativelightorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor); +void R_Shadow_RenderLightThroughStencil(int numverts, int numtris, int *elements, vec3_t relativelightorigin, float *normals); +void R_Shadow_ClearStencil(void); #endif diff --git a/r_sky.c b/r_sky.c index 9b237f90..e73d3672 100644 --- a/r_sky.c +++ b/r_sky.c @@ -305,7 +305,7 @@ void R_Sky(void) // this modifies the depth buffer so we have to clear it afterward //R_SkyRoom(); // clear the depthbuffer that was used while rendering the skyroom - //R_Mesh_ClearDepth(); + //qglClear(GL_DEPTH_BUFFER_BIT); } */ } diff --git a/vid_shared.c b/vid_shared.c index 4ae9663a..212118b7 100644 --- a/vid_shared.c +++ b/vid_shared.c @@ -98,6 +98,7 @@ void (GLAPIENTRY *qglClearDepth)(GLclampd depth); void (GLAPIENTRY *qglDepthFunc)(GLenum func); void (GLAPIENTRY *qglDepthMask)(GLboolean flag); void (GLAPIENTRY *qglDepthRange)(GLclampd near_val, GLclampd far_val); +void (GLAPIENTRY *qglColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); void (GLAPIENTRY *qglDrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); void (GLAPIENTRY *qglDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); @@ -224,6 +225,7 @@ static gl_extensionfunctionlist_t opengl110funcs[] = {"glDepthMask", (void **) &qglDepthMask}, {"glDepthRange", (void **) &qglDepthRange}, {"glDrawElements", (void **) &qglDrawElements}, + {"glColorMask", (void **) &qglColorMask}, {"glVertexPointer", (void **) &qglVertexPointer}, // {"glNormalPointer", (void **) &qglNormalPointer}, {"glColorPointer", (void **) &qglColorPointer}, -- 2.39.2