From 34143ce95fe6b6eb7075501e8eae5c9e1d42ca84 Mon Sep 17 00:00:00 2001 From: havoc Date: Thu, 30 Sep 2004 10:05:01 +0000 Subject: [PATCH] removed a few fields from q3msurface_t added a facelist to each q3mtexture_t so that the renderer can build a list of faces of the same texture without any face->texture comparisons rewrote R_Q3BSP_DrawSky and R_Q3BSP_Draw, this improved a nexuiz timedemo with no rtlights by 116% git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@4565 d7cf8633-e32d-0410-b094-e92efae38249 --- gl_rsurf.c | 733 ++++++++++++++++++++++++------------------------- model_brush.c | 127 +++++---- model_shared.h | 34 +-- 3 files changed, 462 insertions(+), 432 deletions(-) diff --git a/gl_rsurf.c b/gl_rsurf.c index 136e8ec9..5c9bfd92 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -29,6 +29,10 @@ static float floatblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHav static qbyte templight[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*4]; +static mempool_t *r_surf_mempool = NULL; +static int r_surf_surfacevisiblelimit = 0; +static qbyte *r_surf_surfacevisible = NULL; + cvar_t r_ambient = {0, "r_ambient", "0"}; cvar_t r_drawportals = {0, "r_drawportals", "0"}; cvar_t r_testvis = {0, "r_testvis", "0"}; @@ -58,6 +62,17 @@ int r_q3bsp_nummarksurfaces; q3msurface_t *r_q3bsp_maxsurfacelist[65536]; */ +void R_Surf_ClearSurfaceVisible(int num) +{ + if (r_surf_surfacevisiblelimit < num) + { + Mem_Free(r_surf_surfacevisible); + r_surf_surfacevisiblelimit = num; + r_surf_surfacevisible = Mem_Alloc(r_surf_mempool, r_surf_surfacevisiblelimit); + } + memset(r_surf_surfacevisible, 0, num); +} + static int dlightdivtable[32768]; static int R_IntAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surf) @@ -1880,7 +1895,8 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t else if (ent != &cl_entities[0].render || surface->visframe == r_framecount) { t = surface->texinfo->texture->currentframe; - if (t->flags & SURF_LIGHTMAP) + // FIXME: transparent surfaces need to be lit later + if (t->flags & SURF_LIGHTMAP && t->rendertype == SURFRENDER_OPAQUE) R_Shadow_RenderLighting(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i, surface->mesh.data_vertex3f, surface->mesh.data_svector3f, surface->mesh.data_tvector3f, surface->mesh.data_normal3f, surface->mesh.data_texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.base, t->skin.nmap, t->skin.gloss, lightcubemap, LIGHTING_DIFFUSE | LIGHTING_SPECULAR); } } @@ -1917,454 +1933,431 @@ void R_Q3BSP_DrawCollisionFace(entity_render_t *ent, q3msurface_t *face) GL_LockArrays(0, 0); } -void R_Q3BSP_DrawSkyFace(entity_render_t *ent, q3msurface_t *face) +void R_Q3BSP_DrawFace_TransparentCallback(const void *voident, int facenumber) { + const entity_render_t *ent = voident; + q3msurface_t *face = ent->model->brushq3.data_faces + facenumber; rmeshstate_t m; - if (!face->num_triangles) - return; - // drawing sky transparently would be too difficult - if (ent->flags & RENDER_TRANSPARENT) - return; - c_faces++; - if (skyrendernow) - { - skyrendernow = false; - if (skyrendermasked) - R_Sky(); - } - if (!r_q3bsp_renderskydepth.integer) - return; - R_Mesh_Matrix(&ent->matrix); - - GL_Color(fogcolor[0], fogcolor[1], fogcolor[2], 1); - if (skyrendermasked) - { - // depth-only (masking) - GL_ColorMask(0,0,0,0); - // just to make sure that braindead drivers don't draw anything - // despite that colormask... - GL_BlendFunc(GL_ZERO, GL_ONE); - } - else - { - // fog sky - GL_BlendFunc(GL_ONE, GL_ZERO); - } - GL_DepthMask(true); - GL_DepthTest(true); - memset(&m, 0, sizeof(m)); - m.pointer_vertex = face->data_vertex3f; - R_Mesh_State(&m); - - GL_LockArrays(0, face->num_vertices); - R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); - GL_LockArrays(0, 0); - GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1); -} - -void R_Q3BSP_DrawFace_OpaqueWall_Pass_OpaqueGlow(entity_render_t *ent, q3msurface_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); - } + if (ent->effects & EF_ADDITIVE) + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); else - GL_Color(0, 0, 0, 1); - m.pointer_vertex = face->data_vertex3f; - R_Mesh_State(&m); - GL_LockArrays(0, face->num_vertices); - R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); - GL_LockArrays(0, 0); -} - -void R_Q3BSP_DrawFace_OpaqueWall_Pass_TextureLightmapCombine(entity_render_t *ent, q3msurface_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); - m.pointer_vertex = face->data_vertex3f; - R_Mesh_State(&m); - GL_LockArrays(0, face->num_vertices); - R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); - GL_LockArrays(0, 0); -} - -void R_Q3BSP_DrawFace_OpaqueWall_Pass_Texture(entity_render_t *ent, q3msurface_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); - m.pointer_vertex = face->data_vertex3f; - R_Mesh_State(&m); - GL_LockArrays(0, face->num_vertices); - R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); - GL_LockArrays(0, 0); -} - -void R_Q3BSP_DrawFace_OpaqueWall_Pass_Lightmap(entity_render_t *ent, q3msurface_t *face) -{ - rmeshstate_t m; - memset(&m, 0, sizeof(m)); - GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); - GL_DepthMask(false); - GL_DepthTest(true); - m.tex[0] = R_GetTexture(face->lightmaptexture); - m.pointer_texcoord[0] = face->data_texcoordlightmap2f; - GL_Color(1, 1, 1, 1); - m.pointer_vertex = face->data_vertex3f; - R_Mesh_State(&m); - GL_LockArrays(0, face->num_vertices); - R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); - GL_LockArrays(0, 0); -} - -void R_Q3BSP_DrawFace_OpaqueWall_Pass_LightmapOnly(entity_render_t *ent, q3msurface_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->lightmaptexture); - m.pointer_texcoord[0] = face->data_texcoordlightmap2f; - GL_Color(r_lightmapintensity, r_lightmapintensity, r_lightmapintensity, 1); - m.pointer_vertex = face->data_vertex3f; - R_Mesh_State(&m); - GL_LockArrays(0, face->num_vertices); - R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); - GL_LockArrays(0, 0); -} - -void R_Q3BSP_DrawFace_OpaqueWall_Pass_Glow(entity_render_t *ent, q3msurface_t *face) -{ - rmeshstate_t m; - memset(&m, 0, sizeof(m)); - GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_DepthMask(false); - 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); - m.pointer_vertex = face->data_vertex3f; - R_Mesh_State(&m); - GL_LockArrays(0, face->num_vertices); - R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); - GL_LockArrays(0, 0); -} - -void R_Q3BSP_DrawFace_OpaqueWall_Pass_TextureVertex(entity_render_t *ent, q3msurface_t *face) -{ - int i; - float mul; - rmeshstate_t m; - memset(&m, 0, sizeof(m)); - GL_BlendFunc(GL_ONE, GL_ZERO); - GL_DepthMask(true); - GL_DepthTest(true); + GL_DepthTest(!(ent->effects & EF_NODEPTHTEST)); m.tex[0] = R_GetTexture(face->texture->skin.base); m.pointer_texcoord[0] = face->data_texcoordtexture2f; - mul = 2.0f * r_lightmapintensity; - if (mul == 2 && gl_combine.integer) + // LordHavoc: quake3 was not able to do this; lit transparent surfaces + if (gl_combine.integer) { m.texrgbscale[0] = 2; - m.pointer_color = face->data_color4f; - } - else if (mul == 1) - m.pointer_color = face->data_color4f; - else - { - for (i = 0;i < face->num_vertices;i++) + if (r_textureunits.integer >= 2) { - varray_color4f[i*4+0] = face->data_color4f[i*4+0] * mul; - varray_color4f[i*4+1] = face->data_color4f[i*4+1] * mul; - varray_color4f[i*4+2] = face->data_color4f[i*4+2] * mul; - varray_color4f[i*4+3] = face->data_color4f[i*4+3]; + m.tex[1] = R_GetTexture(face->lightmaptexture); + m.pointer_texcoord[1] = face->data_texcoordlightmap2f; + GL_Color(1, 1, 1, ent->alpha); + } + else + { + if (ent->alpha == 1) + m.pointer_color = face->data_color4f; + else + { + int i; + for (i = 0;i < face->num_vertices;i++) + { + varray_color4f[i*4+0] = face->data_color4f[i*4+0]; + varray_color4f[i*4+1] = face->data_color4f[i*4+1]; + varray_color4f[i*4+2] = face->data_color4f[i*4+2]; + varray_color4f[i*4+3] = face->data_color4f[i*4+3] * ent->alpha; + } + m.pointer_color = varray_color4f; + } } - m.pointer_color = varray_color4f; } - m.pointer_vertex = face->data_vertex3f; - R_Mesh_State(&m); - GL_LockArrays(0, face->num_vertices); - R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); - GL_LockArrays(0, 0); -} - -void R_Q3BSP_DrawFace_OpaqueWall_Pass_VertexOnly(entity_render_t *ent, q3msurface_t *face) -{ - int i; - float mul; - rmeshstate_t m; - memset(&m, 0, sizeof(m)); - GL_BlendFunc(GL_ONE, GL_ZERO); - GL_DepthMask(true); - GL_DepthTest(true); - mul = 2.0f * r_lightmapintensity; - if (mul == 1) - m.pointer_color = face->data_color4f; else { + int i; for (i = 0;i < face->num_vertices;i++) { varray_color4f[i*4+0] = face->data_color4f[i*4+0] * 2.0f; varray_color4f[i*4+1] = face->data_color4f[i*4+1] * 2.0f; varray_color4f[i*4+2] = face->data_color4f[i*4+2] * 2.0f; - varray_color4f[i*4+3] = face->data_color4f[i*4+3]; + varray_color4f[i*4+3] = face->data_color4f[i*4+3] * ent->alpha; } m.pointer_color = varray_color4f; } m.pointer_vertex = face->data_vertex3f; R_Mesh_State(&m); + qglDisable(GL_CULL_FACE); GL_LockArrays(0, face->num_vertices); R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); GL_LockArrays(0, 0); + qglEnable(GL_CULL_FACE); } -void R_Q3BSP_DrawFace_OpaqueWall_Pass_AddTextureAmbient(entity_render_t *ent, q3msurface_t *face) -{ - rmeshstate_t m; - memset(&m, 0, sizeof(m)); - GL_BlendFunc(GL_ONE, GL_ONE); - GL_DepthMask(true); - GL_DepthTest(true); - m.tex[0] = R_GetTexture(face->texture->skin.base); - m.pointer_texcoord[0] = face->data_texcoordtexture2f; - GL_Color(r_ambient.value * (1.0f / 128.0f), r_ambient.value * (1.0f / 128.0f), r_ambient.value * (1.0f / 128.0f), 1); - m.pointer_vertex = face->data_vertex3f; - R_Mesh_State(&m); - GL_LockArrays(0, face->num_vertices); - R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); - GL_LockArrays(0, 0); -} - -void R_Q3BSP_DrawFace_TransparentCallback(const void *voident, int facenumber) +void R_Q3BSP_DrawFaceList(entity_render_t *ent, q3mtexture_t *t, int texturenumfaces, q3msurface_t **texturefacelist) { - int i; - float colorscale; - const entity_render_t *ent = voident; - q3msurface_t *face = ent->model->brushq3.data_faces + facenumber; + int i, texturefaceindex; rmeshstate_t m; - R_Mesh_Matrix(&ent->matrix); - memset(&m, 0, sizeof(m)); - if (ent->effects & EF_ADDITIVE) - GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); - else - GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - GL_DepthMask(false); - GL_DepthTest(!(ent->effects & EF_NODEPTHTEST)); - m.tex[0] = R_GetTexture(face->texture->skin.base); - m.pointer_texcoord[0] = face->data_texcoordtexture2f; - colorscale = r_lightmapintensity; - if (gl_combine.integer) - m.texrgbscale[0] = 2; - else - colorscale *= 2.0f; - for (i = 0;i < face->num_vertices;i++) + if (!texturenumfaces) + return; + c_faces += texturenumfaces; + // transparent surfaces get sorted for later drawing + if ((t->surfaceparms & Q3SURFACEPARM_TRANS) || ent->alpha < 1 || (ent->effects & EF_ADDITIVE)) { - varray_color4f[i*4+0] = face->data_color4f[i*4+0] * colorscale; - varray_color4f[i*4+1] = face->data_color4f[i*4+1] * colorscale; - varray_color4f[i*4+2] = face->data_color4f[i*4+2] * colorscale; - varray_color4f[i*4+3] = face->data_color4f[i*4+3] * ent->alpha; + vec3_t facecenter, center; + // drawing sky transparently would be too difficult + if (t->surfaceparms & Q3SURFACEPARM_SKY) + return; + for (texturefaceindex = 0;texturefaceindex < texturenumfaces;texturefaceindex++) + { + q3msurface_t *face = texturefacelist[texturefaceindex]; + facecenter[0] = (face->mins[0] + face->maxs[0]) * 0.5f; + facecenter[1] = (face->mins[1] + face->maxs[1]) * 0.5f; + facecenter[2] = (face->mins[2] + face->maxs[2]) * 0.5f; + Matrix4x4_Transform(&ent->matrix, facecenter, center); + R_MeshQueue_AddTransparent(center, R_Q3BSP_DrawFace_TransparentCallback, ent, face - ent->model->brushq3.data_faces); + } + return; } - m.pointer_color = varray_color4f; - m.pointer_vertex = face->data_vertex3f; - R_Mesh_State(&m); - qglDisable(GL_CULL_FACE); - GL_LockArrays(0, face->num_vertices); - R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); - GL_LockArrays(0, 0); - qglEnable(GL_CULL_FACE); -} + // sky surfaces draw sky if needed and render themselves as a depth mask + if (t->surfaceparms & Q3SURFACEPARM_SKY) + { + if (skyrendernow) + { + skyrendernow = false; + if (skyrendermasked) + R_Sky(); + } + if (!r_q3bsp_renderskydepth.integer) + return; -void R_Q3BSP_DrawFace(entity_render_t *ent, q3msurface_t *face) -{ - if (!face->num_triangles) + R_Mesh_Matrix(&ent->matrix); + + GL_Color(fogcolor[0], fogcolor[1], fogcolor[2], 1); + if (skyrendermasked) + { + // depth-only (masking) + GL_ColorMask(0,0,0,0); + // just to make sure that braindead drivers don't draw anything + // despite that colormask... + GL_BlendFunc(GL_ZERO, GL_ONE); + } + else + { + // fog sky + GL_BlendFunc(GL_ONE, GL_ZERO); + } + GL_DepthMask(true); + GL_DepthTest(true); + + memset(&m, 0, sizeof(m)); + for (texturefaceindex = 0;texturefaceindex < texturenumfaces;texturefaceindex++) + { + q3msurface_t *face = texturefacelist[texturefaceindex]; + m.pointer_vertex = face->data_vertex3f; + R_Mesh_State(&m); + GL_LockArrays(0, face->num_vertices); + R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); + GL_LockArrays(0, 0); + } + GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1); return; - if (face->texture->surfaceflags && (face->texture->surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NODRAW))) + } + // gl_lightmaps debugging mode skips normal texturing + if (gl_lightmaps.integer) + { + GL_DepthMask(true); + GL_DepthTest(true); + GL_BlendFunc(GL_ONE, GL_ZERO); + memset(&m, 0, sizeof(m)); + for (texturefaceindex = 0;texturefaceindex < texturenumfaces;texturefaceindex++) + { + q3msurface_t *face = texturefacelist[texturefaceindex]; + m.tex[0] = R_GetTexture(face->lightmaptexture); + m.pointer_texcoord[0] = face->data_texcoordlightmap2f; + if (face->lightmaptexture) + { + GL_Color(1, 1, 1, 1); + m.pointer_color = NULL; + } + else + m.pointer_color = face->data_color4f; + m.pointer_vertex = face->data_vertex3f; + R_Mesh_State(&m); + GL_LockArrays(0, face->num_vertices); + R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); + GL_LockArrays(0, 0); + } return; - c_faces++; - if ((face->texture->surfaceparms & Q3SURFACEPARM_TRANS) || ent->alpha < 1 || (ent->effects & EF_ADDITIVE)) + } + // anything else is a typical wall, lightmap * texture + glow + if (!(ent->flags & RENDER_LIGHT)) { - vec3_t facecenter, center; - facecenter[0] = (face->mins[0] + face->maxs[0]) * 0.5f; - facecenter[1] = (face->mins[1] + face->maxs[1]) * 0.5f; - facecenter[2] = (face->mins[2] + face->maxs[2]) * 0.5f; - Matrix4x4_Transform(&ent->matrix, facecenter, center); - R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : center, R_Q3BSP_DrawFace_TransparentCallback, ent, face - ent->model->brushq3.data_faces); + GL_DepthMask(true); + GL_DepthTest(true); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_Color(1, 1, 1, 1); + memset(&m, 0, sizeof(m)); + m.tex[0] = R_GetTexture(t->skin.base); + for (texturefaceindex = 0;texturefaceindex < texturenumfaces;texturefaceindex++) + { + q3msurface_t *face = texturefacelist[texturefaceindex]; + m.pointer_texcoord[0] = face->data_texcoordtexture2f; + m.pointer_vertex = face->data_vertex3f; + R_Mesh_State(&m); + GL_LockArrays(0, face->num_vertices); + R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); + GL_LockArrays(0, 0); + } + if (t->skin.glow) + { + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + GL_DepthMask(false); + m.tex[0] = R_GetTexture(t->skin.glow); + for (texturefaceindex = 0;texturefaceindex < texturenumfaces;texturefaceindex++) + { + q3msurface_t *face = texturefacelist[texturefaceindex]; + m.pointer_texcoord[0] = face->data_texcoordtexture2f; + m.pointer_vertex = face->data_vertex3f; + R_Mesh_State(&m); + GL_LockArrays(0, face->num_vertices); + R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); + GL_LockArrays(0, 0); + } + } return; } - R_Mesh_Matrix(&ent->matrix); if (r_lightmapintensity <= 0) - R_Q3BSP_DrawFace_OpaqueWall_Pass_OpaqueGlow(ent, face); - else if (!(ent->flags & RENDER_LIGHT)) { - R_Q3BSP_DrawFace_OpaqueWall_Pass_Texture(ent, face); - if (face->texture->skin.glow) - R_Q3BSP_DrawFace_OpaqueWall_Pass_Glow(ent, face); + GL_DepthMask(true); + GL_DepthTest(true); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_Color(0, 0, 0, 1); + memset(&m, 0, sizeof(m)); + for (texturefaceindex = 0;texturefaceindex < texturenumfaces;texturefaceindex++) + { + q3msurface_t *face = texturefacelist[texturefaceindex]; + m.pointer_vertex = face->data_vertex3f; + R_Mesh_State(&m); + GL_LockArrays(0, face->num_vertices); + R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); + GL_LockArrays(0, 0); + } } - else if (face->lightmaptexture) + else if (r_textureunits.integer >= 2 && gl_combine.integer) { - if (gl_lightmaps.integer) - R_Q3BSP_DrawFace_OpaqueWall_Pass_LightmapOnly(ent, face); - else - { - if (r_textureunits.integer >= 2 && gl_combine.integer) - R_Q3BSP_DrawFace_OpaqueWall_Pass_TextureLightmapCombine(ent, face); + // dualtexture combine + GL_DepthMask(true); + GL_DepthTest(true); + GL_BlendFunc(GL_ONE, GL_ZERO); + memset(&m, 0, sizeof(m)); + m.tex[0] = R_GetTexture(t->skin.base); + for (texturefaceindex = 0;texturefaceindex < texturenumfaces;texturefaceindex++) + { + q3msurface_t *face = texturefacelist[texturefaceindex]; + m.tex[1] = R_GetTexture(face->lightmaptexture); + m.pointer_texcoord[0] = face->data_texcoordtexture2f; + m.pointer_texcoord[1] = face->data_texcoordlightmap2f; + m.texrgbscale[1] = 2; + if (face->lightmaptexture) + { + GL_Color(r_lightmapintensity, r_lightmapintensity, r_lightmapintensity, 1); + m.pointer_color = NULL; + } + else if (r_lightmapintensity == 1) + m.pointer_color = face->data_color4f; else { - R_Q3BSP_DrawFace_OpaqueWall_Pass_Texture(ent, face); - R_Q3BSP_DrawFace_OpaqueWall_Pass_Lightmap(ent, face); + m.pointer_color = varray_color4f; + for (i = 0;i < face->num_vertices;i++) + { + varray_color4f[i*4+0] = face->data_color4f[i*4+0] * r_lightmapintensity; + varray_color4f[i*4+1] = face->data_color4f[i*4+1] * r_lightmapintensity; + varray_color4f[i*4+2] = face->data_color4f[i*4+2] * r_lightmapintensity; + varray_color4f[i*4+3] = face->data_color4f[i*4+3]; + } } - if (face->texture->skin.glow) - R_Q3BSP_DrawFace_OpaqueWall_Pass_Glow(ent, face); + m.pointer_vertex = face->data_vertex3f; + R_Mesh_State(&m); + GL_LockArrays(0, face->num_vertices); + R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); + GL_LockArrays(0, 0); } } else { - if (gl_lightmaps.integer) - R_Q3BSP_DrawFace_OpaqueWall_Pass_VertexOnly(ent, face); - else + // single texture + GL_DepthMask(true); + GL_DepthTest(true); + GL_BlendFunc(GL_ONE, GL_ZERO); + memset(&m, 0, sizeof(m)); + for (texturefaceindex = 0;texturefaceindex < texturenumfaces;texturefaceindex++) { - R_Q3BSP_DrawFace_OpaqueWall_Pass_TextureVertex(ent, face); - if (face->texture->skin.glow) - R_Q3BSP_DrawFace_OpaqueWall_Pass_Glow(ent, face); + q3msurface_t *face = texturefacelist[texturefaceindex]; + m.tex[0] = R_GetTexture(face->lightmaptexture); + m.pointer_texcoord[0] = face->data_texcoordlightmap2f; + if (face->lightmaptexture) + m.pointer_color = NULL; + else + m.pointer_color = face->data_color4f; + m.pointer_vertex = face->data_vertex3f; + R_Mesh_State(&m); + GL_LockArrays(0, face->num_vertices); + R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); + GL_LockArrays(0, 0); + } + GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); + GL_DepthMask(false); + GL_Color(r_lightmapintensity, r_lightmapintensity, r_lightmapintensity, 1); + memset(&m, 0, sizeof(m)); + m.tex[0] = R_GetTexture(t->skin.base); + for (texturefaceindex = 0;texturefaceindex < texturenumfaces;texturefaceindex++) + { + q3msurface_t *face = texturefacelist[texturefaceindex]; + m.pointer_texcoord[0] = face->data_texcoordtexture2f; + m.pointer_vertex = face->data_vertex3f; + R_Mesh_State(&m); + GL_LockArrays(0, face->num_vertices); + R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); + GL_LockArrays(0, 0); } } if (r_ambient.value) - R_Q3BSP_DrawFace_OpaqueWall_Pass_AddTextureAmbient(ent, face); -} - -void R_Q3BSP_RecursiveWorldNode(q3mnode_t *node) -{ - int i; - q3mleaf_t *leaf; - for (;;) - { - if (R_CullBox(node->mins, node->maxs)) - return; - if (!node->plane) - break; - c_nodes++; - R_Q3BSP_RecursiveWorldNode(node->children[0]); - node = node->children[1]; - } - leaf = (q3mleaf_t *)node; - if (CHECKPVSBIT(r_pvsbits, leaf->clusterindex)) { - c_leafs++; - for (i = 0;i < leaf->numleaffaces;i++) - leaf->firstleafface[i]->visframe = r_framecount; + GL_BlendFunc(GL_ONE, GL_ONE); + GL_DepthMask(false); + GL_Color(r_ambient.value * (1.0f / 128.0f), r_ambient.value * (1.0f / 128.0f), r_ambient.value * (1.0f / 128.0f), 1); + memset(&m, 0, sizeof(m)); + m.tex[0] = R_GetTexture(t->skin.base); + for (texturefaceindex = 0;texturefaceindex < texturenumfaces;texturefaceindex++) + { + q3msurface_t *face = texturefacelist[texturefaceindex]; + m.pointer_texcoord[0] = face->data_texcoordtexture2f; + m.pointer_vertex = face->data_vertex3f; + R_Mesh_State(&m); + GL_LockArrays(0, face->num_vertices); + R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); + GL_LockArrays(0, 0); + } } -} - -// FIXME: num_leafs needs to be recalculated at load time to include only -// node-referenced leafs, as some maps are incorrectly compiled with leafs for -// the submodels (which would render the submodels occasionally, as part of -// the world - not good) -void R_Q3BSP_MarkLeafPVS(void) -{ - int i, j; - q3mleaf_t *leaf; - for (j = 0, leaf = cl.worldmodel->brushq3.data_leafs;j < cl.worldmodel->brushq3.num_leafs;j++, leaf++) + if (t->skin.glow) { - if (CHECKPVSBIT(r_pvsbits, leaf->clusterindex)) + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + GL_DepthMask(false); + GL_Color(1, 1, 1, 1); + memset(&m, 0, sizeof(m)); + m.tex[0] = R_GetTexture(t->skin.glow); + for (texturefaceindex = 0;texturefaceindex < texturenumfaces;texturefaceindex++) { - c_leafs++; - for (i = 0;i < leaf->numleaffaces;i++) - leaf->firstleafface[i]->visframe = r_framecount; + q3msurface_t *face = texturefacelist[texturefaceindex]; + m.pointer_texcoord[0] = face->data_texcoordtexture2f; + m.pointer_vertex = face->data_vertex3f; + R_Mesh_State(&m); + GL_LockArrays(0, face->num_vertices); + R_Mesh_Draw(face->num_vertices, face->num_triangles, face->data_element3i); + GL_LockArrays(0, 0); } } } -static int r_q3bsp_framecount = -1; - -void R_Q3BSP_DrawSky(entity_render_t *ent) +void R_Q3BSP_DrawFaces(entity_render_t *ent, int skyfaces) { - int i; + int i, ti, flagsmask, flags; q3msurface_t *face; - vec3_t modelorg; model_t *model; + q3mtexture_t *t; + const int maxfaces = 1024; + int numfaces = 0; + q3msurface_t *facelist[1024]; R_Mesh_Matrix(&ent->matrix); model = ent->model; - if (r_drawcollisionbrushes.integer < 2) + flagsmask = Q3SURFACEFLAG_NODRAW | Q3SURFACEFLAG_SKY; + if (skyfaces) + flags = Q3SURFACEFLAG_SKY; + else + flags = 0; + if (ent == &cl_entities[0].render) { - Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg); - if (ent == &cl_entities[0].render) + int j; + q3mleaf_t *leaf; + R_Surf_ClearSurfaceVisible(cl.worldmodel->brushq3.num_faces); + for (j = 0, leaf = cl.worldmodel->brushq3.data_leafs;j < cl.worldmodel->brushq3.num_leafs;j++, leaf++) { - if (r_q3bsp_framecount != r_framecount) + if (CHECKPVSBIT(r_pvsbits, leaf->clusterindex) && !R_CullBox(leaf->mins, leaf->maxs)) { - r_q3bsp_framecount = r_framecount; - R_Q3BSP_RecursiveWorldNode(model->brushq3.data_nodes); - //R_Q3BSP_MarkLeafPVS(); + c_leafs++; + for (i = 0;i < leaf->numleaffaces;i++) + r_surf_surfacevisible[leaf->firstleaffacenum[i]] = 1; + } + } + for (ti = 0, t = model->brushq3.data_textures;ti < model->brushq3.num_textures;ti++, t++) + { + if ((t->surfaceflags & flagsmask) == flags) + { + numfaces = 0; + for (i = 0;i < t->numfaces;i++) + { + if (r_surf_surfacevisible[t->facenumlist[i]]) + { + face = t->facelist[i]; + if (!R_CullBox(face->mins, face->maxs)) + { + if (numfaces >= maxfaces) + { + if (numfaces) + R_Q3BSP_DrawFaceList(ent, t, numfaces, facelist); + numfaces = 0; + } + facelist[numfaces++] = face; + } + } + } + if (numfaces) + R_Q3BSP_DrawFaceList(ent, t, numfaces, facelist); } - for (i = 0, face = model->brushq3.data_thismodel->firstface;i < model->brushq3.data_thismodel->numfaces;i++, face++) - if (face->visframe == r_framecount && (face->texture->surfaceflags & Q3SURFACEFLAG_SKY) && !R_CullBox(face->mins, face->maxs)) - R_Q3BSP_DrawSkyFace(ent, face); } - else - for (i = 0, face = model->brushq3.data_thismodel->firstface;i < model->brushq3.data_thismodel->numfaces;i++, face++) - if ((face->texture->surfaceflags & Q3SURFACEFLAG_SKY)) - R_Q3BSP_DrawSkyFace(ent, face); } -} - -void R_Q3BSP_Draw(entity_render_t *ent) -{ - int i; - q3msurface_t *face; - vec3_t modelorg; - model_t *model; - qbyte *pvs; - R_Mesh_Matrix(&ent->matrix); - model = ent->model; - if (r_drawcollisionbrushes.integer < 2) + else { - Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg); - if (ent == &cl_entities[0].render) + t = NULL; + numfaces = 0; + for (i = 0, face = model->brushq3.data_thismodel->firstface;i < model->brushq3.data_thismodel->numfaces;i++, face++) { - if (model->brush.num_pvsclusters && !r_novis.integer && (pvs = model->brush.GetPVS(model, modelorg))) - if (r_q3bsp_framecount != r_framecount) + if ((face->texture->surfaceflags & flagsmask) == flags) { - r_q3bsp_framecount = r_framecount; - R_Q3BSP_RecursiveWorldNode(model->brushq3.data_nodes); - //R_Q3BSP_MarkLeafPVS(); + if (t != face->texture || numfaces >= maxfaces) + { + if (numfaces) + R_Q3BSP_DrawFaceList(ent, t, numfaces, facelist); + numfaces = 0; + t = face->texture; + } + facelist[numfaces++] = face; } - for (i = 0, face = model->brushq3.data_thismodel->firstface;i < model->brushq3.data_thismodel->numfaces;i++, face++) - if (face->visframe == r_framecount && !R_CullBox(face->mins, face->maxs)) - R_Q3BSP_DrawFace(ent, face); } - else - for (i = 0, face = model->brushq3.data_thismodel->firstface;i < model->brushq3.data_thismodel->numfaces;i++, face++) - R_Q3BSP_DrawFace(ent, face); + if (numfaces) + R_Q3BSP_DrawFaceList(ent, t, numfaces, facelist); } +} + +void R_Q3BSP_DrawSky(entity_render_t *ent) +{ + if (r_drawcollisionbrushes.integer < 2) + R_Q3BSP_DrawFaces(ent, true); +} + +void R_Q3BSP_Draw(entity_render_t *ent) +{ + if (r_drawcollisionbrushes.integer < 2) + R_Q3BSP_DrawFaces(ent, false); if (r_drawcollisionbrushes.integer >= 1) { + int i; + model_t *model = ent->model; + q3msurface_t *face; GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); GL_DepthMask(false); GL_DepthTest(true); @@ -2541,10 +2534,16 @@ void R_Q3BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t static void gl_surf_start(void) { + r_surf_mempool = Mem_AllocPool("gl_rsurf", 0, NULL); + r_surf_surfacevisiblelimit = 65536; + r_surf_surfacevisible = Mem_Alloc(r_surf_mempool, r_surf_surfacevisiblelimit); } static void gl_surf_shutdown(void) { + r_surf_surfacevisiblelimit = 0; + r_surf_surfacevisible = NULL; + Mem_FreePool(&r_surf_mempool); } static void gl_surf_newmap(void) diff --git a/model_brush.c b/model_brush.c index 87e6057e..2cb005c4 100644 --- a/model_brush.c +++ b/model_brush.c @@ -4017,7 +4017,7 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l) { q3dface_t *in; q3msurface_t *out; - int i, j, n, count, invalidelements, patchsize[2], finalwidth, finalheight, xlevel, ylevel, row0, row1, x, y, *e, finalvertices, finaltriangles; + int i, j, n, count, invalidelements, patchsize[2], finalwidth, finalheight, xlevel, ylevel, row0, row1, x, y, *e, finalvertices, finaltriangles, firstvertex, firstelement, type; //int *originalelement3i; //int *originalneighbor3i; float *originalvertex3f; @@ -4041,16 +4041,16 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l) for (i = 0;i < count;i++, in++, out++) { // check face type first - out->type = LittleLong(in->type); - if (out->type != Q3FACETYPE_POLYGON - && out->type != Q3FACETYPE_PATCH - && out->type != Q3FACETYPE_MESH - && out->type != Q3FACETYPE_FLARE) + type = LittleLong(in->type); + if (type != Q3FACETYPE_POLYGON + && type != Q3FACETYPE_PATCH + && type != Q3FACETYPE_MESH + && type != Q3FACETYPE_FLARE) { - Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: unknown face type %i\n", i, out->type); + Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: unknown face type %i\n", i, type); out->num_vertices = 0; out->num_triangles = 0; - out->type = 0; // error + type = 0; // error continue; } @@ -4060,7 +4060,7 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l) Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: invalid textureindex %i (%i textures)\n", i, n, loadmodel->brushq3.num_textures); out->num_vertices = 0; out->num_triangles = 0; - out->type = 0; // error + type = 0; // error continue; n = 0; } @@ -4086,48 +4086,48 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l) else out->lightmaptexture = loadmodel->brushq3.data_lightmaps[n]; - out->firstvertex = LittleLong(in->firstvertex); + firstvertex = LittleLong(in->firstvertex); out->num_vertices = LittleLong(in->numvertices); - out->firstelement = LittleLong(in->firstelement); + firstelement = LittleLong(in->firstelement); out->num_triangles = LittleLong(in->numelements) / 3; if (out->num_triangles * 3 != LittleLong(in->numelements)) { Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): numelements %i is not a multiple of 3\n", i, out->texture->name, LittleLong(in->numelements)); out->num_vertices = 0; out->num_triangles = 0; - out->type = 0; // error + type = 0; // error continue; } - if (out->firstvertex < 0 || out->firstvertex + out->num_vertices > loadmodel->brushq3.num_vertices) + if (firstvertex < 0 || firstvertex + out->num_vertices > loadmodel->brushq3.num_vertices) { - Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid vertex range %i : %i (%i vertices)\n", i, out->texture->name, out->firstvertex, out->firstvertex + out->num_vertices, loadmodel->brushq3.num_vertices); + Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid vertex range %i : %i (%i vertices)\n", i, out->texture->name, firstvertex, firstvertex + out->num_vertices, loadmodel->brushq3.num_vertices); out->num_vertices = 0; out->num_triangles = 0; - out->type = 0; // error + type = 0; // error continue; } - if (out->firstelement < 0 || out->firstelement + out->num_triangles * 3 > loadmodel->brushq3.num_triangles * 3) + if (firstelement < 0 || firstelement + out->num_triangles * 3 > loadmodel->brushq3.num_triangles * 3) { - Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid element range %i : %i (%i elements)\n", i, out->texture->name, out->firstelement, out->firstelement + out->num_triangles * 3, loadmodel->brushq3.num_triangles * 3); + Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid element range %i : %i (%i elements)\n", i, out->texture->name, firstelement, firstelement + out->num_triangles * 3, loadmodel->brushq3.num_triangles * 3); out->num_vertices = 0; out->num_triangles = 0; - out->type = 0; // error + type = 0; // error continue; } - switch(out->type) + switch(type) { case Q3FACETYPE_POLYGON: case Q3FACETYPE_MESH: // no processing necessary - out->data_vertex3f = loadmodel->brushq3.data_vertex3f + out->firstvertex * 3; - out->data_texcoordtexture2f = loadmodel->brushq3.data_texcoordtexture2f + out->firstvertex * 2; - out->data_texcoordlightmap2f = loadmodel->brushq3.data_texcoordlightmap2f + out->firstvertex * 2; - out->data_svector3f = loadmodel->brushq3.data_svector3f + out->firstvertex * 3; - out->data_tvector3f = loadmodel->brushq3.data_tvector3f + out->firstvertex * 3; - out->data_normal3f = loadmodel->brushq3.data_normal3f + out->firstvertex * 3; - out->data_color4f = loadmodel->brushq3.data_color4f + out->firstvertex * 4; - out->data_element3i = loadmodel->brushq3.data_element3i + out->firstelement; - out->data_neighbor3i = loadmodel->brushq3.data_neighbor3i + out->firstelement; + out->data_vertex3f = loadmodel->brushq3.data_vertex3f + firstvertex * 3; + out->data_texcoordtexture2f = loadmodel->brushq3.data_texcoordtexture2f + firstvertex * 2; + out->data_texcoordlightmap2f = loadmodel->brushq3.data_texcoordlightmap2f + firstvertex * 2; + out->data_svector3f = loadmodel->brushq3.data_svector3f + firstvertex * 3; + out->data_tvector3f = loadmodel->brushq3.data_tvector3f + firstvertex * 3; + out->data_normal3f = loadmodel->brushq3.data_normal3f + firstvertex * 3; + out->data_color4f = loadmodel->brushq3.data_color4f + firstvertex * 4; + out->data_element3i = loadmodel->brushq3.data_element3i + firstelement; + out->data_neighbor3i = loadmodel->brushq3.data_neighbor3i + firstelement; break; case Q3FACETYPE_PATCH: patchsize[0] = LittleLong(in->specific.patch.patchsize[0]); @@ -4137,18 +4137,18 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l) Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid patchsize %ix%i\n", i, out->texture->name, patchsize[0], patchsize[1]); out->num_vertices = 0; out->num_triangles = 0; - out->type = 0; // error + type = 0; // error continue; } - originalvertex3f = loadmodel->brushq3.data_vertex3f + out->firstvertex * 3; - //originalsvector3f = loadmodel->brushq3.data_svector3f + out->firstvertex * 3; - //originaltvector3f = loadmodel->brushq3.data_tvector3f + out->firstvertex * 3; - //originalnormal3f = loadmodel->brushq3.data_normal3f + out->firstvertex * 3; - originaltexcoordtexture2f = loadmodel->brushq3.data_texcoordtexture2f + out->firstvertex * 2; - originaltexcoordlightmap2f = loadmodel->brushq3.data_texcoordlightmap2f + out->firstvertex * 2; - originalcolor4f = loadmodel->brushq3.data_color4f + out->firstvertex * 4; - //originalelement3i = loadmodel->brushq3.data_element3i + out->firstelement; - //originalneighbor3i = loadmodel->brushq3.data_neighbor3i + out->firstelement; + originalvertex3f = loadmodel->brushq3.data_vertex3f + firstvertex * 3; + //originalsvector3f = loadmodel->brushq3.data_svector3f + firstvertex * 3; + //originaltvector3f = loadmodel->brushq3.data_tvector3f + firstvertex * 3; + //originalnormal3f = loadmodel->brushq3.data_normal3f + firstvertex * 3; + originaltexcoordtexture2f = loadmodel->brushq3.data_texcoordtexture2f + firstvertex * 2; + originaltexcoordlightmap2f = loadmodel->brushq3.data_texcoordlightmap2f + firstvertex * 2; + originalcolor4f = loadmodel->brushq3.data_color4f + firstvertex * 4; + //originalelement3i = loadmodel->brushq3.data_element3i + firstelement; + //originalneighbor3i = loadmodel->brushq3.data_neighbor3i + firstelement; /* originalvertex3f = out->data_vertex3f; //originalsvector3f = out->data_svector3f; @@ -4190,10 +4190,10 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l) out->data_texcoordlightmap2f = out->data_texcoordtexture2f + finalvertices * 2; out->data_element3i = Mem_Alloc(loadmodel->mempool, sizeof(int[6]) * finaltriangles); out->data_neighbor3i = out->data_element3i + finaltriangles * 3; - out->type = Q3FACETYPE_MESH; - out->firstvertex = -1; + type = Q3FACETYPE_MESH; + firstvertex = -1; out->num_vertices = finalvertices; - out->firstelement = -1; + firstelement = -1; out->num_triangles = finaltriangles; // generate geometry // (note: normals are skipped because they get recalculated) @@ -4229,7 +4229,6 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l) } // q3map does not put in collision brushes for curves... ugh // build the lower quality collision geometry - out->collisions = true; xlevel = QuadraticBSplinePatchSubdivisionLevelOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value, 10); ylevel = QuadraticBSplinePatchSubdivisionLevelOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value, 10); // bound to user settings @@ -4287,7 +4286,7 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l) // don't render it out->num_vertices = 0; out->num_triangles = 0; - out->type = 0; + type = 0; break; } for (j = 0, invalidelements = 0;j < out->num_triangles * 3;j++) @@ -4295,7 +4294,7 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l) invalidelements++; if (invalidelements) { - Con_Printf("Mod_Q3BSP_LoadFaces: Warning: face #%i has %i invalid elements, type = %i, texture->name = \"%s\", texture->surfaceflags = %i, texture->nativecontents = %i, firstvertex = %i, numvertices = %i, firstelement = %i, numelements = %i, elements list:\n", i, invalidelements, out->type, out->texture->name, out->texture->surfaceflags, out->texture->nativecontents, out->firstvertex, out->num_vertices, out->firstelement, out->num_triangles * 3); + Con_Printf("Mod_Q3BSP_LoadFaces: Warning: face #%i has %i invalid elements, type = %i, texture->name = \"%s\", texture->surfaceflags = %i, texture->nativecontents = %i, firstvertex = %i, numvertices = %i, firstelement = %i, numelements = %i, elements list:\n", i, invalidelements, type, out->texture->name, out->texture->surfaceflags, out->texture->nativecontents, firstvertex, out->num_vertices, firstelement, out->num_triangles * 3); for (j = 0;j < out->num_triangles * 3;j++) { Con_Printf(" %i", out->data_element3i[j]); @@ -4499,12 +4498,15 @@ static void Mod_Q3BSP_LoadLeafFaces(lump_t *l) loadmodel->brushq3.data_leaffaces = out; loadmodel->brushq3.num_leaffaces = count; + loadmodel->brushq3.data_leaffacenums = Mem_Alloc(loadmodel->mempool, count * sizeof(int)); + for (i = 0;i < count;i++, in++, out++) { n = LittleLong(*in); if (n < 0 || n >= loadmodel->brushq3.num_faces) Host_Error("Mod_Q3BSP_LoadLeafFaces: invalid face index %i (%i faces)\n", n, loadmodel->brushq3.num_faces); *out = loadmodel->brushq3.data_faces + n; + loadmodel->brushq3.data_leaffacenums[i] = n; } } @@ -4540,6 +4542,7 @@ static void Mod_Q3BSP_LoadLeafs(lump_t *l) if (n < 0 || n + c > loadmodel->brushq3.num_leaffaces) Host_Error("Mod_Q3BSP_LoadLeafs: invalid leafface range %i : %i (%i leaffaces)\n", n, n + c, loadmodel->brushq3.num_leaffaces); out->firstleafface = loadmodel->brushq3.data_leaffaces + n; + out->firstleaffacenum = loadmodel->brushq3.data_leaffacenums + n; out->numleaffaces = c; n = LittleLong(in->firstleafbrush); c = LittleLong(in->numleafbrushes); @@ -4866,7 +4869,7 @@ static void Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace_t *trace, q3mnode_t *node for (i = 0;i < leaf->numleaffaces;i++) { face = leaf->firstleafface[i]; - if (face->collisions && face->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, face->mins, face->maxs)) + if (face->num_collisiontriangles && face->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, face->mins, face->maxs)) { face->collisionmarkframe = markframe; Collision_TraceLineTriangleMeshFloat(trace, linestart, lineend, face->num_collisiontriangles, face->data_collisionelement3i, face->data_collisionvertex3f, face->texture->supercontents, segmentmins, segmentmaxs); @@ -5246,9 +5249,9 @@ static void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, q3mnode_t *nod for (i = 0;i < leaf->numleaffaces;i++) { face = leaf->firstleafface[i]; - if (face->collisions && face->markframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, face->mins, face->maxs)) + if (face->num_collisiontriangles && face->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, face->mins, face->maxs)) { - face->markframe = markframe; + face->collisionmarkframe = markframe; Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, face->num_collisiontriangles, face->data_collisionelement3i, face->data_collisionvertex3f, face->texture->supercontents, segmentmins, segmentmaxs); } } @@ -5302,7 +5305,7 @@ static void Mod_Q3BSP_TraceBox(model_t *model, int frame, trace_t *trace, const for (i = 0;i < model->brushq3.data_thismodel->numfaces;i++) { face = model->brushq3.data_thismodel->firstface + i; - if (face->collisions) + if (face->num_collisiontriangles) Collision_TraceLineTriangleMeshFloat(trace, boxstartmins, boxendmins, face->num_collisiontriangles, face->data_collisionelement3i, face->data_collisionvertex3f, face->texture->supercontents, segmentmins, segmentmaxs); } } @@ -5326,7 +5329,7 @@ static void Mod_Q3BSP_TraceBox(model_t *model, int frame, trace_t *trace, const for (i = 0;i < model->brushq3.data_thismodel->numfaces;i++) { face = model->brushq3.data_thismodel->firstface + i; - if (face->collisions) + if (face->num_collisiontriangles) Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, face->num_collisiontriangles, face->data_collisionelement3i, face->data_collisionvertex3f, face->texture->supercontents, segmentmins, segmentmaxs); } } @@ -5540,6 +5543,30 @@ void Mod_Q3BSP_GetVisible(model_t *model, const vec3_t point, const vec3_t mins, } */ +void Mod_Q3BSP_BuildTextureFaceLists(void) +{ + int i, j; + loadmodel->brushq3.data_texturefaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummodelsurfaces * sizeof(q3msurface_t *)); + loadmodel->brushq3.data_texturefacenums = Mem_Alloc(loadmodel->mempool, loadmodel->nummodelsurfaces * sizeof(int)); + for (i = 0;i < loadmodel->brushq3.num_textures;i++) + loadmodel->brushq3.data_textures[i].numfaces = 0; + for (i = 0;i < loadmodel->nummodelsurfaces;i++) + loadmodel->brushq3.data_faces[loadmodel->surfacelist[i]].texture->numfaces++; + j = 0; + for (i = 0;i < loadmodel->brushq3.num_textures;i++) + { + loadmodel->brushq3.data_textures[i].facelist = loadmodel->brushq3.data_texturefaces + j; + loadmodel->brushq3.data_textures[i].facenumlist = loadmodel->brushq3.data_texturefacenums + j; + j += loadmodel->brushq3.data_textures[i].numfaces; + loadmodel->brushq3.data_textures[i].numfaces = 0; + } + for (i = 0;i < loadmodel->nummodelsurfaces;i++) + { + loadmodel->brushq3.data_faces[loadmodel->surfacelist[i]].texture->facenumlist[loadmodel->brushq3.data_faces[loadmodel->surfacelist[i]].texture->numfaces] = loadmodel->surfacelist[i]; + loadmodel->brushq3.data_faces[loadmodel->surfacelist[i]].texture->facelist[loadmodel->brushq3.data_faces[loadmodel->surfacelist[i]].texture->numfaces++] = loadmodel->brushq3.data_faces + loadmodel->surfacelist[i]; + } +} + void Mod_Q3BSP_RecursiveFindNumLeafs(q3mnode_t *node) { int numleafs; @@ -5698,6 +5725,8 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer) if (j < mod->brushq3.data_thismodel->numfaces) mod->DrawSky = R_Q3BSP_DrawSky; } + + Mod_Q3BSP_BuildTextureFaceLists(); } void Mod_IBSP_Load(model_t *mod, void *buffer) diff --git a/model_shared.h b/model_shared.h index 516cf45f..2c3630ea 100644 --- a/model_shared.h +++ b/model_shared.h @@ -327,6 +327,7 @@ model_brushq2_t; #define Q3SURFACEPARM_TRANS 16777216 #define Q3SURFACEPARM_WATER 33554432 +struct q3msurface_s; typedef struct q3mtexture_s { char name[Q3PATHLENGTH]; @@ -337,6 +338,10 @@ typedef struct q3mtexture_s int number; skinframe_t skin; + + int numfaces; + struct q3msurface_s **facelist; + int *facenumlist; } q3mtexture_t; @@ -363,7 +368,8 @@ typedef struct q3mleaf_s int clusterindex; int areaindex; int numleaffaces; - struct q3mface_s **firstleafface; + struct q3msurface_s **firstleafface; + int *firstleaffacenum; int numleafbrushes; struct q3mbrush_s **firstleafbrush; } @@ -374,7 +380,7 @@ typedef struct q3mmodel_s vec3_t mins; vec3_t maxs; int numfaces; - struct q3mface_s *firstface; + struct q3msurface_s *firstface; int numbrushes; struct q3mbrush_s *firstbrush; } @@ -404,21 +410,17 @@ typedef struct q3meffect_s } q3meffect_t; -typedef struct q3mface_s +typedef struct q3msurface_s { + // FIXME: collisionmarkframe should be kept in a separate array + // FIXME: visframe should be kept in a separate array + // FIXME: shadowmark should be kept in a separate array + struct q3mtexture_s *texture; struct q3meffect_s *effect; rtexture_t *lightmaptexture; - int collisions; // performs per triangle collisions on this surface int collisionmarkframe; // don't collide twice in one trace - int type; - int firstvertex; - int firstelement; - int patchsize[2]; - // used for processing - int markframe; - // (world only) visframe == r_framecount means it is visible this frame - int visframe; + int visframe; // visframe == r_framecount means it is visible this frame // bounding box for culling float mins[3]; float maxs[3]; @@ -442,12 +444,9 @@ typedef struct q3mface_s // index into model->brush.shadowmesh int num_firstshadowmeshtriangle; - + // used for shadow volume generation int shadowmark; - - // temporary use by light processing - int lighttemp_castshadow; } q3msurface_t; @@ -459,6 +458,8 @@ typedef struct model_brushq3_s int num_textures; q3mtexture_t *data_textures; + q3msurface_t **data_texturefaces; + int *data_texturefacenums; int num_planes; mplane_t *data_planes; @@ -474,6 +475,7 @@ typedef struct model_brushq3_s int num_leaffaces; q3msurface_t **data_leaffaces; + int *data_leaffacenums; int num_models; q3mmodel_t *data_models; -- 2.39.2