From 64a368a5aabc3826fa374e35cd5e55909c8fa344 Mon Sep 17 00:00:00 2001 From: havoc Date: Thu, 3 Oct 2002 17:11:24 +0000 Subject: [PATCH] massive coding has been done on shadow volumes (some scrapped code which will be removed, some incomplete code, etc) some model fixes relating to gl_combine - r_quickmodels is gone off-screen models were not being culled (oops) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@2493 d7cf8633-e32d-0410-b094-e92efae38249 --- gl_models.c | 251 ++++++------- gl_rmain.c | 220 +++++++++++- gl_rsurf.c | 89 +++-- model_alias.c | 2 + model_brush.c | 935 +++++++++++++++++++++++++++++++++++++++++++++---- model_brush.h | 21 +- model_shared.c | 150 ++++++++ model_shared.h | 27 ++ model_sprite.c | 1 + r_light.c | 8 +- r_light.h | 2 +- r_shadow.c | 34 +- r_shadow.h | 2 +- 13 files changed, 1468 insertions(+), 274 deletions(-) diff --git a/gl_models.c b/gl_models.c index a3af2006..ceb9b5bf 100644 --- a/gl_models.c +++ b/gl_models.c @@ -3,8 +3,6 @@ #include "cl_collision.h" #include "r_shadow.h" -cvar_t r_quickmodels = {0, "r_quickmodels", "1"}; - typedef struct { float m[3][4]; @@ -47,33 +45,9 @@ void gl_models_newmap(void) void GL_Models_Init(void) { - Cvar_RegisterVariable(&r_quickmodels); - R_RegisterModule("GL_Models", gl_models_start, gl_models_shutdown, gl_models_newmap); } -/* -void R_AliasTransformVerts(int vertcount) -{ - vec3_t point; - float *av; - av = aliasvert; - while (vertcount >= 4) - { - VectorCopy(av, point);softwaretransform(point, av);av += 4; - VectorCopy(av, point);softwaretransform(point, av);av += 4; - VectorCopy(av, point);softwaretransform(point, av);av += 4; - VectorCopy(av, point);softwaretransform(point, av);av += 4; - vertcount -= 4; - } - while(vertcount > 0) - { - VectorCopy(av, point);softwaretransform(point, av);av += 4; - vertcount--; - } -} -*/ - void R_AliasLerpVerts(int vertcount, float *vertices, float *normals, float lerp1, const trivertx_t *verts1, const vec3_t fscale1, const vec3_t translate1, float lerp2, const trivertx_t *verts2, const vec3_t fscale2, const vec3_t translate2, @@ -237,9 +211,9 @@ void R_LerpMDLMD2Vertices(const entity_render_t *ent, float *vertices, float *no void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2) { - int i, c, pantsfullbright, shirtfullbright, colormapped, tex; + int i, c, fullbright, pantsfullbright, shirtfullbright, colormapped, tex; float pantscolor[3], shirtcolor[3]; - float fog, colorscale; + float fog, ifog, colorscale; vec3_t diff; qbyte *bcolor; rmeshstate_t m; @@ -248,9 +222,15 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2) const entity_render_t *ent = calldata1; int blendfunc1, blendfunc2; -// softwaretransformforentity(ent); R_Mesh_Matrix(&ent->matrix); + model = ent->model; + R_Mesh_ResizeCheck(model->numverts); + + skinframe = R_FetchSkinFrame(ent); + + fullbright = (ent->effects & EF_FULLBRIGHT) != 0; + fog = 0; if (fogenabled) { @@ -267,11 +247,7 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2) // 1. render model as normal, scaled by inverse of fog alpha (darkens it) // 2. render fog as additive } - - model = ent->model; - R_Mesh_ResizeCheck(model->numverts); - - skinframe = R_FetchSkinFrame(ent); + ifog = 1 - fog; if (ent->effects & EF_ADDITIVE) { @@ -289,64 +265,31 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2) blendfunc2 = GL_ZERO; } - colorscale = r_colorscale; - if (gl_combine.integer) - colorscale *= 0.25f; - if (!skinframe->base && !skinframe->pants && !skinframe->shirt && !skinframe->glow) { // untextured memset(&m, 0, sizeof(m)); m.blendfunc1 = blendfunc1; m.blendfunc2 = blendfunc2; + colorscale = r_colorscale; if (gl_combine.integer) + { + colorscale *= 0.25f; m.texrgbscale[0] = 4; + } m.tex[0] = R_GetTexture(r_notexture); R_Mesh_State(&m); - c_alias_polys += model->numtris; for (i = 0;i < model->numverts * 2;i++) varray_texcoord[0][i] = model->mdlmd2data_texcoords[i] * 8.0f; - aliasvert = varray_vertex; - aliasvertcolor = varray_color; - R_LerpMDLMD2Vertices(ent, aliasvert, aliasvertnorm); - R_LightModel(ent, model->numverts, colorscale, colorscale, colorscale, false); - aliasvert = aliasvertbuf; - aliasvertcolor = aliasvertcolorbuf; + R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm); + R_LightModel(ent, model->numverts, varray_vertex, aliasvertnorm, varray_color, colorscale, colorscale, colorscale, false); GL_UseColorArray(); R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices); return; } - colormapped = !skinframe->merged || (ent->colormap >= 0 && skinframe->base && (skinframe->pants || skinframe->shirt)); - if (r_quickmodels.integer && !colormapped && !fog && !skinframe->glow && !skinframe->fog) - { - // fastpath for the normal situation (one texture) - memset(&m, 0, sizeof(m)); - m.blendfunc1 = blendfunc1; - m.blendfunc2 = blendfunc2; - if (gl_combine.integer) - m.texrgbscale[0] = 4; - m.tex[0] = R_GetTexture(skinframe->merged); - R_Mesh_State(&m); - - c_alias_polys += model->numtris; - memcpy(varray_texcoord[0], model->mdlmd2data_texcoords, model->numverts * sizeof(float[2])); - aliasvert = varray_vertex; - aliasvertcolor = varray_color; - R_LerpMDLMD2Vertices(ent, aliasvert, aliasvertnorm); - R_LightModel(ent, model->numverts, colorscale, colorscale, colorscale, false); - aliasvert = aliasvertbuf; - aliasvertcolor = aliasvertcolorbuf; - GL_UseColorArray(); - R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices); - return; - } - - R_LerpMDLMD2Vertices(ent, aliasvert, aliasvertnorm); - R_LightModel(ent, model->numverts, colorscale * (1 - fog), colorscale * (1 - fog), colorscale * (1 - fog), false); - if (colormapped) { // 128-224 are backwards ranges @@ -371,19 +314,27 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2) memset(&m, 0, sizeof(m)); m.blendfunc1 = blendfunc1; m.blendfunc2 = blendfunc2; + colorscale = r_colorscale; if (gl_combine.integer) + { + colorscale *= 0.25f; m.texrgbscale[0] = 4; + } m.tex[0] = tex; R_Mesh_State(&m); - - blendfunc1 = GL_SRC_ALPHA; - blendfunc2 = GL_ONE; - c_alias_polys += model->numtris; - R_ModulateColors(aliasvertcolor, varray_color, model->numverts, colorscale, colorscale, colorscale); - memcpy(varray_vertex, aliasvert, model->numverts * sizeof(float[4])); + R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm); memcpy(varray_texcoord[0], model->mdlmd2data_texcoords, model->numverts * sizeof(float[2])); - GL_UseColorArray(); + if (fullbright) + GL_Color(colorscale * ifog, colorscale * ifog, colorscale * ifog, ent->alpha); + else + { + GL_UseColorArray(); + R_LightModel(ent, model->numverts, varray_vertex, aliasvertnorm, varray_color, colorscale * ifog, colorscale * ifog, colorscale * ifog, false); + } R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices); + c_alias_polys += model->numtris; + blendfunc1 = GL_SRC_ALPHA; + blendfunc2 = GL_ONE; } if (colormapped) @@ -396,24 +347,27 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2) memset(&m, 0, sizeof(m)); m.blendfunc1 = blendfunc1; m.blendfunc2 = blendfunc2; + colorscale = r_colorscale; if (gl_combine.integer) + { + colorscale *= 0.25f; m.texrgbscale[0] = 4; + } m.tex[0] = tex; R_Mesh_State(&m); - - blendfunc1 = GL_SRC_ALPHA; - blendfunc2 = GL_ONE; - c_alias_polys += model->numtris; + R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm); + memcpy(varray_texcoord[0], model->mdlmd2data_texcoords, model->numverts * sizeof(float[2])); if (pantsfullbright) - GL_Color(pantscolor[0] * colorscale, pantscolor[1] * colorscale, pantscolor[2] * colorscale, ent->alpha); + GL_Color(pantscolor[0] * colorscale * ifog, pantscolor[1] * colorscale * ifog, pantscolor[2] * colorscale * ifog, ent->alpha); else { GL_UseColorArray(); - R_ModulateColors(aliasvertcolor, varray_color, model->numverts, pantscolor[0] * colorscale, pantscolor[1] * colorscale, pantscolor[2] * colorscale); + R_LightModel(ent, model->numverts, varray_vertex, aliasvertnorm, varray_color, pantscolor[0] * colorscale * ifog, pantscolor[1] * colorscale * ifog, pantscolor[2] * colorscale * ifog, false); } - memcpy(varray_vertex, aliasvert, model->numverts * sizeof(float[4])); - memcpy(varray_texcoord[0], model->mdlmd2data_texcoords, model->numverts * sizeof(float[2])); R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices); + c_alias_polys += model->numtris; + blendfunc1 = GL_SRC_ALPHA; + blendfunc2 = GL_ONE; } } if (skinframe->shirt) @@ -424,24 +378,27 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2) memset(&m, 0, sizeof(m)); m.blendfunc1 = blendfunc1; m.blendfunc2 = blendfunc2; + colorscale = r_colorscale; if (gl_combine.integer) + { + colorscale *= 0.25f; m.texrgbscale[0] = 4; + } m.tex[0] = tex; R_Mesh_State(&m); - - blendfunc1 = GL_SRC_ALPHA; - blendfunc2 = GL_ONE; - c_alias_polys += model->numtris; + R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm); + memcpy(varray_texcoord[0], model->mdlmd2data_texcoords, model->numverts * sizeof(float[2])); if (shirtfullbright) - GL_Color(shirtcolor[0] * colorscale, shirtcolor[1] * colorscale, shirtcolor[2] * colorscale, ent->alpha); + GL_Color(shirtcolor[0] * colorscale * ifog, shirtcolor[1] * colorscale * ifog, shirtcolor[2] * colorscale * ifog, ent->alpha); else { GL_UseColorArray(); - R_ModulateColors(aliasvertcolor, varray_color, model->numverts, shirtcolor[0] * colorscale, shirtcolor[1] * colorscale, shirtcolor[2] * colorscale); + R_LightModel(ent, model->numverts, varray_vertex, aliasvertnorm, varray_color, shirtcolor[0] * colorscale * ifog, shirtcolor[1] * colorscale * ifog, shirtcolor[2] * colorscale * ifog, false); } - memcpy(varray_vertex, aliasvert, model->numverts * sizeof(float[4])); - memcpy(varray_texcoord[0], model->mdlmd2data_texcoords, model->numverts * sizeof(float[2])); R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices); + c_alias_polys += model->numtris; + blendfunc1 = GL_SRC_ALPHA; + blendfunc2 = GL_ONE; } } } @@ -459,9 +416,9 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2) blendfunc1 = GL_SRC_ALPHA; blendfunc2 = GL_ONE; c_alias_polys += model->numtris; - memcpy(varray_vertex, aliasvert, model->numverts * sizeof(float[4])); + R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm); memcpy(varray_texcoord[0], model->mdlmd2data_texcoords, model->numverts * sizeof(float[2])); - GL_Color((1 - fog) * r_colorscale, (1 - fog) * r_colorscale, (1 - fog) * r_colorscale, ent->alpha); + GL_Color(ifog * r_colorscale, ifog * r_colorscale, ifog * r_colorscale, ent->alpha); R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices); } } @@ -474,13 +431,25 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2) R_Mesh_State(&m); c_alias_polys += model->numtris; - memcpy(varray_vertex, aliasvert, model->numverts * sizeof(float[4])); + R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm); memcpy(varray_texcoord[0], model->mdlmd2data_texcoords, model->numverts * sizeof(float[2])); GL_Color(fogcolor[0] * fog * r_colorscale, fogcolor[1] * fog * r_colorscale, fogcolor[2] * fog * r_colorscale, ent->alpha); R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices); } } +void R_DrawQ1Q2AliasModelShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume) +{ + float projectdistance; + projectdistance = lightradius + ent->model->radius - sqrt(DotProduct(relativelightorigin, relativelightorigin)); + if (projectdistance > 0.1) + { + R_Mesh_ResizeCheck(ent->model->numverts * 2); + R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm); + R_Shadow_Volume(ent->model->numverts, ent->model->numtris, varray_vertex, ent->model->mdlmd2data_indices, ent->model->mdlmd2data_triangleneighbors, relativelightorigin, lightradius, projectdistance, visiblevolume); + } +} + extern cvar_t r_shadows; void R_DrawQ1Q2AliasModelFakeShadow (entity_render_t *ent) { @@ -488,13 +457,14 @@ 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, lightscale, lightcolor[3]; vec3_t temp; + mlight_t *sl; + rdlight_t *rd; memset(&m, 0, sizeof(m)); m.blendfunc1 = GL_ONE; m.blendfunc2 = GL_ONE; @@ -544,6 +514,7 @@ void R_DrawQ1Q2AliasModelFakeShadow (entity_render_t *ent) } return; } + */ lightdirection[0] = 0.5; lightdirection[1] = 0.2; @@ -599,21 +570,6 @@ int ZymoticLerpBones(int count, const zymbonematrix *bonebase, const frameblend_ zymbonematrix *out, rootmatrix, m; const zymbonematrix *bone1, *bone2, *bone3, *bone4; - /* - // LordHavoc: combine transform from zym coordinate space to quake coordinate space with model to world transform matrix - rootmatrix.m[0][0] = softwaretransform_matrix[0][1]; - rootmatrix.m[0][1] = -softwaretransform_matrix[0][0]; - rootmatrix.m[0][2] = softwaretransform_matrix[0][2]; - rootmatrix.m[0][3] = softwaretransform_matrix[0][3]; - rootmatrix.m[1][0] = softwaretransform_matrix[1][1]; - rootmatrix.m[1][1] = -softwaretransform_matrix[1][0]; - rootmatrix.m[1][2] = softwaretransform_matrix[1][2]; - rootmatrix.m[1][3] = softwaretransform_matrix[1][3]; - rootmatrix.m[2][0] = softwaretransform_matrix[2][1]; - rootmatrix.m[2][1] = -softwaretransform_matrix[2][0]; - rootmatrix.m[2][2] = softwaretransform_matrix[2][2]; - rootmatrix.m[2][3] = softwaretransform_matrix[2][3]; - */ rootmatrix.m[0][0] = 1; rootmatrix.m[0][1] = 0; rootmatrix.m[0][2] = 0; @@ -771,10 +727,10 @@ int ZymoticLerpBones(int count, const zymbonematrix *bonebase, const frameblend_ return true; } -void ZymoticTransformVerts(int vertcount, int *bonecounts, zymvertex_t *vert) +void ZymoticTransformVerts(int vertcount, float *vertex, int *bonecounts, zymvertex_t *vert) { int c; - float *out = aliasvert; + float *out = vertex; zymbonematrix *matrix; while(vertcount--) { @@ -805,13 +761,13 @@ void ZymoticTransformVerts(int vertcount, int *bonecounts, zymvertex_t *vert) } } -void ZymoticCalcNormals(int vertcount, int shadercount, int *renderlist) +void ZymoticCalcNormals(int vertcount, float *vertex, float *normals, int shadercount, int *renderlist) { int a, b, c, d; float *out, v1[3], v2[3], normal[3], s; int *u; // clear normals - memset(aliasvertnorm, 0, sizeof(float) * vertcount * 3); + memset(normals, 0, sizeof(float) * vertcount * 3); memset(aliasvertusage, 0, sizeof(int) * vertcount); // parse render list and accumulate surface normals while(shadercount--) @@ -822,36 +778,36 @@ void ZymoticCalcNormals(int vertcount, int shadercount, int *renderlist) a = renderlist[0]*4; b = renderlist[1]*4; c = renderlist[2]*4; - v1[0] = aliasvert[a+0] - aliasvert[b+0]; - v1[1] = aliasvert[a+1] - aliasvert[b+1]; - v1[2] = aliasvert[a+2] - aliasvert[b+2]; - v2[0] = aliasvert[c+0] - aliasvert[b+0]; - v2[1] = aliasvert[c+1] - aliasvert[b+1]; - v2[2] = aliasvert[c+2] - aliasvert[b+2]; + v1[0] = vertex[a+0] - vertex[b+0]; + v1[1] = vertex[a+1] - vertex[b+1]; + v1[2] = vertex[a+2] - vertex[b+2]; + v2[0] = vertex[c+0] - vertex[b+0]; + v2[1] = vertex[c+1] - vertex[b+1]; + v2[2] = vertex[c+2] - vertex[b+2]; CrossProduct(v1, v2, normal); VectorNormalizeFast(normal); // add surface normal to vertices a = renderlist[0] * 3; - aliasvertnorm[a+0] += normal[0]; - aliasvertnorm[a+1] += normal[1]; - aliasvertnorm[a+2] += normal[2]; + normals[a+0] += normal[0]; + normals[a+1] += normal[1]; + normals[a+2] += normal[2]; aliasvertusage[renderlist[0]]++; a = renderlist[1] * 3; - aliasvertnorm[a+0] += normal[0]; - aliasvertnorm[a+1] += normal[1]; - aliasvertnorm[a+2] += normal[2]; + normals[a+0] += normal[0]; + normals[a+1] += normal[1]; + normals[a+2] += normal[2]; aliasvertusage[renderlist[1]]++; a = renderlist[2] * 3; - aliasvertnorm[a+0] += normal[0]; - aliasvertnorm[a+1] += normal[1]; - aliasvertnorm[a+2] += normal[2]; + normals[a+0] += normal[0]; + normals[a+1] += normal[1]; + normals[a+2] += normal[2]; aliasvertusage[renderlist[2]]++; renderlist += 3; } } // FIXME: precalc this // average surface normals - out = aliasvertnorm; + out = normals; u = aliasvertusage; while(vertcount--) { @@ -869,7 +825,7 @@ void ZymoticCalcNormals(int vertcount, int shadercount, int *renderlist) void R_DrawZymoticModelMeshCallback (const void *calldata1, int calldata2) { - float fog, colorscale; + float fog, ifog, colorscale; vec3_t diff; int i, *renderlist, *elements; zymtype1header_t *m; @@ -909,12 +865,7 @@ void R_DrawZymoticModelMeshCallback (const void *calldata1, int calldata2) // 1. render model as normal, scaled by inverse of fog alpha (darkens it) // 2. render fog as additive } - - ZymoticLerpBones(m->numbones, (zymbonematrix *)(m->lump_poses.start + (int) m), ent->frameblend, (zymbone_t *)(m->lump_bones.start + (int) m)); - ZymoticTransformVerts(numverts, (int *)(m->lump_vertbonecounts.start + (int) m), (zymvertex_t *)(m->lump_verts.start + (int) m)); - ZymoticCalcNormals(numverts, m->numshaders, (int *)(m->lump_render.start + (int) m)); - - R_LightModel(ent, numverts, 1 - fog, 1 - fog, 1 - fog, false); + ifog = 1 - fog; memset(&mstate, 0, sizeof(mstate)); if (ent->effects & EF_ADDITIVE) @@ -940,13 +891,14 @@ void R_DrawZymoticModelMeshCallback (const void *calldata1, int calldata2) } mstate.tex[0] = R_GetTexture(texture); R_Mesh_State(&mstate); - - c_alias_polys += numtriangles; - memcpy(varray_vertex, aliasvert, numverts * sizeof(float[4])); - R_ModulateColors(aliasvertcolor, varray_color, numverts, colorscale, colorscale, colorscale); + ZymoticLerpBones(m->numbones, (zymbonematrix *)(m->lump_poses.start + (int) m), ent->frameblend, (zymbone_t *)(m->lump_bones.start + (int) m)); + ZymoticTransformVerts(numverts, varray_vertex, (int *)(m->lump_vertbonecounts.start + (int) m), (zymvertex_t *)(m->lump_verts.start + (int) m)); + ZymoticCalcNormals(numverts, varray_vertex, aliasvertnorm, m->numshaders, (int *)(m->lump_render.start + (int) m)); memcpy(varray_texcoord[0], (float *)(m->lump_texcoords.start + (int) m), numverts * sizeof(float[2])); GL_UseColorArray(); + R_LightModel(ent, numverts, varray_vertex, aliasvertnorm, varray_color, ifog * colorscale, ifog * colorscale, ifog * colorscale, false); R_Mesh_Draw(numverts, numtriangles, elements); + c_alias_polys += numtriangles; if (fog) { @@ -956,12 +908,9 @@ void R_DrawZymoticModelMeshCallback (const void *calldata1, int calldata2) // FIXME: need alpha mask for fogging... //mstate.tex[0] = R_GetTexture(texture); R_Mesh_State(&mstate); - - c_alias_polys += numtriangles; - memcpy(varray_vertex, aliasvert, numverts * sizeof(float[4])); - //memcpy(mesh_texcoord[0], (float *)(m->lump_texcoords.start + (int) m), numverts * sizeof(float[2])); GL_Color(fogcolor[0] * r_colorscale, fogcolor[1] * r_colorscale, fogcolor[2] * r_colorscale, ent->alpha * fog); R_Mesh_Draw(numverts, numtriangles, elements); + c_alias_polys += numtriangles; } } diff --git a/gl_rmain.c b/gl_rmain.c index 184af307..7ab983c1 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -460,7 +460,6 @@ static void R_MarkEntities (void) VectorAdd(ent->angles, r_refdef.viewangles, ent->angles); } - ent->visframe = r_framecount; VectorCopy(ent->angles, v); if (!ent->model || ent->model->type != mod_brush) v[0] = -v[0]; @@ -468,9 +467,11 @@ static void R_MarkEntities (void) Matrix4x4_Invert_Simple(&ent->inversematrix, &ent->matrix); R_LerpAnimation(ent); R_UpdateEntLights(ent); - if (R_CullBox(ent->mins, ent->maxs)) - continue; - R_FarClip_Box(ent->mins, ent->maxs); + if (R_NotCulledBox(ent->mins, ent->maxs)) + { + ent->visframe = r_framecount; + R_FarClip_Box(ent->mins, ent->maxs); + } } } @@ -549,12 +550,12 @@ void R_DrawFakeShadows (void) int i; entity_render_t *ent; - if (!r_drawentities.integer) - return; - ent = &cl_entities[0].render; if (ent->model && ent->model->DrawFakeShadow) ent->model->DrawFakeShadow(ent); + + if (!r_drawentities.integer) + return; for (i = 0;i < r_refdef.numentities;i++) { ent = r_refdef.entities[i]; @@ -563,6 +564,204 @@ void R_DrawFakeShadows (void) } } +void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float lightradius, int visiblevolume) +{ + int i; + vec3_t p, p2, temp, relativelightorigin; + float dist, projectdistance; + // rough checks + if (ent->model && ent->model->DrawShadowVolume) + { + temp[0] = bound(ent->mins[0], lightorigin[0], ent->maxs[0]) - lightorigin[0]; + temp[1] = bound(ent->mins[1], lightorigin[1], ent->maxs[1]) - lightorigin[1]; + temp[2] = bound(ent->mins[2], lightorigin[2], ent->maxs[2]) - lightorigin[2]; + dist = DotProduct(temp, temp); + if (dist < lightradius * lightradius) + { + projectdistance = lightradius - sqrt(dist); + { +#if 0 + int d0, d1, d2, d3; + // calculate projected bounding box and decide if it is on-screen + d0 = false; + d1 = false; + d2 = false; + d3 = false; + for (i = 0;i < 8;i++) + { + p[0] = i & 1 ? ent->maxs[0] : ent->mins[0]; + p[1] = i & 2 ? ent->maxs[1] : ent->mins[1]; + p[2] = i & 4 ? ent->maxs[2] : ent->mins[2]; + VectorSubtract(p, lightorigin, temp); + dist = projectdistance / sqrt(DotProduct(temp, temp)); + VectorMA(p, dist, temp, p2); + if (!d0 && (DotProduct(p , frustum[0].normal) < frustum[0].dist || DotProduct(p2, frustum[0].normal) < frustum[0].dist)) + d0 = true; + if (!d1 && (DotProduct(p , frustum[1].normal) < frustum[1].dist || DotProduct(p2, frustum[1].normal) < frustum[1].dist)) + d1 = true; + if (!d2 && (DotProduct(p , frustum[2].normal) < frustum[2].dist || DotProduct(p2, frustum[2].normal) < frustum[2].dist)) + d2 = true; + if (!d3 && (DotProduct(p , frustum[3].normal) < frustum[3].dist || DotProduct(p2, frustum[3].normal) < frustum[3].dist)) + d3 = true; + } + if (d0 && d1 && d2 && d3) +#else + vec3_t mins, maxs; + // calculate projected bounding box and decide if it is on-screen + VectorCopy(ent->mins, mins); + VectorCopy(ent->maxs, maxs); + for (i = 0;i < 8;i++) + { + p[0] = i & 1 ? ent->maxs[0] : ent->mins[0]; + p[1] = i & 2 ? ent->maxs[1] : ent->mins[1]; + p[2] = i & 4 ? ent->maxs[2] : ent->mins[2]; + VectorSubtract(p, lightorigin, temp); + dist = projectdistance / sqrt(DotProduct(temp, temp)); + VectorMA(p, dist, temp, p2); + if (mins[0] > p2[0]) mins[0] = p2[0];if (maxs[0] < p2[0]) maxs[0] = p2[0]; + if (mins[1] > p2[1]) mins[1] = p2[1];if (maxs[1] < p2[1]) maxs[1] = p2[1]; + if (mins[2] > p2[2]) mins[2] = p2[2];if (maxs[2] < p2[2]) maxs[2] = p2[2]; + } + if (R_NotCulledBox(mins, maxs)) +#endif + { + Matrix4x4_Transform(&ent->inversematrix, lightorigin, relativelightorigin); + R_Mesh_Matrix(&ent->matrix); + ent->model->DrawShadowVolume (ent, relativelightorigin, lightradius, visiblevolume); + } + } + } + } +} + +void R_DrawWorldLightShadowVolume(mlight_t *sl) +{ + shadowmesh_t *mesh; + R_Mesh_Matrix(&cl_entities[0].render.matrix); + for (mesh = sl->shadowvolume;mesh;mesh = mesh->next) + { + memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4])); + R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->elements); + } +} + +void R_DrawShadowVolumes (void) +{ + int i, lnum; + entity_render_t *ent; + vec3_t mins, maxs;//, relativelightorigin; + mlight_t *sl; + rdlight_t *rd; + rmeshstate_t m; + + for (lnum = 0, sl = cl.worldmodel->lights;lnum < cl.worldmodel->numlights;lnum++, sl++) + { + if (d_lightstylevalue[sl->style] <= 0) + continue; + mins[0] = sl->origin[0] - sl->cullradius; + maxs[0] = sl->origin[0] + sl->cullradius; + mins[1] = sl->origin[1] - sl->cullradius; + maxs[1] = sl->origin[1] + sl->cullradius; + mins[2] = sl->origin[2] - sl->cullradius; + maxs[2] = sl->origin[2] + sl->cullradius; + if (R_CullBox(mins, maxs)) + continue; + memset(&m, 0, sizeof(m)); + m.blendfunc1 = GL_ONE; + m.blendfunc2 = GL_ONE; + R_Mesh_State(&m); + GL_Color(0.0 * r_colorscale, 0.0125 * r_colorscale, 0.1 * r_colorscale, 1); + if (sl->shadowvolume) + R_DrawWorldLightShadowVolume(sl); + else + { + ent = &cl_entities[0].render; + R_TestAndDrawShadowVolume(ent, sl->origin, sl->cullradius, true); + } + /* + ent = &cl_entities[0].render; + if (ent->model && ent->model->DrawShadowVolume && ent->maxs[0] >= mins[0] && ent->mins[0] <= maxs[0] && ent->maxs[1] >= mins[1] && ent->mins[1] <= maxs[1] && ent->maxs[2] >= mins[2] && ent->mins[2] <= maxs[2]) + { + Matrix4x4_Transform(&ent->inversematrix, sl->origin, relativelightorigin); + R_Mesh_Matrix(&ent->matrix); + ent->model->DrawShadowVolume (ent, relativelightorigin, sl->cullradius, true); + } + */ + if (r_drawentities.integer) + { + for (i = 0;i < r_refdef.numentities;i++) + { + ent = r_refdef.entities[i]; + /* + if (ent->mins[0] <= sl->maxs[0] + && ent->maxs[0] >= sl->mins[0] + && ent->mins[1] <= sl->maxs[1] + && ent->maxs[1] >= sl->mins[1] + && ent->mins[2] <= sl->maxs[2] + && ent->maxs[2] >= sl->mins[2]) + */ + R_TestAndDrawShadowVolume(ent, sl->origin, sl->cullradius, true); + /* + ent = r_refdef.entities[i]; + if (ent->model && ent->model->DrawShadowVolume && ent->maxs[0] >= mins[0] && ent->mins[0] <= maxs[0] && ent->maxs[1] >= mins[1] && ent->mins[1] <= maxs[1] && ent->maxs[2] >= mins[2] && ent->mins[2] <= maxs[2]) + { + Matrix4x4_Transform(&ent->inversematrix, sl->origin, relativelightorigin); + R_Mesh_Matrix(&ent->matrix); + ent->model->DrawShadowVolume (ent, relativelightorigin, sl->cullradius, true); + } + */ + } + } + } + + for (lnum = 0, rd = r_dlight;lnum < r_numdlights;lnum++, rd++) + { + mins[0] = rd->origin[0] - rd->cullradius; + maxs[0] = rd->origin[0] + rd->cullradius; + mins[1] = rd->origin[1] - rd->cullradius; + maxs[1] = rd->origin[1] + rd->cullradius; + mins[2] = rd->origin[2] - rd->cullradius; + maxs[2] = rd->origin[2] + rd->cullradius; + if (R_CullBox(mins, maxs)) + continue; + memset(&m, 0, sizeof(m)); + m.blendfunc1 = GL_ONE; + m.blendfunc2 = GL_ONE; + R_Mesh_State(&m); + GL_Color(0.1 * r_colorscale, 0.0125 * r_colorscale, 0.0 * r_colorscale, 1); + ent = &cl_entities[0].render; + if (ent != rd->ent) + R_TestAndDrawShadowVolume(ent, rd->origin, rd->cullradius, true); + /* + ent = &cl_entities[0].render; + if (ent != rd->ent && ent->model && ent->model->DrawShadowVolume && ent->maxs[0] >= mins[0] && ent->mins[0] <= maxs[0] && ent->maxs[1] >= mins[1] && ent->mins[1] <= maxs[1] && ent->maxs[2] >= mins[2] && ent->mins[2] <= maxs[2]) + { + Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin); + R_Mesh_Matrix(&ent->matrix); + ent->model->DrawShadowVolume (ent, relativelightorigin, rd->cullradius, true); + } + */ + if (r_drawentities.integer) + { + for (i = 0;i < r_refdef.numentities;i++) + { + ent = r_refdef.entities[i]; + if (ent != rd->ent) + R_TestAndDrawShadowVolume(ent, rd->origin, rd->cullradius, true); + /* + ent = r_refdef.entities[i]; + if (ent != rd->ent && ent->model && ent->model->DrawShadowVolume && ent->maxs[0] >= mins[0] && ent->mins[0] <= maxs[0] && ent->maxs[1] >= mins[1] && ent->mins[1] <= maxs[1] && ent->maxs[2] >= mins[2] && ent->mins[2] <= maxs[2]) + { + Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin); + R_Mesh_Matrix(&ent->matrix); + ent->model->DrawShadowVolume (ent, relativelightorigin, rd->cullradius, true); + } + */ + } + } + } +} + static void R_SetFrustum (void) { int i; @@ -718,11 +917,16 @@ void R_RenderView (void) R_MeshQueue_Render(); R_MeshQueue_EndScene(); - if (r_shadows.integer) + if (r_shadows.integer == 1) { R_DrawFakeShadows(); R_TimeReport("fakeshadows"); } + if (r_shadows.integer == 2) + { + R_DrawShadowVolumes(); + R_TimeReport("shadowvolumes"); + } R_Mesh_Finish(); R_TimeReport("meshfinish"); } diff --git a/gl_rsurf.c b/gl_rsurf.c index 37e048cc..b6c80518 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -1830,8 +1830,23 @@ 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) +void R_DrawBrushModelShadowVolume (entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume) { +#if 0 + float projectdistance, temp[3]; + shadowmesh_t *mesh; + VectorSubtract(relativelightorigin, ent->model->shadowmesh_center, temp); + projectdistance = lightradius + ent->model->shadowmesh_radius - sqrt(DotProduct(temp, temp)); + if (projectdistance >= 0.1) + { + for (mesh = ent->model->shadowmesh;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, relativelightorigin, lightradius, projectdistance, visiblevolume); + } + } +#else int i, numsurfaces; msurface_t *surf; float projectdistance, f, temp[3], lightradius2; @@ -1840,30 +1855,29 @@ void R_DrawBrushModelShadowVolumes (entity_render_t *ent, vec3_t relativelightor 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 + projectdistance = lightradius + f; + if (projectdistance >= 0.1 && projectdistance < lightradius) { - f = PlaneDiff(relativelightorigin, surf->plane); - if (surf->flags & SURF_PLANEBACK) - f = -f; - // draw shadows only for backfaces - if (f < 0) + VectorSubtract(relativelightorigin, surf->poly_center, temp); + if (DotProduct(temp, temp) < (surf->poly_radius2 + lightradius2)) { - projectdistance = lightradius + f; - if (projectdistance > 0) + for (mesh = surf->mesh;mesh;mesh = mesh->chain) { - 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, varray_vertex, mesh->index, mesh->triangleneighbors, relativelightorigin, projectdistance, visiblevolume); - } + 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->index, mesh->triangleneighbors, relativelightorigin, lightradius, projectdistance, visiblevolume); } } } } +#endif } +/* extern cvar_t r_shadows; void R_DrawBrushModelFakeShadow (entity_render_t *ent) { @@ -1872,6 +1886,7 @@ void R_DrawBrushModelFakeShadow (entity_render_t *ent) rmeshstate_t m; mlight_t *sl; rdlight_t *rd; + svbspmesh_t *mesh; if (r_shadows.integer < 2) return; @@ -1882,18 +1897,35 @@ void R_DrawBrushModelFakeShadow (entity_render_t *ent) 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) + if (0)//ent->model == cl.worldmodel) + { + for (i = 0, sl = cl.worldmodel->lights;i < cl.worldmodel->numlights;i++, sl++) + { + if (d_lightstylevalue[sl->style] > 0 && R_NotCulledBox(sl->shadowvolumemins, sl->shadowvolumemaxs)) + { + for (mesh = sl->shadowvolume;mesh;mesh = mesh->next) + { + memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4])); + R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->elements); + } + } + } + } + else + { + for (i = 0, sl = cl.worldmodel->lights;i < cl.worldmodel->numlights;i++, sl++) { - Matrix4x4_Transform(&ent->inversematrix, sl->origin, relativelightorigin); - R_DrawBrushModelShadowVolumes (ent, relativelightorigin, sl->cullradius, true); + 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_DrawBrushModelShadowVolume (ent, relativelightorigin, sl->cullradius, true); + } } } for (i = 0, rd = r_dlight;i < r_numdlights;i++, rd++) @@ -1906,10 +1938,11 @@ void R_DrawBrushModelFakeShadow (entity_render_t *ent) && ent->mins[2] <= rd->origin[2] + rd->cullradius) { Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin); - R_DrawBrushModelShadowVolumes (ent, relativelightorigin, rd->cullradius, true); + R_DrawBrushModelShadowVolume (ent, relativelightorigin, rd->cullradius, true); } } } +*/ static void gl_surf_start(void) { diff --git a/model_alias.c b/model_alias.c index b848772a..bcf3959b 100644 --- a/model_alias.c +++ b/model_alias.c @@ -248,6 +248,7 @@ static int Mod_LoadInternalSkin (char *basename, qbyte *skindata, qbyte *skintem #define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)\n", loadmodel->name, VALUE, MIN, MAX); #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)\n", loadmodel->name, VALUE, MIN, MAX); +extern void R_DrawQ1Q2AliasModelShadowVolume (entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume); void Mod_LoadAliasModel (model_t *mod, void *buffer) { int i, j, version, numverts, totalposes, totalskins, skinwidth, skinheight, totalverts, groupframes, groupskins; @@ -530,6 +531,7 @@ void Mod_LoadAliasModel (model_t *mod, void *buffer) loadmodel->Draw = R_DrawQ1Q2AliasModel; loadmodel->DrawSky = NULL; loadmodel->DrawFakeShadow = R_DrawQ1Q2AliasModelFakeShadow; + loadmodel->DrawShadowVolume = R_DrawQ1Q2AliasModelShadowVolume; loadmodel->mdlmd2data_triangleneighbors = Mem_Alloc(loadmodel->mempool, loadmodel->numtris * sizeof(int[3])); Mod_BuildTriangleNeighbors(loadmodel->mdlmd2data_triangleneighbors, loadmodel->mdlmd2data_indices, loadmodel->numtris); diff --git a/model_brush.c b/model_brush.c index 28347fc6..fa85dc6c 100644 --- a/model_brush.c +++ b/model_brush.c @@ -426,6 +426,8 @@ static void Mod_LoadTextures (lump_t *l) else { tx->flags |= SURF_LIGHTMAP; + if (!tx->fogtexture) + tx->flags |= SURF_CLIPSOLID; tx->shader = &Cshader_wall_lightmap; } @@ -662,61 +664,853 @@ void Mod_LoadLightList(void) } } + + +/* +// svbspmesh_t is in model_brush.h + +typedef struct svbsppolygon_s +{ + struct svbsppolygon_s *next; + int numverts; + float *verts; + float normal[3], dist; +} +svbsppolygon_t; + +typedef struct svbspnode_s +{ + // true if this is a leaf (has no children), not a node + int isleaf; + // (shared) parent node + struct svbspnode_s *parent; + // (leaf) dark or lit leaf + int dark; + // (leaf) polygons bounding this leaf + svbsppolygon_t *polygons; + // (node) children + struct svbspnode_s *children[2]; + // (node) splitting plane + float normal[3], dist; +} +svbspnode_t; + +svbspnode_t *Mod_SVBSP_AllocNode(svbspnode_t *parent, svbspnode_t *child0, svbspnode_t *child1, float *normal, float dist) +{ + svbspnode_t *node; + node = Mem_Alloc(loadmodel->mempool, sizeof(svbspnode_t)); + node->parent = parent; + node->children[0] = child0; + node->children[1] = child1; + VectorCopy(normal, node->normal); + node->dist = dist; + return node; +} + +svbspnode_t *Mod_SVBSP_AllocLeaf(svbspnode_t *parent, int dark) +{ + svbspnode_t *leaf; + leaf = Mem_Alloc(loadmodel->mempool, sizeof(svbspnode_t)); + leaf->isleaf = true; + leaf->parent = parent; + leaf->dark = dark; + return leaf; +} + +svbspnode_t *Mod_SVBSP_NewTree(void) +{ + return Mod_SVBSP_AllocLeaf(NULL, false); +} + +void Mod_SVBSP_FreeTree(svbspnode_t *node) +{ + if (!node->isleaf) + { + Mod_SVBSP_FreeTree(node->children[0]); + Mod_SVBSP_FreeTree(node->children[1]); + } + Mem_Free(node); +} + +void Mod_SVBSP_RecursiveAddPolygon(svbspnode_t *node, int numverts, float *verts, float *normal, float dist, int constructmode) +{ + int i, j, numvertsfront, numvertsback, maxverts, counts[3]; + float *vertsfront, *vertsback, *v, d, temp[3]; + float dists[4096]; + qbyte sides[4096]; + svbsppolygon_t *poly; + if (node->isleaf) + { + if (constructmode == 0) + { + // construct tree structure + node->isleaf = false; + node->children[0] = Mod_SVBSP_AllocLeaf(node, false); + node->children[1] = Mod_SVBSP_AllocLeaf(node, false); + VectorCopy(normal, node->normal); + node->dist = dist; + } + else if (constructmode == 1) + { + // mark dark leafs + node->dark = true; + } + else + { + // link polygons into lit leafs only (this is the optimization) + if (!node->dark) + { + poly = Mem_Alloc(loadmodel->mempool, sizeof(svbsppolygon_t) + numverts * sizeof(float[3])); + poly->numverts = numverts; + poly->verts = (float *)(poly + 1); + VectorCopy(normal, poly->normal); + poly->dist = dist; + memcpy(poly->verts, verts, numverts * sizeof(float[3])); + poly->next = node->polygons; + node->polygons = poly; + } + } + } + else + { + counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0; + for (i = 0, v = verts;i < numverts;i++, v += 3) + { + dists[i] = DotProduct(v, node->normal) - node->dist; + if (dists[i] >= 0.1) + sides[i] = SIDE_FRONT; + else if (dists[i] <= -0.1) + sides[i] = SIDE_BACK; + else + sides[i] = SIDE_ON; + counts[sides[i]]++; + } + if (counts[SIDE_FRONT] && counts[SIDE_BACK]) + { + // some front, some back... sliced + numvertsfront = 0; + numvertsback = 0; + // this is excessive, but nice for safety... + maxverts = numverts + 4; + vertsfront = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3])); + vertsback = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3])); + for (i = 0, j = numverts - 1;i < numverts;j = i, i++) + { + if (sides[j] == SIDE_FRONT) + { + VectorCopy(&verts[j * 3], &vertsfront[numvertsfront * 3]); + numvertsfront++; + if (sides[i] == SIDE_BACK) + { + d = dists[j] / (dists[j] - dists[i]); + VectorSubtract(&verts[i * 3], &verts[j * 3], temp); + VectorMA(&verts[j * 3], d, temp, temp); + VectorCopy(temp, &vertsfront[numvertsfront * 3]); + VectorCopy(temp, &vertsback[numvertsback * 3]); + numvertsfront++; + numvertsback++; + } + } + else if (sides[j] == SIDE_BACK) + { + VectorCopy(&verts[j * 3], &vertsback[numvertsback * 3]); + numvertsback++; + if (sides[i] == SIDE_FRONT) + { + d = dists[j] / (dists[j] - dists[i]); + VectorSubtract(&verts[i * 3], &verts[j * 3], temp); + VectorMA(&verts[j * 3], d, temp, temp); + VectorCopy(temp, &vertsfront[numvertsfront * 3]); + VectorCopy(temp, &vertsback[numvertsback * 3]); + numvertsfront++; + numvertsback++; + } + } + else + { + VectorCopy(&verts[j * 3], &vertsfront[numvertsfront * 3]); + VectorCopy(&verts[j * 3], &vertsback[numvertsback * 3]); + numvertsfront++; + numvertsback++; + } + } + Mod_SVBSP_RecursiveAddPolygon(node->children[1], numvertsfront, vertsfront, normal, dist, constructmode); + Mod_SVBSP_RecursiveAddPolygon(node->children[0], numvertsback, vertsback, normal, dist, constructmode); + Mem_Free(vertsfront); + Mem_Free(vertsback); + } + else if (counts[SIDE_BACK]) + Mod_SVBSP_RecursiveAddPolygon(node->children[0], numverts, verts, normal, dist, constructmode); + else if (counts[SIDE_FRONT]) + Mod_SVBSP_RecursiveAddPolygon(node->children[1], numverts, verts, normal, dist, constructmode); + else + { + // mode 0 is constructing tree, don't make unnecessary splits + if (constructmode == 1) + { + // marking dark leafs + // send it down the side it is not facing + Mod_SVBSP_RecursiveAddPolygon(node->children[DotProduct(node->normal, normal) < 0], numverts, verts, normal, dist, constructmode); + } + else if (constructmode == 2) + { + // linking polygons into lit leafs only + // send it down the side it is facing + Mod_SVBSP_RecursiveAddPolygon(node->children[DotProduct(node->normal, normal) >= 0], numverts, verts, normal, dist, constructmode); + } + } + } +} + +int svbsp_count_nodes; +int svbsp_count_leafs; +int svbsp_count_polygons; +int svbsp_count_darkleafs; +int svbsp_count_originalpolygons; +int svbsp_count_meshs; +int svbsp_count_triangles; +int svbsp_count_vertices; + +void Mod_SVBSP_AddPolygon(svbspnode_t *root, int numverts, float *verts, int constructmode, float *test, int linenumber) +{ + int i; + float normal[3], dist, dir0[3], dir1[3], *v0, *v1, *v2; + svbsp_count_originalpolygons++; + for (i = 0, v0 = verts + (numverts - 2) * 3, v1 = verts + (numverts - 1) * 3, v2 = verts;i < numverts;i++, v0 = v1, v1 = v2, v2 += 3) + { + VectorSubtract(v0, v1, dir0); + VectorSubtract(v2, v1, dir1); + CrossProduct(dir0, dir1, normal); + if (DotProduct(normal, normal) >= 0.1) + break; + } + if (i == numverts) + return; + VectorNormalize(normal); + dist = DotProduct(verts, normal); + if (test && DotProduct(test, normal) > dist + 0.1) + Con_Printf("%i %f %f %f %f : %f %f %f %f\n", linenumber, normal[0], normal[1], normal[2], dist, test[0], test[1], test[2], DotProduct(test, normal)); + Mod_SVBSP_RecursiveAddPolygon(root, numverts, verts, normal, dist, constructmode); +} + +void Mod_SVBSP_RecursiveGatherStats(svbspnode_t *node) +{ + svbsppolygon_t *poly; + for (poly = node->polygons;poly;poly = poly->next) + svbsp_count_polygons++; + if (node->isleaf) + { + svbsp_count_leafs++; + if (node->dark) + svbsp_count_darkleafs++; + } + else + { + svbsp_count_nodes++; + Mod_SVBSP_RecursiveGatherStats(node->children[0]); + Mod_SVBSP_RecursiveGatherStats(node->children[1]); + } +} + +svbspmesh_t *Mod_SVBSP_AllocMesh(int maxverts) +{ + svbspmesh_t *mesh; + mesh = Mem_Alloc(loadmodel->mempool, sizeof(svbspmesh_t) + maxverts * sizeof(float[4]) + maxverts * sizeof(int[3])); + mesh->maxverts = maxverts; + mesh->maxtriangles = maxverts; + mesh->numverts = 0; + mesh->numtriangles = 0; + mesh->verts = (float *)(mesh + 1); + mesh->elements = (int *)(mesh->verts + mesh->maxverts * 4); + return mesh; +} + +svbspmesh_t *Mod_SVBSP_ReAllocMesh(svbspmesh_t *oldmesh) +{ + svbspmesh_t *newmesh; + newmesh = Mem_Alloc(loadmodel->mempool, sizeof(svbspmesh_t) + oldmesh->numverts * sizeof(float[4]) + oldmesh->numtriangles * sizeof(int[3])); + newmesh->maxverts = newmesh->numverts = oldmesh->numverts; + newmesh->maxtriangles = newmesh->numtriangles = oldmesh->numtriangles; + newmesh->verts = (float *)(newmesh + 1); + newmesh->elements = (int *)(newmesh->verts + newmesh->maxverts * 4); + memcpy(newmesh->verts, oldmesh->verts, newmesh->numverts * sizeof(float[4])); + memcpy(newmesh->elements, oldmesh->elements, newmesh->numtriangles * sizeof(int[3])); + return newmesh; +} + +void Mod_SVBSP_RecursiveBuildTriangleMeshs(svbspmesh_t *firstmesh, svbspnode_t *node) +{ + svbsppolygon_t *poly; + svbspmesh_t *mesh; + int i, j, k; + float *v, *m, temp[3]; + if (node->isleaf) + { + for (poly = node->polygons;poly;poly = poly->next) + { + mesh = firstmesh; + while (poly->numverts + mesh->numverts > mesh->maxverts || (poly->numverts - 2) + mesh->numtriangles > mesh->maxtriangles) + { + if (mesh->next == NULL) + mesh->next = Mod_SVBSP_AllocMesh(max(1000, poly->numverts)); + mesh = mesh->next; + } + for (i = 0, v = poly->verts;i < poly->numverts - 2;i++, v += 3) + { + for (k = 0;k < 3;k++) + { + if (k == 0) + v = poly->verts; + else if (k == 1) + v = poly->verts + (i + 1) * 3; + else if (k == 2) + v = poly->verts + (i + 2) * 3; + for (j = 0, m = mesh->verts;j < mesh->numverts;j++, m += 4) + { + VectorSubtract(v, m, temp); + if (DotProduct(temp, temp) < 0.1) + break; + } + if (j == mesh->numverts) + { + mesh->numverts++; + VectorCopy(v, m); + } + mesh->elements[mesh->numtriangles * 3 + k] = j; + } + mesh->numtriangles++; + } + } + } + else + { + Mod_SVBSP_RecursiveBuildTriangleMeshs(firstmesh, node->children[0]); + Mod_SVBSP_RecursiveBuildTriangleMeshs(firstmesh, node->children[1]); + } +} + +svbspmesh_t *Mod_SVBSP_BuildTriangleMeshs(svbspnode_t *root, vec3_t mins, vec3_t maxs) +{ + svbspmesh_t *firstmesh, *mesh, *newmesh, *nextmesh; + int i; + float *v; + firstmesh = Mod_SVBSP_AllocMesh(1000); + Mod_SVBSP_RecursiveBuildTriangleMeshs(firstmesh, root); + // reallocate meshs to conserve space + for (mesh = firstmesh, firstmesh = NULL;mesh;mesh = nextmesh) + { + svbsp_count_meshs++; + svbsp_count_triangles += mesh->numtriangles; + svbsp_count_vertices += mesh->numverts; + + // calculate bbox + if (firstmesh == NULL) + { + VectorCopy(mesh->verts, mins); + VectorCopy(mesh->verts, maxs); + } + for (i = 0, v = mesh->verts;i < mesh->numverts;i++, v += 4) + { + if (mins[0] > v[0]) mins[0] = v[0];if (maxs[0] < v[0]) maxs[0] = v[0]; + if (mins[1] > v[1]) mins[1] = v[1];if (maxs[1] < v[1]) maxs[1] = v[1]; + if (mins[2] > v[2]) mins[2] = v[2];if (maxs[2] < v[2]) maxs[2] = v[2]; + } + + nextmesh = mesh->next; + newmesh = Mod_SVBSP_ReAllocMesh(mesh); + newmesh->next = firstmesh; + firstmesh = newmesh; + Mem_Free(mesh); + } + return firstmesh; +} + +void Mod_SVBSP_FreeTriangleMeshs(svbspmesh_t *mesh) +{ + svbspmesh_t *nextmesh; + for (;mesh;mesh = nextmesh) + { + nextmesh = mesh->next; + Mem_Free(mesh); + } +} +*/ + +typedef struct svpolygon_s +{ + struct svpolygon_s *next; + int maxverts; + int numverts; + float *verts; + float normal[3], dist; +} +svpolygon_t; + +typedef struct svbrush_s +{ + struct svbrush_s *next; + svpolygon_t *polygons; + vec3_t mins, maxs; +} +svbrush_t; + +typedef struct svworld_s +{ + svbrush_t *brushs; +} +svworld_t; + +svworld_t *Mod_ShadowBrush_NewWorld(mempool_t *mempool) +{ + return Mem_Alloc(mempool, sizeof(svworld_t)); +} + +void Mod_ShadowBrush_FreeWorld(svworld_t *world) +{ + svbrush_t *brush, *brushnext; + svpolygon_t *poly, *polynext; + for (brush = world->brushs;brush;brush = brushnext) + { + brushnext = brush->next; + for (poly = brush->polygons;poly;poly = polynext) + { + polynext = poly->next; + Mem_Free(poly); + } + Mem_Free(brush); + } + Mem_Free(world); +} + +svbrush_t *Mod_ShadowBrush_BeginBrush(mempool_t *mempool) +{ + return Mem_Alloc(mempool, sizeof(svbrush_t)); +} + +void Mod_ShadowBrush_AddPolygon(mempool_t *mempool, svbrush_t *brush, int numverts, float *verts) +{ + int i; + float normal[3], dist, dir0[3], dir1[3], *v0, *v1, *v2; + svpolygon_t *poly; + for (i = 0, v0 = verts + (numverts - 2) * 3, v1 = verts + (numverts - 1) * 3, v2 = verts;i < numverts;i++, v0 = v1, v1 = v2, v2 += 3) + { + VectorSubtract(v0, v1, dir0); + VectorSubtract(v2, v1, dir1); + CrossProduct(dir0, dir1, normal); + if (DotProduct(normal, normal) >= 0.1) + break; + } + if (i == numverts) + return; + VectorNormalize(normal); + dist = DotProduct(verts, normal); + + poly = Mem_Alloc(mempool, sizeof(svpolygon_t) + numverts * sizeof(float[3])); + poly->numverts = numverts; + poly->verts = (float *)(poly + 1); + VectorCopy(normal, poly->normal); + poly->dist = dist; + poly->next = brush->polygons; + brush->polygons = poly; + memcpy(poly->verts, verts, numverts * sizeof(float[3])); +} + +void Mod_ShadowBrush_EndBrush(svworld_t *world, svbrush_t *brush) +{ + int i; + float *v; + svpolygon_t *poly; + if (!brush->polygons) + { + Mem_Free(brush); + return; + } + brush->next = world->brushs; + world->brushs = brush; + VectorCopy(brush->polygons->verts, brush->mins); + VectorCopy(brush->polygons->verts, brush->maxs); + for (poly = brush->polygons;poly;poly = poly->next) + { + for (i = 0, v = poly->verts;i < poly->numverts;i++, v += 3) + { + if (brush->mins[0] > v[0]) brush->mins[0] = v[0];if (brush->maxs[0] < v[0]) brush->maxs[0] = v[0]; + if (brush->mins[1] > v[1]) brush->mins[1] = v[1];if (brush->maxs[1] < v[1]) brush->maxs[1] = v[1]; + if (brush->mins[2] > v[2]) brush->mins[2] = v[2];if (brush->maxs[2] < v[2]) brush->maxs[2] = v[2]; + } + } +} + +void Mod_ShadowBrush_ProcessWorld(mempool_t *mempool, svworld_t *world) +{ + /* + for (clipbrush = world->brushs;clipbrush;clipbrush = clipbrush->next) + { + for (brush = world->brushs;brush;brush = brush->next) + { + if (brush != clipbrush + && brush->mins[0] <= clipbrush->maxs[0] + && brush->maxs[0] >= clipbrush->mins[0] + && brush->mins[1] <= clipbrush->maxs[1] + && brush->maxs[1] >= clipbrush->mins[1] + && brush->mins[2] <= clipbrush->maxs[2] + && brush->maxs[2] >= clipbrush->mins[2]) + continue; + for (poly = brush->polygons;poly;poly = poly->next) + { + + } + } + } + */ +} + +shadowmesh_t *Mod_ShadowBrush_BuildMeshs(mempool_t *mempool, svworld_t *world) +{ + shadowmesh_t *mesh; + svbrush_t *brush; + svpolygon_t *poly; + mesh = Mod_ShadowMesh_Begin(mempool); + for (brush = world->brushs;brush;brush = brush->next) + for (poly = brush->polygons;poly;poly = poly->next) + Mod_ShadowMesh_AddPolygon(mempool, mesh, poly->numverts, poly->verts); + mesh = Mod_ShadowMesh_Finish(mempool, mesh); + return mesh; +} + void Mod_ProcessLightList(void) { - int i, j, k, *mark; + int j, k, *mark, lnum; mlight_t *e; msurface_t *surf; float dist; - mleaf_t *l; + mleaf_t *leaf; qbyte *pvs; - for (i = 0, e = loadmodel->lights;i < loadmodel->numlights;i++, e++) + for (lnum = 0, e = loadmodel->lights;lnum < loadmodel->numlights;lnum++, 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); + leaf = Mod_PointInLeaf(e->origin, loadmodel); + if (leaf->compressed_vis) + pvs = Mod_DecompressVis (leaf->compressed_vis, loadmodel); else pvs = mod_novis; - for (j = 0, l = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++) + for (j = 0;j < loadmodel->numsurfaces;j++) + loadmodel->surfacevisframes[j] = -1; + for (j = 0, leaf = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++, leaf++) { if (pvs[j >> 3] & (1 << (j & 7))) { - for (k = 0, mark = l->firstmarksurface;k < l->nummarksurfaces;k++, mark++) + for (k = 0, mark = leaf->firstmarksurface;k < leaf->nummarksurfaces;k++, mark++) { surf = loadmodel->surfaces + *mark; + if (surf->number != *mark) + Con_Printf("%d != %d\n", surf->number, *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; + loadmodel->surfacevisframes[*mark] = -2; } } } + // build list of light receiving surfaces e->numsurfaces = 0; - for (j = 0;j < loadmodel->nummodelsurfaces;j++) - if (loadmodel->surfacevisframes[j] == i - 1000000) + for (j = 0;j < loadmodel->numsurfaces;j++) + if (loadmodel->surfacevisframes[j] == -2) 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; + for (j = 0;j < loadmodel->numsurfaces;j++) + if (loadmodel->surfacevisframes[j] == -2) + e->surfaces[e->numsurfaces++] = loadmodel->surfaces + j; } + /* + { + // find bounding box and sphere of lit surfaces + float *v, temp[3], radius2; + radius2 = 0; + for (j = 0;j < e->numsurfaces;j++) + { + surf = e->surfaces[j]; + if (j == 0) + { + VectorCopy(surf->poly_verts, e->mins); + VectorCopy(surf->poly_verts, e->maxs); + } + for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3) + { + if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0]; + if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1]; + if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2]; + VectorSubtract(v, e->origin, temp); + dist = DotProduct(temp, temp); + if (radius2 < dist) + radius2 = dist; + } + } + if (e->cullradius2 > radius2) + { + e->cullradius2 = radius2; + e->cullradius = sqrt(e->cullradius2); + } + } + */ +#if 1 + // clip shadow volumes against eachother to remove unnecessary + // polygons (and sections of polygons) + { + svworld_t *svworld; + float f; + float temp[3]; + float *verts = NULL; + svbrush_t *svbrush; + float *v0; + float projectdistance; + int maxverts = 0; + float *v1; + svworld = Mod_ShadowBrush_NewWorld(loadmodel->mempool); + for (j = 0, surf = loadmodel->surfaces + loadmodel->firstmodelsurface;j < loadmodel->nummodelsurfaces;j++, surf++) + { + if (!(surf->flags & SURF_CLIPSOLID)) + continue; + f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist; + if (surf->flags & SURF_PLANEBACK) + f = -f; + projectdistance = e->cullradius + f; + if (projectdistance < 0.1 || projectdistance > e->cullradius) + continue; + VectorSubtract(e->origin, surf->poly_center, temp); + if (DotProduct(temp, temp) > (surf->poly_radius2 + e->cullradius2)) + continue; + if (maxverts < surf->poly_numverts) + { + maxverts = surf->poly_numverts; + if (verts) + Mem_Free(verts); + verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3])); + } + svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool); + // copy the original polygon, reversed, for the front 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) + VectorCopy(v0, v1); + Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, surf->poly_numverts, verts); + // project the original polygon, for the back cap of the volume + for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3) + { + VectorSubtract(v0, e->origin, temp); + VectorNormalize(temp); + VectorMA(v0, projectdistance, temp, v1); + } + Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, surf->poly_numverts, verts); + // project the shadow volume sides + for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;k++, v0 = v1, v1 += 3) + { + 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]); + Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + } + Mod_ShadowBrush_EndBrush(svworld, svbrush); + } + e->shadowvolume = Mod_ShadowBrush_BuildMeshs(loadmodel->mempool, svworld); + Mod_ShadowBrush_FreeWorld(svworld); + } +#elif 0 + // build svbsp (shadow volume bsp) + { + int maxverts = 0, constructmode; + float *verts = NULL, projectdistance, *v0, *v1, f, temp[3]; + svbspnode_t *svbsproot; + svbsproot = Mod_SVBSP_NewTree(); + // we do this in three stages: + // 1. construct the svbsp structure + // 2. mark which leafs are dark (shadow) + // 3. link polygons into only leafs that are not dark + // this results in polygons that are only on the outside of the + // shadow volume, removing polygons that are inside the shadow + // volume (which waste time) + for (constructmode = 0;constructmode < 3;constructmode++) + { + svbsp_count_originalpolygons = 0; +#if 1 + for (j = 0, surf = loadmodel->surfaces + loadmodel->firstmodelsurface;j < loadmodel->nummodelsurfaces;j++, surf++) + { + if (!(surf->flags & SURF_CLIPSOLID)) + continue; + /* + if (surf->poly_maxs[0] < e->mins[0] + || surf->poly_mins[0] > e->maxs[0] + || surf->poly_maxs[1] < e->mins[1] + || surf->poly_mins[1] > e->maxs[1] + || surf->poly_maxs[2] < e->mins[2] + || surf->poly_mins[2] > e->maxs[2]) + continue; + */ + f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist; + if (surf->flags & SURF_PLANEBACK) + f = -f; + projectdistance = e->cullradius + f; + if (projectdistance < 0.1 || projectdistance > e->cullradius) + continue; + /* + // find the nearest vertex of the projected volume + for (k = 0, v0 = surf->poly_verts;k < surf->poly_numverts;k++, v0 += 3) + { + VectorSubtract(v0, e->origin, temp); + VectorNormalize(temp); + if (maxdist00 > v0[0] - e->origin[0]) maxdist00 = v0[0] - e->origin[0]; + if (maxdist01 < e->origin[0] - v0[0]) maxdist01 = e->origin[0] - v0[0]; + if (maxdist10 > v0[1] - e->origin[1]) maxdist10 = v0[1] - e->origin[1]; + if (maxdist11 < e->origin[1] - v0[1]) maxdist11 = e->origin[1] - v0[1]; + if (maxdist20 > v0[2] - e->origin[2]) maxdist20 = v0[2] - e->origin[2]; + if (maxdist21 < e->origin[2] - v0[2]) maxdist21 = e->origin[2] - v0[2]; + dist = + + dist = DotProduct(temp, temp); + if (bestdist > dist) + { + bestdist = dist; + VectorCopy(temp, bestvec); + } + } + projectdistance = e->cullradius - sqrt(bestdist); + if (projectdistance < 0.1) + continue; + for (k = 0, v0 = surf->poly_verts;k < surf->poly_numverts;k++, v0 += 3) + { + VectorNormalize(temp); + if (temp[0] > 0) + { + dist = (e->maxs[0] - e->origin[0]) / temp[0]; + if (maxdist > + } + else if (temp[0] < 0) + dist = (e->mins[0] - e->origin[0]) / temp[0]; + dist = + VectorMA(v0, projectdistance, temp, temp); + dist = (temp[0] + VectorSubtract(temp, e->origin, + } + */ + VectorSubtract(e->origin, surf->poly_center, temp); + if (DotProduct(temp, temp) > (surf->poly_radius2 + e->cullradius2)) + continue; + if (maxverts < surf->poly_numverts) + { + maxverts = surf->poly_numverts; + if (verts) + Mem_Free(verts); + verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3])); + } + // copy the original polygon, reversed, for the front 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) + VectorCopy(v0, v1); + Mod_SVBSP_AddPolygon(svbsproot, surf->poly_numverts, verts, constructmode, surf->poly_center, __LINE__); + // project the original polygon, for the back cap of the volume + for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3) + { + VectorSubtract(v0, e->origin, temp); + VectorNormalize(temp); + VectorMA(v0, projectdistance, temp, v1); + } + Mod_SVBSP_AddPolygon(svbsproot, surf->poly_numverts, verts, constructmode, surf->poly_center, __LINE__); + // project the shadow volume sides + for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;k++, v0 = v1, v1 += 3) + { + 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]); + Mod_SVBSP_AddPolygon(svbsproot, 4, verts, constructmode, surf->poly_center, __LINE__); + } + } +#else + for (j = 0;j < e->numsurfaces;j++) + { + surf = e->surfaces[j]; + if (!(surf->flags & SURF_CLIPSOLID)) + continue; + f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist; + if (surf->flags & SURF_PLANEBACK) + f = -f; + projectdistance = e->cullradius - f; + if (projectdistance < 0.1 || projectdistance > e->cullradius) + continue; + VectorSubtract(e->origin, surf->poly_center, temp); + if (DotProduct(temp, temp) > (surf->poly_radius2 + e->cullradius2)) + continue; + if (maxverts < surf->poly_numverts) + { + maxverts = surf->poly_numverts; + if (verts) + Mem_Free(verts); + verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3])); + } + // 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_SVBSP_AddPolygon(svbsproot, surf->poly_numverts, verts, constructmode, surf->poly_center, __LINE__); + // 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_SVBSP_AddPolygon(svbsproot, surf->poly_numverts, verts, constructmode, surf->poly_center, __LINE__); + // project the shadow volume sides + for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;k++, v0 = v1, v1 += 3) + { + 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]); + Mod_SVBSP_AddPolygon(svbsproot, 4, verts, constructmode, surf->poly_center, __LINE__); + } + } +#endif + } + if (verts) + Mem_Free(verts); + + svbsp_count_nodes = 0; + svbsp_count_leafs = 0; + svbsp_count_polygons = 0; + svbsp_count_darkleafs = 0; + svbsp_count_meshs = 0; + svbsp_count_triangles = 0; + svbsp_count_vertices = 0; + e->shadowvolume = Mod_SVBSP_BuildTriangleMeshs(svbsproot, e->shadowvolumemins, e->shadowvolumemaxs); + Mod_SVBSP_RecursiveGatherStats(svbsproot); + Mod_SVBSP_FreeTree(svbsproot); + Con_Printf("light %d (radius %d) has %d surfaces, svbsp contains %d nodes, %d leafs, %d are dark (%d%%), %d original polygons, %d polygons stored (%d%%), %d meshs %d vertices %d triangles\n", lnum, (int)e->cullradius, e->numsurfaces, svbsp_count_nodes, svbsp_count_leafs, svbsp_count_darkleafs, svbsp_count_leafs ? (100 * svbsp_count_darkleafs / svbsp_count_leafs) : 0, svbsp_count_originalpolygons, svbsp_count_polygons, svbsp_count_originalpolygons ? (100 * svbsp_count_polygons / svbsp_count_originalpolygons) : 0, svbsp_count_meshs, svbsp_count_triangles, svbsp_count_vertices); + } +#endif } - // construct shadow volumes for each light - /* - for (i = 0, e = loadmodel->lights;i < loadmodel->numlights;i++, e++) - { - FIXME FINISH THIS CODE! - } - */ } @@ -1168,7 +1962,7 @@ void Mod_GenerateWarpMesh (msurface_t *surf) void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly) { - int i, iu, iv, *index, *n, smax, tmax; + int i, iu, iv, *index, smax, tmax; float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3]; surfmesh_t *mesh; @@ -1215,16 +2009,13 @@ void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly) 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; } + Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles); VectorCopy(surf->plane->normal, normal); if (surf->flags & SURF_PLANEBACK) @@ -1261,7 +2052,7 @@ void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly) void Mod_GenerateVertexMesh (msurface_t *surf) { - int i, *index, *n; + int i, *index; float *in, s, t, normal[3]; surfmesh_t *mesh; @@ -1279,16 +2070,13 @@ void Mod_GenerateVertexMesh (msurface_t *surf) 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; } + Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles); VectorCopy(surf->plane->normal, normal); if (surf->flags & SURF_PLANEBACK) @@ -2431,7 +3219,7 @@ static void Mod_MakePortals(void) Mod_LoadBrushModel ================= */ -extern void R_DrawBrushModelFakeShadow (entity_render_t *ent); +extern void R_DrawBrushModelShadowVolume (entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume); void Mod_LoadBrushModel (model_t *mod, void *buffer) { int i, j; @@ -2521,45 +3309,56 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) mod->nummodelsurfaces = bm->numfaces; mod->DrawSky = NULL; - // LordHavoc: calculate bmodel bounding box rather than trusting what it says - for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++) + if (mod->nummodelsurfaces) { - // we only need to have a drawsky function if it is used (usually only on world model) - if (surf->texinfo->texture->shader == &Cshader_sky) - mod->DrawSky = R_DrawBrushModelSky; - for (k = 0;k < surf->numedges;k++) + // LordHavoc: calculate bmodel bounding box rather than trusting what it says + for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++) { - l = mod->surfedges[k + surf->firstedge]; - if (l > 0) - vec = mod->vertexes[mod->edges[l].v[0]].position; - else - vec = mod->vertexes[mod->edges[-l].v[1]].position; - if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0]; - if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1]; - if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2]; - if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0]; - if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1]; - if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2]; - dist = vec[0]*vec[0]+vec[1]*vec[1]; - if (modelyawradius < dist) - modelyawradius = dist; - dist += vec[2]*vec[2]; - if (modelradius < dist) - modelradius = dist; + // we only need to have a drawsky function if it is used (usually only on world model) + if (surf->texinfo->texture->shader == &Cshader_sky) + mod->DrawSky = R_DrawBrushModelSky; + for (k = 0;k < surf->numedges;k++) + { + l = mod->surfedges[k + surf->firstedge]; + if (l > 0) + vec = mod->vertexes[mod->edges[l].v[0]].position; + else + vec = mod->vertexes[mod->edges[-l].v[1]].position; + if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0]; + if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1]; + if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2]; + if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0]; + if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1]; + if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2]; + dist = vec[0]*vec[0]+vec[1]*vec[1]; + if (modelyawradius < dist) + modelyawradius = dist; + dist += vec[2]*vec[2]; + if (modelradius < dist) + modelradius = dist; + } } + modelyawradius = sqrt(modelyawradius); + modelradius = sqrt(modelradius); + mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius); + mod->yawmins[2] = mod->normalmins[2]; + mod->yawmaxs[2] = mod->normalmaxs[2]; + mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius; + mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius; + mod->radius = modelradius; + mod->radius2 = modelradius * modelradius; + // LordHavoc: build triangle meshs for entire model's geometry + // (only used for shadow volumes) + mod->shadowmesh = Mod_ShadowMesh_Begin(originalloadmodel->mempool); + for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++) + if (surf->flags & SURF_CLIPSOLID) + Mod_ShadowMesh_AddPolygon(originalloadmodel->mempool, mod->shadowmesh, surf->poly_numverts, surf->poly_verts); + mod->shadowmesh = Mod_ShadowMesh_Finish(originalloadmodel->mempool, mod->shadowmesh); + Mod_ShadowMesh_CalcBBox(mod->shadowmesh, mod->shadowmesh_mins, mod->shadowmesh_maxs, mod->shadowmesh_center, &mod->shadowmesh_radius); } - modelyawradius = sqrt(modelyawradius); - modelradius = sqrt(modelradius); - mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius); - mod->yawmins[2] = mod->normalmins[2]; - mod->yawmaxs[2] = mod->normalmaxs[2]; - mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius; - mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius; - mod->radius = modelradius; - mod->radius2 = modelradius * modelradius; - // LordHavoc: check for empty submodels (lacrima.bsp has such a glitch) - if (mod->normalmins[0] > mod->normalmaxs[0] || mod->normalmins[1] > mod->normalmaxs[1] || mod->normalmins[2] > mod->normalmaxs[2]) + else { + // LordHavoc: empty submodel (lacrima.bsp has such a glitch) Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname); VectorClear(mod->normalmins); VectorClear(mod->normalmaxs); @@ -2569,12 +3368,14 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) VectorClear(mod->rotatedmaxs); mod->radius = 0; mod->radius2 = 0; + mod->shadowmesh = NULL; } mod->numleafs = bm->visleafs; mod->Draw = R_DrawBrushModelNormal; - mod->DrawFakeShadow = R_DrawBrushModelFakeShadow; + mod->DrawFakeShadow = NULL; + mod->DrawShadowVolume = R_DrawBrushModelShadowVolume; // LordHavoc: only register submodels if it is the world // (prevents bsp models from replacing world submodels) diff --git a/model_brush.h b/model_brush.h index 8424b538..7a8e1d0c 100644 --- a/model_brush.h +++ b/model_brush.h @@ -301,14 +301,15 @@ typedef struct mportal_s } mportal_t; -typedef struct mlightshadowvolumemesh_s +typedef struct svbspmesh_s { - struct mlightshadowvolumemesh_s *next; - int numverts; - int numtris; - float *vertex; + struct svbspmesh_s *next; + int numverts, maxverts; + int numtriangles, maxtriangles; + float *verts; + int *elements; } -mlightshadowvolumemesh_t; +svbspmesh_t; typedef struct mlight_s { @@ -334,10 +335,12 @@ typedef struct mlight_s // surfaces this shines on int numsurfaces; msurface_t **surfaces; + // lit area + //vec3_t mins, maxs; // precomputed shadow volume meshs - mlightshadowvolumemesh_t *shadowvolumemeshs; - // used only for loading calculations, number of leafs this shines on - //int numleafs; + //svbspmesh_t *shadowvolume; + //vec3_t shadowvolumemins, shadowvolumemaxs; + shadowmesh_t *shadowvolume; } mlight_t; diff --git a/model_shared.c b/model_shared.c index a2ac48e6..8506945e 100644 --- a/model_shared.c +++ b/model_shared.c @@ -408,3 +408,153 @@ void Mod_BuildTriangleNeighbors(int *neighbors, int *elements, int numtriangles) n[2] = Mod_FindTriangleWithEdge(elements, numtriangles, e[0], e[2]); } } + +shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts) +{ + shadowmesh_t *mesh; + mesh = Mem_Alloc(mempool, sizeof(shadowmesh_t) + maxverts * sizeof(float[4]) + maxverts * sizeof(int[3]) + maxverts * sizeof(int[3])); + mesh->maxverts = maxverts; + mesh->maxtriangles = maxverts; + mesh->numverts = 0; + mesh->numtriangles = 0; + mesh->verts = (float *)(mesh + 1); + mesh->elements = (int *)(mesh->verts + mesh->maxverts * 4); + mesh->neighbors = (int *)(mesh->elements + mesh->maxtriangles * 3); + return mesh; +} + +shadowmesh_t *Mod_ShadowMesh_ReAlloc(mempool_t *mempool, shadowmesh_t *oldmesh) +{ + shadowmesh_t *newmesh; + newmesh = Mem_Alloc(mempool, sizeof(shadowmesh_t) + oldmesh->numverts * sizeof(float[4]) + oldmesh->numtriangles * sizeof(int[3]) + oldmesh->numtriangles * sizeof(int[3])); + newmesh->maxverts = newmesh->numverts = oldmesh->numverts; + newmesh->maxtriangles = newmesh->numtriangles = oldmesh->numtriangles; + newmesh->verts = (float *)(newmesh + 1); + newmesh->elements = (int *)(newmesh->verts + newmesh->maxverts * 4); + newmesh->neighbors = (int *)(newmesh->elements + newmesh->maxtriangles * 3); + 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])); + return newmesh; +} + +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) + { + VectorSubtract(v, m, temp); + if (DotProduct(temp, temp) < 0.1) + return j; + } + mesh->numverts++; + VectorCopy(v, m); + return j; +} + +void Mod_ShadowMesh_AddPolygon(mempool_t *mempool, shadowmesh_t *mesh, int numverts, float *verts) +{ + int i, i1, i2, i3; + float *v; + while (numverts + mesh->numverts > mesh->maxverts || (numverts - 2) + mesh->numtriangles > mesh->maxtriangles) + { + if (mesh->next == NULL) + mesh->next = Mod_ShadowMesh_Alloc(mempool, max(1000, numverts)); + mesh = mesh->next; + } + i1 = Mod_ShadowMesh_AddVertex(mesh, verts); + i2 = 0; + i3 = Mod_ShadowMesh_AddVertex(mesh, verts + 3); + for (i = 0, v = verts + 6;i < numverts - 2;i++, v += 3) + { + i2 = i3; + i3 = Mod_ShadowMesh_AddVertex(mesh, v); + mesh->elements[mesh->numtriangles * 3 + 0] = i1; + mesh->elements[mesh->numtriangles * 3 + 1] = i2; + mesh->elements[mesh->numtriangles * 3 + 2] = i3; + mesh->numtriangles++; + } +} + +shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool) +{ + return Mod_ShadowMesh_Alloc(mempool, 1000); +} + +shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh) +{ + int i; + shadowmesh_t *mesh, *newmesh, *nextmesh; + // reallocate meshs to conserve space + for (mesh = firstmesh, firstmesh = NULL;mesh;mesh = nextmesh) + { + nextmesh = mesh->next; + newmesh = Mod_ShadowMesh_ReAlloc(mempool, mesh); + newmesh->next = firstmesh; + firstmesh = newmesh; + Mem_Free(mesh); + 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_BuildTriangleNeighbors(newmesh->neighbors, newmesh->elements, newmesh->numtriangles); + } + return firstmesh; +} + +void Mod_ShadowMesh_CalcBBox(shadowmesh_t *firstmesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius) +{ + int i; + shadowmesh_t *mesh; + vec3_t nmins, nmaxs, ncenter, temp; + float nradius2, dist2, *v; + // calculate bbox + for (mesh = firstmesh;mesh;mesh = mesh->next) + { + if (mesh == firstmesh) + { + VectorCopy(mesh->verts, nmins); + VectorCopy(mesh->verts, nmaxs); + } + for (i = 0, v = mesh->verts;i < mesh->numverts;i++, v += 4) + { + if (nmins[0] > v[0]) nmins[0] = v[0];if (nmaxs[0] < v[0]) nmaxs[0] = v[0]; + if (nmins[1] > v[1]) nmins[1] = v[1];if (nmaxs[1] < v[1]) nmaxs[1] = v[1]; + if (nmins[2] > v[2]) nmins[2] = v[2];if (nmaxs[2] < v[2]) nmaxs[2] = v[2]; + } + } + // calculate center and radius + ncenter[0] = (nmins[0] + nmaxs[0]) * 0.5f; + ncenter[1] = (nmins[1] + nmaxs[1]) * 0.5f; + ncenter[2] = (nmins[2] + nmaxs[2]) * 0.5f; + nradius2 = 0; + for (mesh = firstmesh;mesh;mesh = mesh->next) + { + for (i = 0, v = mesh->verts;i < mesh->numverts;i++, v += 4) + { + VectorSubtract(v, ncenter, temp); + dist2 = DotProduct(temp, temp); + if (nradius2 < dist2) + nradius2 = dist2; + } + } + // return data + if (mins) + VectorCopy(nmins, mins); + if (maxs) + VectorCopy(nmaxs, maxs); + if (center) + VectorCopy(ncenter, center); + if (radius) + *radius = sqrt(nradius2); +} + +void Mod_ShadowMesh_Free(shadowmesh_t *mesh) +{ + shadowmesh_t *nextmesh; + for (;mesh;mesh = nextmesh) + { + nextmesh = mesh->next; + Mem_Free(mesh); + } +} diff --git a/model_shared.h b/model_shared.h index c58b2383..998e0284 100644 --- a/model_shared.h +++ b/model_shared.h @@ -58,6 +58,17 @@ skinframe_t; #define MAX_SKINS 256 +typedef struct shadowmesh_s +{ + struct shadowmesh_s *next; + int numverts, maxverts; + int numtriangles, maxtriangles; + float *verts; + int *elements; + int *neighbors; +} +shadowmesh_t; + #include "model_brush.h" #include "model_sprite.h" @@ -176,6 +187,11 @@ typedef struct model_s int numlights; mlight_t *lights; + // used only for casting dynamic shadow volumes + shadowmesh_t *shadowmesh; + vec3_t shadowmesh_mins, shadowmesh_maxs, shadowmesh_center; + float shadowmesh_radius; + // skin animation info animscene_t *skinscenes; // [numskins] // skin frame info @@ -202,6 +218,8 @@ typedef struct model_s void(*DrawSky)(struct entity_render_s *ent); // draw a fake shadow for the model void(*DrawFakeShadow)(struct entity_render_s *ent); + // draw a shadow volume for the model based on light source + void(*DrawShadowVolume)(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume); // memory pool for allocations mempool_t *mempool; @@ -241,5 +259,14 @@ extern char loadname[32]; // for hunk tags int Mod_FindTriangleWithEdge(int *elements, int numtriangles, int start, int end); void Mod_BuildTriangleNeighbors(int *neighbors, int *elements, int numtriangles); +shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts); +shadowmesh_t *Mod_ShadowMesh_ReAlloc(mempool_t *mempool, shadowmesh_t *oldmesh); +int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, float *v); +void Mod_ShadowMesh_AddPolygon(mempool_t *mempool, shadowmesh_t *mesh, int numverts, float *verts); +shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool); +shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh); +void Mod_ShadowMesh_CalcBBox(shadowmesh_t *firstmesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius); +void Mod_ShadowMesh_Free(shadowmesh_t *mesh); + #endif // __MODEL__ diff --git a/model_sprite.c b/model_sprite.c index 10260751..28ddbd3d 100644 --- a/model_sprite.c +++ b/model_sprite.c @@ -247,6 +247,7 @@ void Mod_LoadSpriteModel (model_t *mod, void *buffer) loadmodel->Draw = R_DrawSpriteModel; loadmodel->DrawSky = NULL; loadmodel->DrawFakeShadow = NULL; + loadmodel->DrawShadowVolume = NULL; version = LittleLong(((dsprite_t *)buffer)->version); if (version == SPRITE_VERSION || SPRITE32_VERSION) diff --git a/r_light.c b/r_light.c index b06f3cb9..3424cdd5 100644 --- a/r_light.c +++ b/r_light.c @@ -667,7 +667,7 @@ void R_ModelLightPoint (const entity_render_t *ent, vec3_t color, const vec3_t p RecursiveLightPoint (color, cl.worldmodel->nodes, p[0], p[1], p[2], p[2] - 65536); } -void R_LightModel(const entity_render_t *ent, int numverts, float colorr, float colorg, float colorb, int worldcoords) +void R_LightModel(const entity_render_t *ent, int numverts, float *vertices, float *normals, float *colors, float colorr, float colorg, float colorb, int worldcoords) { int i, j, nearlights = 0, maxnearlights = r_modellights.integer; float color[3], basecolor[3], v[3], t, *av, *avn, *avc, a, f, dist2, mscale, dot, stylescale, intensity, ambientcolor[3]; @@ -825,11 +825,11 @@ void R_LightModel(const entity_render_t *ent, int numverts, float colorr, float basecolor[0] *= colorr; basecolor[1] *= colorg; basecolor[2] *= colorb; - avc = aliasvertcolor; + avc = colors; if (nearlights) { - av = aliasvert; - avn = aliasvertnorm; + av = vertices; + avn = normals; for (i = 0;i < numverts;i++) { VectorCopy(basecolor, color); diff --git a/r_light.h b/r_light.h index 0a3b5d8e..c09e26fa 100644 --- a/r_light.h +++ b/r_light.h @@ -21,7 +21,7 @@ void R_AnimateLight(void); void R_MarkLights(entity_render_t *ent); void R_DrawCoronas(void); void R_CompleteLightPoint(vec3_t color, const vec3_t p, int dynamic, const mleaf_t *leaf); -void R_LightModel(const entity_render_t *ent, int numverts, float colorr, float colorg, float colorb, int worldcoords); +void R_LightModel(const entity_render_t *ent, int numverts, float *vertices, float *normals, float *colors, float colorr, float colorg, float colorb, int worldcoords); void R_UpdateEntLights(entity_render_t *ent); #endif diff --git a/r_shadow.c b/r_shadow.c index aebace17..ee32a61b 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -36,10 +36,15 @@ void R_Shadow_Init(void) R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap); } -void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, int *neighbors, vec3_t relativelightorigin, float projectdistance, int visiblevolume) +void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance, int visiblevolume) { int i, *e, *n, *out, tris; float *v0, *v1, *v2, temp[3], f; + if (projectdistance < 0.1) + { + Con_Printf("R_Shadow_Volume: projectdistance %f\n"); + return; + } // terminology: // // frontface: @@ -84,8 +89,15 @@ void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, in for (i = 0, v0 = vertex, v1 = vertex + numverts * 4;i < numverts;i++, v0 += 4, v1 += 4) { VectorSubtract(v0, relativelightorigin, temp); +#if 0 + f = lightradius / sqrt(DotProduct(temp,temp)); + if (f < 1) + f = 1; + VectorMA(relativelightorigin, f, temp, v1); +#else f = projectdistance / sqrt(DotProduct(temp,temp)); VectorMA(v0, f, temp, v1); +#endif } // check which triangles are facing the light @@ -113,7 +125,7 @@ void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, in #else // readable version { - float dir0[3], dir1[3], + float dir0[3], dir1[3]; // calculate two mostly perpendicular edge directions VectorSubtract(v0, v1, dir0); @@ -133,7 +145,6 @@ void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, in // the normal is not normalized because it is used on both sides of // the comparison, so it's magnitude does not matter trianglefacinglight[i] = DotProduct(relativelightorigin, temp) >= DotProduct(v0, temp); - } #endif } @@ -150,6 +161,7 @@ void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, in { // triangle is backface and therefore casts shadow, // output front and back caps for shadow volume +#if 1 // front cap (with flipped winding order) out[0] = e[0]; out[1] = e[2]; @@ -160,6 +172,14 @@ void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, in out[5] = e[2] + numverts; out += 6; tris += 2; +#else + // rear cap + out[0] = e[0] + numverts; + out[1] = e[1] + numverts; + out[2] = e[2] + numverts; + out += 3; + tris += 1; +#endif // check the edges if (n[0] < 0 || trianglefacinglight[n[0]]) { @@ -199,14 +219,16 @@ void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, in // draw the volume if (visiblevolume) { - qglDisable(GL_CULL_FACE); + //qglDisable(GL_CULL_FACE); R_Mesh_Draw(numverts * 2, tris, shadowelements); - qglEnable(GL_CULL_FACE); + //qglEnable(GL_CULL_FACE); } else { qglColorMask(0,0,0,0); + qglDepthMask(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); @@ -215,9 +237,11 @@ void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, in 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); + qglDepthMask(1); qglColorMask(1,1,1,1); } } diff --git a/r_shadow.h b/r_shadow.h index cef3d81b..bd3669d0 100644 --- a/r_shadow.h +++ b/r_shadow.h @@ -3,7 +3,7 @@ #define R_SHADOW_H void R_Shadow_Init(void); -void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, int *neighbors, vec3_t relativelightorigin, float projectdistance, int visiblevolume); +void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance, int visiblevolume); void R_Shadow_VertexLight(int numverts, float *vertex, 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); -- 2.39.2