void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light);
-extern void R_Model_Brush_DrawLightForSurfaceList(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, msurface_t **surflist, int numsurfaces, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
void R_ShadowVolumeLighting(int visiblevolumes)
{
int i;
if (!visiblevolumes)
R_Shadow_Stage_ShadowVolumes();
ent = &cl_entities[0].render;
- if (wl->shadowvolume && r_shadow_staticworldlights.integer)
- R_Shadow_DrawWorldLightShadowVolume(&ent->matrix, wl);
+ if (r_shadow_staticworldlights.integer)
+ R_Shadow_DrawStaticWorldLight_Shadow(wl, &ent->matrix);
else
R_TestAndDrawShadowVolume(ent, wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
if (r_drawentities.integer)
Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
- if (wl->numsurfaces)
- R_Model_Brush_DrawLightForSurfaceList(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, wl->surfaces, wl->numsurfaces, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
+ if (r_shadow_staticworldlights.integer)
+ R_Shadow_DrawStaticWorldLight_Light(wl, &ent->matrix, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
else
ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
}
}
}
-void R_Model_Brush_DrawLightForSurfaceList(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, msurface_t **surflist, int numsurfaces, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz)
-{
- int surfnum;
- msurface_t *surf;
- texture_t *t;
- if (ent->model == NULL)
- return;
- R_Mesh_Matrix(&ent->matrix);
- R_UpdateTextureInfo(ent);
- for (surfnum = 0;surfnum < numsurfaces;surfnum++)
- {
- surf = surflist[surfnum];
- if (surf->visframe == r_framecount)
- {
- t = surf->texinfo->texture->currentframe;
- if (t->rendertype == SURFRENDER_OPAQUE && t->flags & SURF_SHADOWLIGHT)
- {
- R_Shadow_DiffuseLighting(surf->mesh.num_vertices, surf->mesh.num_triangles, surf->mesh.data_element3i, surf->mesh.data_vertex3f, surf->mesh.data_svector3f, surf->mesh.data_tvector3f, surf->mesh.data_normal3f, surf->mesh.data_texcoordtexture2f, relativelightorigin, lightradius, lightcolor, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.base, t->skin.nmap, NULL);
- R_Shadow_SpecularLighting(surf->mesh.num_vertices, surf->mesh.num_triangles, surf->mesh.data_element3i, surf->mesh.data_vertex3f, surf->mesh.data_svector3f, surf->mesh.data_tvector3f, surf->mesh.data_normal3f, surf->mesh.data_texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.gloss, t->skin.nmap, NULL);
- }
- }
- }
-}
-
void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz)
{
int surfnum;
qglColorMask(1,1,1,1);
}
-void R_Q3BSP_DrawFace(entity_render_t *ent, q3mface_t *face)
+void R_Q3BSP_DrawFace_OpaqueWall_Pass_OpaqueGlow(entity_render_t *ent, q3mface_t *face)
+{
+ rmeshstate_t m;
+ memset(&m, 0, sizeof(m));
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ GL_DepthMask(true);
+ GL_DepthTest(true);
+ if (face->texture->skin.glow)
+ {
+ m.tex[0] = R_GetTexture(face->texture->skin.glow);
+ m.pointer_texcoord[0] = face->data_texcoordtexture2f;
+ GL_Color(1, 1, 1, 1);
+ }
+ else
+ GL_Color(0, 0, 0, 1);
+ R_Mesh_State_Texture(&m);
+ GL_VertexPointer(face->data_vertex3f);
+ R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i);
+}
+
+void R_Q3BSP_DrawFace_OpaqueWall_Pass_TextureLightmap(entity_render_t *ent, q3mface_t *face)
{
rmeshstate_t m;
+ memset(&m, 0, sizeof(m));
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ GL_DepthMask(true);
+ GL_DepthTest(true);
+ m.tex[0] = R_GetTexture(face->texture->skin.base);
+ m.pointer_texcoord[0] = face->data_texcoordtexture2f;
+ m.tex[1] = R_GetTexture(face->lightmaptexture);
+ m.pointer_texcoord[1] = face->data_texcoordlightmap2f;
+ m.texrgbscale[1] = 2;
+ GL_Color(1, 1, 1, 1);
+ R_Mesh_State_Texture(&m);
+ GL_VertexPointer(face->data_vertex3f);
+ R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i);
+}
+
+void R_Q3BSP_DrawFace_OpaqueWall_Pass_Texture(entity_render_t *ent, q3mface_t *face)
+{
+ rmeshstate_t m;
+ memset(&m, 0, sizeof(m));
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ GL_DepthMask(true);
+ GL_DepthTest(true);
+ m.tex[0] = R_GetTexture(face->texture->skin.base);
+ m.pointer_texcoord[0] = face->data_texcoordtexture2f;
+ GL_Color(1, 1, 1, 1);
+ R_Mesh_State_Texture(&m);
+ GL_VertexPointer(face->data_vertex3f);
+ R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i);
+}
+
+void R_Q3BSP_DrawFace_OpaqueWall_Pass_Lightmap(entity_render_t *ent, q3mface_t *face)
+{
+ rmeshstate_t m;
+ memset(&m, 0, sizeof(m));
+ GL_BlendFunc(GL_ONE, GL_SRC_COLOR);
+ GL_DepthMask(true);
+ GL_DepthTest(true);
+ m.tex[0] = R_GetTexture(face->lightmaptexture);
+ m.pointer_texcoord[0] = face->data_texcoordlightmap2f;
+ GL_Color(1, 1, 1, 1);
+ R_Mesh_State_Texture(&m);
+ GL_VertexPointer(face->data_vertex3f);
+ R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i);
+}
+
+void R_Q3BSP_DrawFace_OpaqueWall_Pass_Glow(entity_render_t *ent, q3mface_t *face)
+{
+ rmeshstate_t m;
+ memset(&m, 0, sizeof(m));
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+ GL_DepthMask(true);
+ GL_DepthTest(true);
+ if (face->texture->skin.glow)
+ {
+ m.tex[0] = R_GetTexture(face->texture->skin.glow);
+ m.pointer_texcoord[0] = face->data_texcoordtexture2f;
+ GL_Color(1, 1, 1, 1);
+ }
+ else
+ GL_Color(0, 0, 0, 1);
+ R_Mesh_State_Texture(&m);
+ GL_VertexPointer(face->data_vertex3f);
+ R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i);
+}
+
+void R_Q3BSP_DrawFace_OpaqueWall_Pass_TextureVertex(entity_render_t *ent, q3mface_t *face)
+{
+ rmeshstate_t m;
+ memset(&m, 0, sizeof(m));
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ GL_DepthMask(true);
+ GL_DepthTest(true);
+ m.tex[0] = R_GetTexture(face->texture->skin.base);
+ m.pointer_texcoord[0] = face->data_texcoordtexture2f;
+ m.texrgbscale[0] = 2;
+ GL_ColorPointer(face->data_color4f);
+ R_Mesh_State_Texture(&m);
+ GL_VertexPointer(face->data_vertex3f);
+ R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i);
+}
+
+void R_Q3BSP_DrawFace(entity_render_t *ent, q3mface_t *face)
+{
if (!face->num_triangles)
return;
if (face->texture->renderflags)
if (face->texture->renderflags & Q3MTEXTURERENDERFLAGS_NODRAW)
return;
}
+ if (face->texture->nativecontents & CONTENTSQ3_TRANSLUCENT)
+ qglDisable(GL_CULL_FACE);
R_Mesh_Matrix(&ent->matrix);
face->visframe = r_framecount;
- memset(&m, 0, sizeof(m));
- GL_BlendFunc(GL_ONE, GL_ZERO);
- GL_DepthMask(true);
- GL_DepthTest(true);
- m.tex[0] = R_GetTexture(face->texture->skin.base);
- m.pointer_texcoord[0] = face->data_texcoordtexture2f;
- if (face->lightmaptexture)
+ if (r_shadow_realtime_world.integer)
+ R_Q3BSP_DrawFace_OpaqueWall_Pass_OpaqueGlow(ent, face);
+ else if (face->lightmaptexture)
{
- m.tex[1] = R_GetTexture(face->lightmaptexture);
- m.pointer_texcoord[1] = face->data_texcoordlightmap2f;
- m.texrgbscale[1] = 2;
- GL_Color(1, 1, 1, 1);
+ if (r_textureunits.integer >= 2)
+ R_Q3BSP_DrawFace_OpaqueWall_Pass_TextureLightmap(ent, face);
+ else
+ {
+ R_Q3BSP_DrawFace_OpaqueWall_Pass_Texture(ent, face);
+ R_Q3BSP_DrawFace_OpaqueWall_Pass_Lightmap(ent, face);
+ }
+ if (face->texture->skin.glow)
+ R_Q3BSP_DrawFace_OpaqueWall_Pass_Glow(ent, face);
}
else
{
- m.texrgbscale[0] = 2;
- GL_ColorPointer(face->data_color4f);
+ R_Q3BSP_DrawFace_OpaqueWall_Pass_TextureVertex(ent, face);
+ if (face->texture->skin.glow)
+ R_Q3BSP_DrawFace_OpaqueWall_Pass_Glow(ent, face);
}
- R_Mesh_State_Texture(&m);
- GL_VertexPointer(face->data_vertex3f);
- R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i);
+ if (face->texture->nativecontents & CONTENTSQ3_TRANSLUCENT)
+ qglEnable(GL_CULL_FACE);
}
void R_Q3BSP_RecursiveWorldNode(entity_render_t *ent, q3mnode_t *node, const vec3_t modelorg, qbyte *pvs, int markframe)
}
-#define OPTIONS_ITEMS 32
+#define OPTIONS_ITEMS 33
int options_cursor;
extern cvar_t gl_delayfinish;
extern cvar_t slowmo;
extern dllhandle_t jpeg_dll;
+extern cvar_t gl_texture_anisotropy;
void M_Menu_Options_AdjustSliders (int dir)
{
Cvar_SetValueQuick (&gl_dither, !gl_dither.integer);
else if (options_cursor == optnum++)
Cvar_SetValueQuick (&gl_delayfinish, !gl_delayfinish.integer);
+ else if (options_cursor == optnum++)
+ Cvar_SetValueQuick (&gl_texture_anisotropy, bound(0, gl_texture_anisotropy.value + dir, 8));
else if (options_cursor == optnum++)
Cvar_SetValueQuick (&slowmo, bound(0, slowmo.value + dir * 0.25, 5));
else if (options_cursor == optnum++)
M_Options_PrintCheckbox(" Texture Combine", true, gl_combine.integer);
M_Options_PrintCheckbox(" Dithering", true, gl_dither.integer);
M_Options_PrintCheckbox("Delay gfx (faster)", true, gl_delayfinish.integer);
+ M_Options_PrintSlider( "Anisotropic Filter", gl_support_anisotropy, gl_texture_anisotropy.value, 0, 8);
M_Options_PrintSlider( " Game Speed", sv.active, slowmo.value, 0, 5);
M_Options_PrintSlider( " CD Music Volume", cdaudioinitialized, bgmvolume.value, 0, 1);
M_Options_PrintSlider( " Sound Volume", snd_initialized, volume.value, 0, 1);
// set time
*prog->time = realtime;
-
+
// call the prog init
PRVM_ExecuteProgram((func_t) (PRVM_ED_FindFunction(M_F_INIT) - prog->functions),"");
-
+
PRVM_End;
}
MR_Draw = M_Draw;
MR_ToggleMenu_f = M_ToggleMenu_f;
MR_Shutdown = M_Shutdown;
-
+
// init
if(!m_init)
{
MR_Draw = MP_Draw;
MR_ToggleMenu_f = MP_ToggleMenu_f;
MR_Shutdown = MP_Shutdown;
-
+
if(!mp_init)
{
MP_Init();
// use -forceqmenu to use always the normal quake menu (it sets forceqmenu to 1)
if(COM_CheckParm("-forceqmenu"))
Cvar_SetValueQuick(&forceqmenu,1);
- // use -useqmenu for debugging proposes, cause it starts
+ // use -useqmenu for debugging proposes, cause it starts
// the normal quake menu only the first time
else if(COM_CheckParm("-useqmenu"))
MR_SetRouting (TRUE);
else
- MR_SetRouting (FALSE);
+ MR_SetRouting (FALSE);
}
cvar_t r_nosurftextures = {0, "r_nosurftextures", "0"};
cvar_t mod_q3bsp_curves_subdivide_level = {0, "mod_q3bsp_curves_subdivide_level", "2"};
cvar_t mod_q3bsp_curves_collisions = {0, "mod_q3bsp_curves_collisions", "1"};
-cvar_t mod_q3bsp_optimizedtraceline = {0, "mod_q3bsp_optimizedtraceline", "1"};
+cvar_t mod_q3bsp_optimizedtraceline = {0, "mod_q3bsp_optimizedtraceline", "0"};
void Mod_BrushInit(void)
{
// neighboring surfaces (one per poly_numverts)
//struct msurface_s **neighborsurfaces;
// currently used only for generating static shadow volumes
- int castshadow;
+ int lighttemp_castshadow;
}
msurface_t;
VectorNormalize(v);
}
-shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts)
+shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int neighbors, int expandable)
{
- shadowmesh_t *mesh;
- mesh = Mem_Alloc(mempool, sizeof(shadowmesh_t) + maxverts * sizeof(float[3]) + maxverts * sizeof(int[3]) + maxverts * sizeof(int[3]) + SHADOWMESHVERTEXHASH * sizeof(shadowmeshvertexhash_t *) + maxverts * sizeof(shadowmeshvertexhash_t));
- mesh->maxverts = maxverts;
- mesh->maxtriangles = maxverts;
- mesh->numverts = 0;
- mesh->numtriangles = 0;
- mesh->vertex3f = (float *)(mesh + 1);
- mesh->element3i = (int *)(mesh->vertex3f + mesh->maxverts * 3);
- mesh->neighbor3i = (int *)(mesh->element3i + mesh->maxtriangles * 3);
- mesh->vertexhashtable = (shadowmeshvertexhash_t **)(mesh->neighbor3i + mesh->maxtriangles * 3);
- mesh->vertexhashentries = (shadowmeshvertexhash_t *)(mesh->vertexhashtable + SHADOWMESHVERTEXHASH);
- return mesh;
+ shadowmesh_t *newmesh;
+ qbyte *data;
+ int size;
+ size = sizeof(shadowmesh_t);
+ size += maxverts * sizeof(float[3]);
+ if (light)
+ size += maxverts * sizeof(float[11]);
+ size += maxtriangles * sizeof(int[3]);
+ if (neighbors)
+ size += maxtriangles * sizeof(int[3]);
+ if (expandable)
+ size += SHADOWMESHVERTEXHASH * sizeof(shadowmeshvertexhash_t *) + maxverts * sizeof(shadowmeshvertexhash_t);
+ data = Mem_Alloc(mempool, size);
+ newmesh = (void *)data;data += sizeof(*newmesh);
+ newmesh->map_diffuse = map_diffuse;
+ newmesh->map_specular = map_specular;
+ newmesh->map_normal = map_normal;
+ newmesh->maxverts = maxverts;
+ newmesh->maxtriangles = maxtriangles;
+ newmesh->numverts = 0;
+ newmesh->numtriangles = 0;
+
+ newmesh->vertex3f = (void *)data;data += maxverts * sizeof(float[3]);
+ if (light)
+ {
+ newmesh->svector3f = (void *)data;data += maxverts * sizeof(float[3]);
+ newmesh->tvector3f = (void *)data;data += maxverts * sizeof(float[3]);
+ newmesh->normal3f = (void *)data;data += maxverts * sizeof(float[3]);
+ newmesh->texcoord2f = (void *)data;data += maxverts * sizeof(float[2]);
+ }
+ newmesh->element3i = (void *)data;data += maxtriangles * sizeof(int[3]);
+ if (neighbors)
+ {
+ newmesh->neighbor3i = (void *)data;data += maxtriangles * sizeof(int[3]);
+ }
+ if (expandable)
+ {
+ newmesh->vertexhashtable = (void *)data;data += SHADOWMESHVERTEXHASH * sizeof(shadowmeshvertexhash_t *);
+ newmesh->vertexhashentries = (void *)data;data += maxverts * sizeof(shadowmeshvertexhash_t);
+ }
+ return newmesh;
}
-shadowmesh_t *Mod_ShadowMesh_ReAlloc(mempool_t *mempool, shadowmesh_t *oldmesh)
+shadowmesh_t *Mod_ShadowMesh_ReAlloc(mempool_t *mempool, shadowmesh_t *oldmesh, int light, int neighbors)
{
shadowmesh_t *newmesh;
- newmesh = Mem_Alloc(mempool, sizeof(shadowmesh_t) + oldmesh->numverts * sizeof(float[3]) + oldmesh->numtriangles * sizeof(int[3]) + oldmesh->numtriangles * sizeof(int[3]));
- newmesh->maxverts = newmesh->numverts = oldmesh->numverts;
- newmesh->maxtriangles = newmesh->numtriangles = oldmesh->numtriangles;
- newmesh->vertex3f = (float *)(newmesh + 1);
- newmesh->element3i = (int *)(newmesh->vertex3f + newmesh->maxverts * 3);
- newmesh->neighbor3i = (int *)(newmesh->element3i + newmesh->maxtriangles * 3);
- memcpy(newmesh->vertex3f, oldmesh->vertex3f, newmesh->numverts * sizeof(float[3]));
- memcpy(newmesh->element3i, oldmesh->element3i, newmesh->numtriangles * sizeof(int[3]));
- memcpy(newmesh->neighbor3i, oldmesh->neighbor3i, newmesh->numtriangles * sizeof(int[3]));
+ newmesh = Mod_ShadowMesh_Alloc(mempool, oldmesh->numverts, oldmesh->numtriangles, oldmesh->map_diffuse, oldmesh->map_specular, oldmesh->map_normal, light, neighbors, false);
+ newmesh->numverts = oldmesh->numverts;
+ newmesh->numtriangles = oldmesh->numtriangles;
+
+ memcpy(newmesh->vertex3f, oldmesh->vertex3f, oldmesh->numverts * sizeof(float[3]));
+ if (newmesh->svector3f && oldmesh->svector3f)
+ {
+ memcpy(newmesh->svector3f, oldmesh->svector3f, oldmesh->numverts * sizeof(float[3]));
+ memcpy(newmesh->tvector3f, oldmesh->tvector3f, oldmesh->numverts * sizeof(float[3]));
+ memcpy(newmesh->normal3f, oldmesh->normal3f, oldmesh->numverts * sizeof(float[3]));
+ memcpy(newmesh->texcoord2f, oldmesh->texcoord2f, oldmesh->numverts * sizeof(float[2]));
+ }
+ memcpy(newmesh->element3i, oldmesh->element3i, oldmesh->numtriangles * sizeof(int[3]));
+ if (newmesh->neighbor3i && oldmesh->neighbor3i)
+ memcpy(newmesh->neighbor3i, oldmesh->neighbor3i, oldmesh->numtriangles * sizeof(int[3]));
return newmesh;
}
-int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, float *v)
+int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, float *vertex14f)
{
- int hashindex;
- float *m;
+ int hashindex, vnum;
shadowmeshvertexhash_t *hash;
// this uses prime numbers intentionally
- hashindex = (int) (v[0] * 3 + v[1] * 5 + v[2] * 7) % SHADOWMESHVERTEXHASH;
+ hashindex = (int) (vertex14f[0] * 3 + vertex14f[1] * 5 + vertex14f[2] * 7) % SHADOWMESHVERTEXHASH;
for (hash = mesh->vertexhashtable[hashindex];hash;hash = hash->next)
{
- m = mesh->vertex3f + (hash - mesh->vertexhashentries) * 3;
- if (m[0] == v[0] && m[1] == v[1] && m[2] == v[2])
+ vnum = (hash - mesh->vertexhashentries);
+ if ((mesh->vertex3f == NULL || (mesh->vertex3f[vnum * 3 + 0] == vertex14f[0] && mesh->vertex3f[vnum * 3 + 1] == vertex14f[1] && mesh->vertex3f[vnum * 3 + 2] == vertex14f[2]))
+ && (mesh->svector3f == NULL || (mesh->svector3f[vnum * 3 + 0] == vertex14f[3] && mesh->svector3f[vnum * 3 + 1] == vertex14f[4] && mesh->svector3f[vnum * 3 + 2] == vertex14f[5]))
+ && (mesh->tvector3f == NULL || (mesh->tvector3f[vnum * 3 + 0] == vertex14f[6] && mesh->tvector3f[vnum * 3 + 1] == vertex14f[7] && mesh->tvector3f[vnum * 3 + 2] == vertex14f[8]))
+ && (mesh->normal3f == NULL || (mesh->normal3f[vnum * 3 + 0] == vertex14f[9] && mesh->normal3f[vnum * 3 + 1] == vertex14f[10] && mesh->normal3f[vnum * 3 + 2] == vertex14f[11]))
+ && (mesh->texcoord2f == NULL || (mesh->texcoord2f[vnum * 2 + 0] == vertex14f[12] && mesh->texcoord2f[vnum * 2 + 1] == vertex14f[13])))
return hash - mesh->vertexhashentries;
}
- hash = mesh->vertexhashentries + mesh->numverts;
+ vnum = mesh->numverts++;
+ hash = mesh->vertexhashentries + vnum;
hash->next = mesh->vertexhashtable[hashindex];
mesh->vertexhashtable[hashindex] = hash;
- m = mesh->vertex3f + (hash - mesh->vertexhashentries) * 3;
- VectorCopy(v, m);
- mesh->numverts++;
- return mesh->numverts - 1;
+ if (mesh->vertex3f) {mesh->vertex3f[vnum * 3 + 0] = vertex14f[0];mesh->vertex3f[vnum * 3 + 1] = vertex14f[1];mesh->vertex3f[vnum * 3 + 2] = vertex14f[2];}
+ if (mesh->svector3f) {mesh->svector3f[vnum * 3 + 0] = vertex14f[3];mesh->svector3f[vnum * 3 + 1] = vertex14f[4];mesh->svector3f[vnum * 3 + 2] = vertex14f[5];}
+ if (mesh->tvector3f) {mesh->tvector3f[vnum * 3 + 0] = vertex14f[6];mesh->tvector3f[vnum * 3 + 1] = vertex14f[7];mesh->tvector3f[vnum * 3 + 2] = vertex14f[8];}
+ if (mesh->normal3f) {mesh->normal3f[vnum * 3 + 0] = vertex14f[9];mesh->normal3f[vnum * 3 + 1] = vertex14f[10];mesh->normal3f[vnum * 3 + 2] = vertex14f[11];}
+ if (mesh->texcoord2f) {mesh->texcoord2f[vnum * 2 + 0] = vertex14f[12];mesh->texcoord2f[vnum * 2 + 1] = vertex14f[13];}
+ return vnum;
}
-void Mod_ShadowMesh_AddTriangle(mempool_t *mempool, shadowmesh_t *mesh, float *vert0, float *vert1, float *vert2)
+void Mod_ShadowMesh_AddTriangle(mempool_t *mempool, shadowmesh_t *mesh, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, float *vertex14f)
{
- while (mesh->numverts + 3 > mesh->maxverts || mesh->numtriangles + 1 > mesh->maxtriangles)
+ if (mesh->numtriangles == 0)
+ {
+ // set the properties on this empty mesh to be more favorable...
+ // (note: this case only occurs for the first triangle added to a new mesh chain)
+ mesh->map_diffuse = map_diffuse;
+ mesh->map_specular = map_specular;
+ mesh->map_normal = map_normal;
+ }
+ while (mesh->map_diffuse != map_diffuse || mesh->map_specular != map_specular || mesh->map_normal != map_normal || mesh->numverts + 3 > mesh->maxverts || mesh->numtriangles + 1 > mesh->maxtriangles)
{
if (mesh->next == NULL)
- mesh->next = Mod_ShadowMesh_Alloc(mempool, max(mesh->maxtriangles, 1));
+ mesh->next = Mod_ShadowMesh_Alloc(mempool, max(mesh->maxverts, 300), max(mesh->maxtriangles, 100), map_diffuse, map_specular, map_normal, mesh->svector3f != NULL, mesh->neighbor3i != NULL, true);
mesh = mesh->next;
}
- mesh->element3i[mesh->numtriangles * 3 + 0] = Mod_ShadowMesh_AddVertex(mesh, vert0);
- mesh->element3i[mesh->numtriangles * 3 + 1] = Mod_ShadowMesh_AddVertex(mesh, vert1);
- mesh->element3i[mesh->numtriangles * 3 + 2] = Mod_ShadowMesh_AddVertex(mesh, vert2);
+ mesh->element3i[mesh->numtriangles * 3 + 0] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 0);
+ mesh->element3i[mesh->numtriangles * 3 + 1] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 1);
+ mesh->element3i[mesh->numtriangles * 3 + 2] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 2);
mesh->numtriangles++;
}
-void Mod_ShadowMesh_AddPolygon(mempool_t *mempool, shadowmesh_t *mesh, int numverts, float *verts)
+void Mod_ShadowMesh_AddMesh(mempool_t *mempool, shadowmesh_t *mesh, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, float *vertex3f, float *svector3f, float *tvector3f, float *normal3f, float *texcoord2f, int numtris, int *element3i)
{
- int i;
- float *v;
- for (i = 0, v = verts + 3;i < numverts - 2;i++, v += 3)
- Mod_ShadowMesh_AddTriangle(mempool, mesh, verts, v, v + 3);
- /*
- int i, i1, i2, i3;
- float *v;
- while (mesh->num_vertices + numverts > mesh->maxverts || mesh->num_triangles + (numverts - 2) > mesh->maxtriangles)
+ int i, j, e;
+ float vbuf[3*14], *v;
+ memset(vbuf, 0, sizeof(vbuf));
+ for (i = 0;i < numtris;i++)
{
- if (mesh->next == NULL)
- mesh->next = Mod_ShadowMesh_Alloc(mempool, max(mesh->maxtriangles, 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->num_triangles * 3 + 0] = i1;
- mesh->elements[mesh->num_triangles * 3 + 1] = i2;
- mesh->elements[mesh->num_triangles * 3 + 2] = i3;
- mesh->num_triangles++;
+ for (j = 0, v = vbuf;j < 3;j++, v += 14)
+ {
+ e = *element3i++;
+ if (vertex3f)
+ {
+ v[0] = vertex3f[e * 3 + 0];
+ v[1] = vertex3f[e * 3 + 1];
+ v[2] = vertex3f[e * 3 + 2];
+ }
+ if (svector3f)
+ {
+ v[3] = svector3f[e * 3 + 0];
+ v[4] = svector3f[e * 3 + 1];
+ v[5] = svector3f[e * 3 + 2];
+ }
+ if (tvector3f)
+ {
+ v[6] = tvector3f[e * 3 + 0];
+ v[7] = tvector3f[e * 3 + 1];
+ v[8] = tvector3f[e * 3 + 2];
+ }
+ if (normal3f)
+ {
+ v[9] = normal3f[e * 3 + 0];
+ v[10] = normal3f[e * 3 + 1];
+ v[11] = normal3f[e * 3 + 2];
+ }
+ if (texcoord2f)
+ {
+ v[12] = texcoord2f[e * 2 + 0];
+ v[13] = texcoord2f[e * 2 + 1];
+ }
+ }
+ Mod_ShadowMesh_AddTriangle(mempool, mesh, map_diffuse, map_specular, map_normal, vbuf);
}
- */
-}
-
-void Mod_ShadowMesh_AddMesh(mempool_t *mempool, shadowmesh_t *mesh, float *verts, int numtris, int *elements)
-{
- int i;
- for (i = 0;i < numtris;i++, elements += 3)
- Mod_ShadowMesh_AddTriangle(mempool, mesh, verts + elements[0] * 3, verts + elements[1] * 3, verts + elements[2] * 3);
}
-shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int initialnumtriangles)
+shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int neighbors, int expandable)
{
- return Mod_ShadowMesh_Alloc(mempool, initialnumtriangles);
+ return Mod_ShadowMesh_Alloc(mempool, maxverts, maxtriangles, map_diffuse, map_specular, map_normal, light, neighbors, expandable);
}
-shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh)
+shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh, int light, int neighbors)
{
-#if 1
- //int i;
shadowmesh_t *mesh, *newmesh, *nextmesh;
// reallocate meshs to conserve space
for (mesh = firstmesh, firstmesh = NULL;mesh;mesh = nextmesh)
nextmesh = mesh->next;
if (mesh->numverts >= 3 && mesh->numtriangles >= 1)
{
- newmesh = Mod_ShadowMesh_ReAlloc(mempool, mesh);
+ newmesh = Mod_ShadowMesh_ReAlloc(mempool, mesh, light, neighbors);
newmesh->next = firstmesh;
firstmesh = newmesh;
- //Con_Printf("mesh\n");
- //for (i = 0;i < newmesh->num_triangles;i++)
- // Con_Printf("tri %d %d %d\n", newmesh->elements[i * 3 + 0], newmesh->elements[i * 3 + 1], newmesh->elements[i * 3 + 2]);
- Mod_ValidateElements(newmesh->element3i, newmesh->numtriangles, newmesh->numverts, __FILE__, __LINE__);
- Mod_BuildTriangleNeighbors(newmesh->neighbor3i, newmesh->element3i, newmesh->numtriangles);
}
Mem_Free(mesh);
}
-#else
- shadowmesh_t *mesh;
- for (mesh = firstmesh;mesh;mesh = mesh->next)
- {
- Mod_ValidateElements(mesh->elements, mesh->num_triangles, mesh->num_vertices, __FILE__, __LINE__);
- Mod_BuildTriangleNeighbors(mesh->neighbors, mesh->elements, mesh->num_triangles);
- }
-#endif
return firstmesh;
}
typedef struct shadowmesh_s
{
+ // next mesh in chain
struct shadowmesh_s *next;
+ // used for light mesh (NULL on shadow mesh)
+ rtexture_t *map_diffuse;
+ rtexture_t *map_specular;
+ rtexture_t *map_normal;
+ // buffer sizes
int numverts, maxverts;
int numtriangles, maxtriangles;
+ // used always
float *vertex3f;
+ // used for light mesh (NULL on shadow mesh)
+ float *svector3f;
+ float *tvector3f;
+ float *normal3f;
+ float *texcoord2f;
+ // used always
int *element3i;
+ // used for shadow mesh (NULL on light mesh)
int *neighbor3i;
// these are NULL after Mod_ShadowMesh_Finish is performed, only used
// while building meshes
float *data_color4f;
int *data_element3i;
int *data_neighbor3i;
+
+ // temporary use by light processing
+ int lighttemp_castshadow;
}
q3mface_t;
void Mod_ValidateElements(const int *elements, int numtriangles, int numverts, const char *filename, int fileline);
void Mod_BuildTextureVectorsAndNormals(int numverts, int numtriangles, const float *vertex, const float *texcoord, const int *elements, float *svectors, float *tvectors, float *normals);
-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_AddTriangle(mempool_t *mempool, shadowmesh_t *mesh, float *vert0, float *vert1, float *vert2);
-void Mod_ShadowMesh_AddPolygon(mempool_t *mempool, shadowmesh_t *mesh, int numverts, float *verts);
-void Mod_ShadowMesh_AddMesh(mempool_t *mempool, shadowmesh_t *mesh, float *verts, int numtris, int *elements);
-shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int initialnumtriangles);
-shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh);
+shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int neighbors, int expandable);
+shadowmesh_t *Mod_ShadowMesh_ReAlloc(mempool_t *mempool, shadowmesh_t *oldmesh, int light, int neighbors);
+int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, float *vertex14f);
+void Mod_ShadowMesh_AddTriangle(mempool_t *mempool, shadowmesh_t *mesh, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, float *vertex14f);
+void Mod_ShadowMesh_AddMesh(mempool_t *mempool, shadowmesh_t *mesh, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, float *vertex3f, float *svector3f, float *tvector3f, float *normal3f, float *texcoord2f, int numtris, int *element3i);
+shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int neighbors, int expandable);
+shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh, int light, int neighbors);
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);
cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
cvar_t r_shadow_shadows = {CVAR_SAVE, "r_shadow_shadows", "1"};
+cvar_t r_shadow_showtris = {0, "r_shadow_showtris", "0"};
int c_rt_lights, c_rt_clears, c_rt_scissored;
int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
Cvar_RegisterVariable(&r_shadow_texture3d);
Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
Cvar_RegisterVariable(&r_shadow_shadows);
+ Cvar_RegisterVariable(&r_shadow_showtris);
Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
R_Shadow_EditLights_Init();
R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
}
}
-void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light)
+void R_Shadow_DrawStaticWorldLight_Shadow(worldlight_t *light, matrix4x4_t *matrix)
{
R_Mesh_Matrix(matrix);
- R_Shadow_RenderShadowMeshVolume(light->shadowvolume);
+ if (r_shadow_showtris.integer)
+ {
+ shadowmesh_t *mesh;
+ rmeshstate_t m;
+ int depthenabled = qglIsEnabled(GL_DEPTH_TEST);
+ int stencilenabled = qglIsEnabled(GL_STENCIL_TEST);
+ qglDisable(GL_DEPTH_TEST);
+ qglDisable(GL_STENCIL_TEST);
+ //qglDisable(GL_CULL_FACE);
+ qglColorMask(1,1,1,1);
+ memset(&m, 0, sizeof(m));
+ R_Mesh_State_Texture(&m);
+ GL_Color(0,0.1,0,1);
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+ for (mesh = light->meshchain_shadow;mesh;mesh = mesh->next)
+ {
+ GL_VertexPointer(mesh->vertex3f);
+ R_Mesh_Draw_ShowTris(mesh->numverts, mesh->numtriangles, mesh->element3i);
+ }
+ //qglEnable(GL_CULL_FACE);
+ if (depthenabled)
+ qglEnable(GL_DEPTH_TEST);
+ if (stencilenabled)
+ {
+ qglEnable(GL_STENCIL_TEST);
+ qglColorMask(0,0,0,0);
+ }
+ }
+ R_Shadow_RenderShadowMeshVolume(light->meshchain_shadow);
+}
+
+void R_Shadow_DrawStaticWorldLight_Light(worldlight_t *light, matrix4x4_t *matrix, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz)
+{
+ shadowmesh_t *mesh;
+ R_Mesh_Matrix(matrix);
+ if (r_shadow_showtris.integer)
+ {
+ rmeshstate_t m;
+ int depthenabled = qglIsEnabled(GL_DEPTH_TEST);
+ int stencilenabled = qglIsEnabled(GL_STENCIL_TEST);
+ qglDisable(GL_DEPTH_TEST);
+ qglDisable(GL_STENCIL_TEST);
+ //qglDisable(GL_CULL_FACE);
+ memset(&m, 0, sizeof(m));
+ R_Mesh_State_Texture(&m);
+ GL_Color(0.2,0,0,1);
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+ for (mesh = light->meshchain_light;mesh;mesh = mesh->next)
+ {
+ GL_VertexPointer(mesh->vertex3f);
+ R_Mesh_Draw_ShowTris(mesh->numverts, mesh->numtriangles, mesh->element3i);
+ }
+ //qglEnable(GL_CULL_FACE);
+ if (depthenabled)
+ qglEnable(GL_DEPTH_TEST);
+ if (stencilenabled)
+ qglEnable(GL_STENCIL_TEST);
+ }
+ for (mesh = light->meshchain_light;mesh;mesh = mesh->next)
+ {
+ R_Shadow_DiffuseLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, lightradius, lightcolor, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, mesh->map_diffuse, mesh->map_normal, NULL);
+ R_Shadow_SpecularLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, mesh->map_specular, mesh->map_normal, NULL);
+ }
}
cvar_t r_editlights = {0, "r_editlights", "0"};
static int lightpvsbytes;
static qbyte lightpvs[(MAX_MAP_LEAFS + 7)/ 8];
-static int castshadowcount = 1;
void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style, const char *cubemapname, int castshadow)
{
- int i, j, k, l, maxverts = 256, *mark, tris, numsurfaces;
+ int i, j, k, l, maxverts = 256, tris;
float *vertex3f = NULL, mins[3], maxs[3];
worldlight_t *e;
- shadowmesh_t *mesh, *castmesh;
- mleaf_t *leaf;
- msurface_t *surf;
+ shadowmesh_t *mesh, *castmesh = NULL;
if (radius < 15 || DotProduct(color, color) < 0.03)
{
strcpy(e->cubemapname, cubemapname);
// FIXME: add cubemap loading (and don't load a cubemap twice)
}
+ // FIXME: rewrite this to store ALL geometry into a cache in the light
+ if (e->castshadows)
+ castmesh = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
+ e->meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
if (cl.worldmodel)
{
- castshadowcount++;
- VectorCopy(e->origin, e->mins);
- VectorCopy(e->origin, e->maxs);
- i = CL_PointQ1Contents(e->origin);
- if (r_shadow_portallight.integer && i != CONTENTS_SOLID && i != CONTENTS_SKY)
+ if (cl.worldmodel->brushq3.num_leafs)
{
- //qbyte *byteleafpvs;
- qbyte *bytesurfacepvs;
-
- //byteleafpvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.numleafs);
- bytesurfacepvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.numsurfaces);
-
- Portal_Visibility(cl.worldmodel, e->origin, NULL/*byteleafpvs*/, bytesurfacepvs, NULL, 0, true, mins, maxs, e->mins, e->maxs);
-
- /*
- for (i = 0, leaf = cl.worldmodel->brushq1.leafs;i < cl.worldmodel->brushq1.numleafs;i++, leaf++)
+ q3mleaf_t *leaf;
+ q3mface_t *face;
+ lightpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, origin, 0, lightpvs, sizeof(lightpvs));
+ VectorCopy(e->origin, e->mins);
+ VectorCopy(e->origin, e->maxs);
+ for (i = 0, face = cl.worldmodel->brushq3.data_thismodel->firstface;i < cl.worldmodel->brushq3.data_thismodel->numfaces;i++, face++)
+ face->lighttemp_castshadow = false;
+ for (i = 0, leaf = cl.worldmodel->brushq3.data_leafs;i < cl.worldmodel->brushq3.num_leafs;i++, leaf++)
{
- if (byteleafpvs[i] && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
+ if ((leaf->clusterindex < 0 || lightpvs[leaf->clusterindex >> 3] & (1 << (leaf->clusterindex & 7))) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
{
for (k = 0;k < 3;k++)
{
if (e->mins[k] > leaf->mins[k]) e->mins[k] = leaf->mins[k];
if (e->maxs[k] < leaf->maxs[k]) e->maxs[k] = leaf->maxs[k];
}
+ for (j = 0;j < leaf->numleaffaces;j++)
+ {
+ face = leaf->firstleafface[j];
+ if (BoxesOverlap(face->mins, face->maxs, mins, maxs))
+ face->lighttemp_castshadow = true;
+ }
}
}
- */
-
- for (i = 0, surf = cl.worldmodel->brushq1.surfaces;i < cl.worldmodel->brushq1.numsurfaces;i++, surf++)
- if (bytesurfacepvs[i] && BoxesOverlap(surf->poly_mins, surf->poly_maxs, mins, maxs))
- surf->castshadow = castshadowcount;
- //Mem_Free(byteleafpvs);
- Mem_Free(bytesurfacepvs);
- }
- else
- {
- lightpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, origin, 0, lightpvs, sizeof(lightpvs));
- for (i = 0, leaf = cl.worldmodel->brushq1.leafs + 1;i < cl.worldmodel->brushq1.visleafs;i++, leaf++)
+ // add surfaces to shadow casting mesh and light mesh
+ for (i = 0, face = cl.worldmodel->brushq3.data_thismodel->firstface;i < cl.worldmodel->brushq3.data_thismodel->numfaces;i++, face++)
{
- if (lightpvs[i >> 3] & (1 << (i & 7)) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
+ if (face->lighttemp_castshadow)
{
- for (k = 0;k < 3;k++)
- {
- if (e->mins[k] > leaf->mins[k]) e->mins[k] = leaf->mins[k];
- if (e->maxs[k] < leaf->maxs[k]) e->maxs[k] = leaf->maxs[k];
- }
- for (j = 0, mark = leaf->firstmarksurface;j < leaf->nummarksurfaces;j++, mark++)
+ face->lighttemp_castshadow = false;
+ if (!(face->texture->renderflags & (Q3MTEXTURERENDERFLAGS_NODRAW | Q3MTEXTURERENDERFLAGS_SKY)))
{
- surf = cl.worldmodel->brushq1.surfaces + *mark;
- if (surf->castshadow != castshadowcount && BoxesOverlap(surf->poly_mins, surf->poly_maxs, mins, maxs))
- surf->castshadow = castshadowcount;
+ if (e->castshadows)
+ if (!(face->texture->nativecontents & CONTENTSQ3_TRANSLUCENT))
+ Mod_ShadowMesh_AddMesh(r_shadow_mempool, castmesh, NULL, NULL, NULL, face->data_vertex3f, NULL, NULL, NULL, NULL, face->num_triangles, face->data_element3i);
+ if (!(face->texture->renderflags & (Q3MTEXTURERENDERFLAGS_SKY)))
+ Mod_ShadowMesh_AddMesh(r_shadow_mempool, e->meshchain_light, face->texture->skin.base, face->texture->skin.gloss, face->texture->skin.nmap, face->data_vertex3f, face->data_svector3f, face->data_tvector3f, face->data_normal3f, face->data_texcoordtexture2f, face->num_triangles, face->data_element3i);
}
}
}
}
-
- for (k = 0;k < 3;k++)
- {
- if (e->mins[k] < e->origin[k] - e->lightradius) e->mins[k] = e->origin[k] - e->lightradius;
- if (e->maxs[k] > e->origin[k] + e->lightradius) e->maxs[k] = e->origin[k] + e->lightradius;
- }
- e->cullradius = RadiusFromBoundsAndOrigin(e->mins, e->maxs, e->origin);
-
- numsurfaces = 0;
- for (i = 0, surf = cl.worldmodel->brushq1.surfaces + cl.worldmodel->brushq1.firstmodelsurface;i < cl.worldmodel->brushq1.nummodelsurfaces;i++, surf++)
- if (surf->castshadow == castshadowcount)
- numsurfaces++;
- if (numsurfaces)
- e->surfaces = Mem_Alloc(r_shadow_mempool, numsurfaces * sizeof(msurface_t *));
- e->numsurfaces = 0;
- for (i = 0, surf = cl.worldmodel->brushq1.surfaces + cl.worldmodel->brushq1.firstmodelsurface;i < cl.worldmodel->brushq1.nummodelsurfaces;i++, surf++)
- if (surf->castshadow == castshadowcount)
- e->surfaces[e->numsurfaces++] = surf;
-
- if (e->castshadows)
+ else if (cl.worldmodel->brushq1.numleafs)
{
- castshadowcount++;
- for (j = 0;j < e->numsurfaces;j++)
+ mleaf_t *leaf;
+ msurface_t *surf;
+ VectorCopy(e->origin, e->mins);
+ VectorCopy(e->origin, e->maxs);
+ i = CL_PointQ1Contents(e->origin);
+
+ for (i = 0, surf = cl.worldmodel->brushq1.surfaces + cl.worldmodel->brushq1.firstmodelsurface;i < cl.worldmodel->brushq1.nummodelsurfaces;i++, surf++)
+ surf->lighttemp_castshadow = false;
+
+ if (r_shadow_portallight.integer && i != CONTENTS_SOLID && i != CONTENTS_SKY)
{
- surf = e->surfaces[j];
- if (surf->flags & SURF_SHADOWCAST)
+ qbyte *byteleafpvs;
+ qbyte *bytesurfacepvs;
+
+ byteleafpvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.numleafs);
+ bytesurfacepvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.numsurfaces);
+
+ Portal_Visibility(cl.worldmodel, e->origin, byteleafpvs, bytesurfacepvs, NULL, 0, true, mins, maxs, e->mins, e->maxs);
+
+ for (i = 0, leaf = cl.worldmodel->brushq1.leafs;i < cl.worldmodel->brushq1.numleafs;i++, leaf++)
{
- surf->castshadow = castshadowcount;
- if (maxverts < surf->poly_numverts)
- maxverts = surf->poly_numverts;
+ if (byteleafpvs[i] && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
+ {
+ for (k = 0;k < 3;k++)
+ {
+ if (e->mins[k] > leaf->mins[k]) e->mins[k] = leaf->mins[k];
+ if (e->maxs[k] < leaf->maxs[k]) e->maxs[k] = leaf->maxs[k];
+ }
+ }
}
+
+ for (i = 0, surf = cl.worldmodel->brushq1.surfaces;i < cl.worldmodel->brushq1.numsurfaces;i++, surf++)
+ if (bytesurfacepvs[i] && BoxesOverlap(surf->poly_mins, surf->poly_maxs, mins, maxs))
+ surf->lighttemp_castshadow = true;
+
+ Mem_Free(byteleafpvs);
+ Mem_Free(bytesurfacepvs);
}
- e->shadowvolume = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768);
- // make a mesh to cast a shadow volume from
- castmesh = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768);
- for (j = 0;j < e->numsurfaces;j++)
- if ((surf = e->surfaces[j])->castshadow == castshadowcount)
- Mod_ShadowMesh_AddMesh(r_shadow_mempool, castmesh, surf->mesh.data_vertex3f, surf->mesh.num_triangles, surf->mesh.data_element3i);
- castmesh = Mod_ShadowMesh_Finish(r_shadow_mempool, castmesh);
-
- // cast shadow volume from castmesh
- for (mesh = castmesh;mesh;mesh = mesh->next)
+ else
{
- R_Shadow_ResizeShadowElements(castmesh->numtriangles);
+ lightpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, origin, 0, lightpvs, sizeof(lightpvs));
+ for (i = 0, leaf = cl.worldmodel->brushq1.leafs + 1;i < cl.worldmodel->brushq1.visleafs;i++, leaf++)
+ {
+ if (lightpvs[i >> 3] & (1 << (i & 7)) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
+ {
+ for (k = 0;k < 3;k++)
+ {
+ if (e->mins[k] > leaf->mins[k]) e->mins[k] = leaf->mins[k];
+ if (e->maxs[k] < leaf->maxs[k]) e->maxs[k] = leaf->maxs[k];
+ }
+ for (j = 0;j < leaf->nummarksurfaces;j++)
+ {
+ surf = cl.worldmodel->brushq1.surfaces + leaf->firstmarksurface[j];
+ if (!surf->lighttemp_castshadow && BoxesOverlap(surf->poly_mins, surf->poly_maxs, mins, maxs))
+ surf->lighttemp_castshadow = true;
+ }
+ }
+ }
+ }
- if (maxverts < castmesh->numverts * 2)
+ // add surfaces to shadow casting mesh and light mesh
+ for (i = 0, surf = cl.worldmodel->brushq1.surfaces + cl.worldmodel->brushq1.firstmodelsurface;i < cl.worldmodel->brushq1.nummodelsurfaces;i++, surf++)
+ {
+ if (surf->lighttemp_castshadow)
{
- maxverts = castmesh->numverts * 2;
- if (vertex3f)
- Mem_Free(vertex3f);
- vertex3f = NULL;
+ surf->lighttemp_castshadow = false;
+ if (e->castshadows && (surf->flags & SURF_SHADOWCAST))
+ Mod_ShadowMesh_AddMesh(r_shadow_mempool, castmesh, NULL, NULL, NULL, surf->mesh.data_vertex3f, NULL, NULL, NULL, NULL, surf->mesh.num_triangles, surf->mesh.data_element3i);
+ if (!(surf->flags & SURF_DRAWSKY))
+ Mod_ShadowMesh_AddMesh(r_shadow_mempool, e->meshchain_light, surf->texinfo->texture->skin.base, surf->texinfo->texture->skin.gloss, surf->texinfo->texture->skin.nmap, surf->mesh.data_vertex3f, surf->mesh.data_svector3f, surf->mesh.data_tvector3f, surf->mesh.data_normal3f, surf->mesh.data_texcoordtexture2f, surf->mesh.num_triangles, surf->mesh.data_element3i);
}
- if (vertex3f == NULL && maxverts > 0)
- vertex3f = Mem_Alloc(r_shadow_mempool, maxverts * sizeof(float[3]));
+ }
+ }
+ }
+
+ // limit box to light bounds (in case it grew larger)
+ for (k = 0;k < 3;k++)
+ {
+ if (e->mins[k] < e->origin[k] - e->lightradius) e->mins[k] = e->origin[k] - e->lightradius;
+ if (e->maxs[k] > e->origin[k] + e->lightradius) e->maxs[k] = e->origin[k] + e->lightradius;
+ }
+ e->cullradius = RadiusFromBoundsAndOrigin(e->mins, e->maxs, e->origin);
+
+ // cast shadow volume from castmesh
+ castmesh = Mod_ShadowMesh_Finish(r_shadow_mempool, castmesh, false, true);
+ if (castmesh)
+ {
+ maxverts = 0;
+ for (mesh = castmesh;mesh;mesh = mesh->next)
+ {
+ R_Shadow_ResizeShadowElements(mesh->numtriangles);
+ maxverts = max(maxverts, mesh->numverts * 2);
+ }
- // now that we have the buffers big enough, construct and add
- // the shadow volume mesh
+ if (maxverts > 0)
+ {
+ vertex3f = Mem_Alloc(r_shadow_mempool, maxverts * sizeof(float[3]));
+ // now that we have the buffers big enough, construct and add
+ // the shadow volume mesh
+ if (e->castshadows)
+ e->meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
+ for (mesh = castmesh;mesh;mesh = mesh->next)
+ {
+ Mod_BuildTriangleNeighbors(mesh->neighbor3i, mesh->element3i, mesh->numtriangles);
if ((tris = R_Shadow_ConstructShadowVolume(castmesh->numverts, 0, castmesh->numtriangles, castmesh->element3i, castmesh->neighbor3i, castmesh->vertex3f, NULL, shadowelements, vertex3f, e->origin, r_shadow_projectdistance.value)))
- Mod_ShadowMesh_AddMesh(r_shadow_mempool, e->shadowvolume, vertex3f, tris, shadowelements);
+ Mod_ShadowMesh_AddMesh(r_shadow_mempool, e->meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
}
- if (vertex3f)
- Mem_Free(vertex3f);
+ Mem_Free(vertex3f);
vertex3f = NULL;
- // we're done with castmesh now
- Mod_ShadowMesh_Free(castmesh);
- e->shadowvolume = Mod_ShadowMesh_Finish(r_shadow_mempool, e->shadowvolume);
- for (l = 0, mesh = e->shadowvolume;mesh;mesh = mesh->next)
- l += mesh->numtriangles;
- Con_Printf("static shadow volume built containing %i triangles\n", l);
}
- }
- Con_Printf("%f %f %f, %f %f %f, %f, %f, %d\n", e->mins[0], e->mins[1], e->mins[2], e->maxs[0], e->maxs[1], e->maxs[2], e->cullradius, e->lightradius, e->numsurfaces);
+ // we're done with castmesh now
+ Mod_ShadowMesh_Free(castmesh);
+ }
+
+ e->meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, e->meshchain_shadow, false, false);
+ e->meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, e->meshchain_light, true, false);
+
+ k = 0;
+ if (e->meshchain_shadow)
+ for (mesh = e->meshchain_shadow;mesh;mesh = mesh->next)
+ k += mesh->numtriangles;
+ l = 0;
+ if (e->meshchain_light)
+ for (mesh = e->meshchain_light;mesh;mesh = mesh->next)
+ l += mesh->numtriangles;
+ Con_Printf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles, %i light triangles\n", e->mins[0], e->mins[1], e->mins[2], e->maxs[0], e->maxs[1], e->maxs[2], k, l);
}
void R_Shadow_FreeWorldLight(worldlight_t *light)
*lightpointer = light->next;
if (light->cubemapname)
Mem_Free(light->cubemapname);
- if (light->shadowvolume)
- Mod_ShadowMesh_Free(light->shadowvolume);
- if (light->surfaces)
- Mem_Free(light->surfaces);
+ if (light->meshchain_shadow)
+ Mod_ShadowMesh_Free(light->meshchain_shadow);
+ if (light->meshchain_light)
+ Mod_ShadowMesh_Free(light->meshchain_light);
Mem_Free(light);
}
intensity = 0.5;
if (light->selected)
intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
- if (!light->shadowvolume)
+ if (!light->meshchain_shadow)
intensity *= 0.5f;
R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[calldata2], false, light->origin, vright, vup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
}
vec3_t maxs;
vec_t cullradius;
struct worldlight_s *next;
- msurface_t **surfaces;
- int numsurfaces;
rtexture_t *cubemap;
int style;
- shadowmesh_t *shadowvolume;
int selected;
+
+ // premade shadow volumes and lit surfaces to render
+ shadowmesh_t *meshchain_shadow;
+ shadowmesh_t *meshchain_light;
}
worldlight_t;
void R_Shadow_UpdateWorldLightSelection(void);
+void R_Shadow_DrawStaticWorldLight_Shadow(worldlight_t *light, matrix4x4_t *matrix);
+void R_Shadow_DrawStaticWorldLight_Light(worldlight_t *light, matrix4x4_t *matrix, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
+
#endif
#include "quakedef.h"
-static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "0"}; // fast but loose
-static cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "1"}; // tends to get false negatives, uses a timeout to keep entities visible a short time after becoming hidden
+static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1"}; // fast but loose
+static cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "0"}; // tends to get false negatives, uses a timeout to keep entities visible a short time after becoming hidden
static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0"};
static cvar_t sv_entpatch = {0, "sv_entpatch", "1"};
-n darkplaces: add bullet hole decals to the particlefont (Vermeulen)
-n darkplaces: add cl_particles_quality cvar (1-10) which would scale count of particles and inversely scale alpha of particles (TheBeast)
-n darkplaces: add error messages to LHNET_OpenSocket_Connectionless or its callers (Zombie13)
+-n darkplaces: add gl_texture_anisotropy to menu (Static_Fiend)
-n darkplaces: add slowmo to options menu (Cristian Beltramo)
-n darkplaces: add stats to slist menu displaying how many masters/servers have been queried and replied (tell yummyluv)
-n darkplaces: check out qe1 textures and make sure they load in all the e1 maps, report of crashing in most but not all maps (Linny Amore)
+-n darkplaces: default to sv_cullentities_pvs mode again... trace is too slow in q3bsp and unreliable by nature anyway
-n darkplaces: display "No servers found" instead of a cursor when there are none (yummyluv)
-n darkplaces: don't accept connect packets after first one (tell Willis)
-n darkplaces: examine the surface rendering code to make sure it has no bugs regarding texture selection for any of the passes (sublim3)
0 darkplaces: add _reflect textures which filter use of skybox as a cubemap reflection (FrikaC)
0 darkplaces: add a .collision_cancollide QC function call to decide if an entity should collide with another, or pass through it (Uffe)
0 darkplaces: add a clipmask thingy to allow QC to mask off collisions as it wishes (Uffe)
+0 darkplaces: add a config saving command (Speeds)
0 darkplaces: add a scr_screenshot_jpeg_quality cvar (Electro)
-0 darkplaces: add ability to load gfx/particlefont.tga (Vermeulen, frightfan)
+0 darkplaces: add ability to load gfx/particlefont.tga (Vermeulen, frightfan, Error)
0 darkplaces: add automatic binding to whatever address the machine's hostname resolves to (in addition to 0.0.0.0); see original quake code for examples (yummyluv)
0 darkplaces: add chase_pitch cvar to control pitch angle of chase camera, and chase_angle cvar to control yaw angle of chase camera, and add back chase_right cvar (Electro)
0 darkplaces: add cl_particles_particleffect_bloodhack cvar to enable converting id1 blood effects to TE_BLOOD style (Alex Boveri)
d darkplaces: dedicated server should not bother allocating a loopback socket (yummyluv)
d darkplaces: default deathmatch 1 in multiplayer games like Nexuiz incase someone starts a game from console (Vermeulen)
d darkplaces: default to 32bit color
+d darkplaces: disable mod_q3bsp_optimizedtraceline by default until it works
d darkplaces: figure out what is broken about the shadow volumes or stencil comparisons
d darkplaces: figure out what is wrong with loading _glow/_luma textures on md3 models (not bsp textures) (kd23 Nexuiz)
d darkplaces: figure out why disconnections are showing up as " disconnected"