#include "cl_collision.h"
#include "r_shadow.h"
-cvar_t r_quickmodels = {0, "r_quickmodels", "1"};
-
typedef struct
{
float m[3][4];
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,
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;
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)
{
// 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)
{
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
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)
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)
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;
}
}
}
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);
}
}
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)
{
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;
}
return;
}
+ */
lightdirection[0] = 0.5;
lightdirection[1] = 0.2;
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;
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--)
{
}
}
-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--)
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--)
{
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;
// 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)
}
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)
{
// 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;
}
}
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];
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);
+ }
}
}
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];
}
}
+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;
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");
}
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;
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)
{
rmeshstate_t m;
mlight_t *sl;
rdlight_t *rd;
+ svbspmesh_t *mesh;
if (r_shadows.integer < 2)
return;
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++)
&& 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)
{
#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;
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);
else
{
tx->flags |= SURF_LIGHTMAP;
+ if (!tx->fogtexture)
+ tx->flags |= SURF_CLIPSOLID;
tx->shader = &Cshader_wall_lightmap;
}
}
}
+
+
+/*
+// 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!
- }
- */
}
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;
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)
void Mod_GenerateVertexMesh (msurface_t *surf)
{
- int i, *index, *n;
+ int i, *index;
float *in, s, t, normal[3];
surfmesh_t *mesh;
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)
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;
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);
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)
}
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
{
// 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;
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);
+ }
+}
#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"
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
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;
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__
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)
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];
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);
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
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:
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
#else
// readable version
{
- float dir0[3], dir1[3],
+ float dir0[3], dir1[3];
// calculate two mostly perpendicular edge directions
VectorSubtract(v0, v1, dir0);
// 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
}
{
// 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];
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]])
{
// 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);
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);
}
}
#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);