From: havoc Date: Wed, 5 Nov 2003 03:36:38 +0000 (+0000) Subject: added r_shadow_showtris X-Git-Tag: xonotic-v0.1.0preview~6285 X-Git-Url: http://git.xonotic.org/?a=commitdiff_plain;h=7c80c8318c253eab01f35ee35aec044b0309ac9b;hp=569035fb5d987a2ebcac65c5c2657d86556c24b3;p=xonotic%2Fdarkplaces.git added r_shadow_showtris added gl_texture_anisotropy to menu changed sv_cullentities_trace and _pvs defaults to 0 and 1 respectively (now uses pvs culling because trace culling was too slow in q3bsp) r_shadow_realtime_world now works in q3bsp (using upgraded Mod_ShadowMesh functions to combine lighting meshes) rewrote most of R_Q3BSP_DrawFace - now supports singletexture cards, r_shadow_realtime_world, and glow textures git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3623 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/gl_rmain.c b/gl_rmain.c index 1463a2cb..968f8210 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -524,7 +524,6 @@ void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float c 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; @@ -585,8 +584,8 @@ void R_ShadowVolumeLighting(int visiblevolumes) 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) @@ -622,8 +621,8 @@ void R_ShadowVolumeLighting(int visiblevolumes) 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); } diff --git a/gl_rsurf.c b/gl_rsurf.c index dd32b9bc..3e237555 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -1728,30 +1728,6 @@ void R_Model_Brush_DrawShadowVolume (entity_render_t *ent, vec3_t relativelighto } } -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; @@ -1836,9 +1812,112 @@ void R_Q3BSP_DrawSkyFace(entity_render_t *ent, q3mface_t *face) 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) @@ -1848,29 +1927,32 @@ void R_Q3BSP_DrawFace(entity_render_t *ent, q3mface_t *face) 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) diff --git a/menu.c b/menu.c index d3af61ea..114a49cc 100644 --- a/menu.c +++ b/menu.c @@ -1112,7 +1112,7 @@ void M_DrawCheckbox (int x, int y, int on) } -#define OPTIONS_ITEMS 32 +#define OPTIONS_ITEMS 33 int options_cursor; @@ -1127,6 +1127,7 @@ extern cvar_t snd_staticvolume; 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) { @@ -1156,6 +1157,8 @@ 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++) @@ -1277,6 +1280,7 @@ void M_Options_Draw (void) 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); @@ -3867,10 +3871,10 @@ void MP_Init (void) // set time *prog->time = realtime; - + // call the prog init PRVM_ExecuteProgram((func_t) (PRVM_ED_FindFunction(M_F_INIT) - prog->functions),""); - + PRVM_End; } @@ -3897,7 +3901,7 @@ void MR_SetRouting(qboolean forceold) MR_Draw = M_Draw; MR_ToggleMenu_f = M_ToggleMenu_f; MR_Shutdown = M_Shutdown; - + // init if(!m_init) { @@ -3914,7 +3918,7 @@ void MR_SetRouting(qboolean forceold) MR_Draw = MP_Draw; MR_ToggleMenu_f = MP_ToggleMenu_f; MR_Shutdown = MP_Shutdown; - + if(!mp_init) { MP_Init(); @@ -3940,12 +3944,12 @@ void MR_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); } diff --git a/model_brush.c b/model_brush.c index 1a66eae7..c6722f26 100644 --- a/model_brush.c +++ b/model_brush.c @@ -36,7 +36,7 @@ cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"}; 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) { diff --git a/model_brush.h b/model_brush.h index 609793c4..537b6c63 100644 --- a/model_brush.h +++ b/model_brush.h @@ -223,7 +223,7 @@ typedef struct msurface_s // 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; diff --git a/model_shared.c b/model_shared.c index 4b4ea56e..2d3637b2 100644 --- a/model_shared.c +++ b/model_shared.c @@ -613,119 +613,173 @@ void Mod_BuildTextureVectorsAndNormals(int numverts, int numtriangles, const flo 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) @@ -733,25 +787,12 @@ shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh) 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; } diff --git a/model_shared.h b/model_shared.h index cb8a1501..f3a773bf 100644 --- a/model_shared.h +++ b/model_shared.h @@ -84,11 +84,25 @@ shadowmeshvertexhash_t; 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 @@ -377,6 +391,9 @@ typedef struct q3mface_s float *data_color4f; int *data_element3i; int *data_neighbor3i; + + // temporary use by light processing + int lighttemp_castshadow; } q3mface_t; @@ -573,14 +590,13 @@ void Mod_BuildTriangleNeighbors(int *neighbors, const int *elements, int numtria 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); diff --git a/r_shadow.c b/r_shadow.c index b511e9ba..a5d5c746 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -157,6 +157,7 @@ cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "10000"}; 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; @@ -271,6 +272,7 @@ void R_Shadow_Init(void) 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); @@ -1713,10 +1715,72 @@ void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elemen } } -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"}; @@ -1734,15 +1798,12 @@ vec3_t r_editlights_cursorlocation; 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) { @@ -1777,136 +1838,184 @@ void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style 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) @@ -1918,10 +2027,10 @@ 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); } @@ -1957,7 +2066,7 @@ void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2) 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); } diff --git a/r_shadow.h b/r_shadow.h index 61524f7c..2e1a9d4c 100644 --- a/r_shadow.h +++ b/r_shadow.h @@ -55,12 +55,13 @@ typedef struct worldlight_s 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; @@ -68,4 +69,7 @@ extern worldlight_t *r_shadow_worldlightchain; 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 diff --git a/sv_main.c b/sv_main.c index 4470a753..7f1b6a90 100644 --- a/sv_main.c +++ b/sv_main.c @@ -21,8 +21,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #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"}; diff --git a/todo b/todo index e9cdeca4..1e735289 100644 --- a/todo +++ b/todo @@ -3,9 +3,11 @@ -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) @@ -33,8 +35,9 @@ 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) @@ -312,6 +315,7 @@ d darkplaces: dedicated server should error out if it has no sockets (yummyluv) 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"