From 7a001bd650455489c03aa3ec81471774a36ab4fb Mon Sep 17 00:00:00 2001 From: havoc Date: Sun, 29 Mar 2009 13:29:01 +0000 Subject: [PATCH] compute sorted surface list at load of each model - this tripled framerates in some outdoor q1bsp maps cleaned up water rendering setup code so it at least makes sense now model lighting is not computed for unseen models (major fps increase in some q1bsp maps) added an unfinished OBJ model loader (not enabled) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@8832 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_main.c | 32 +--- gl_rmain.c | 407 ++++++++++++++++++++++++++++++-------------- gl_rsurf.c | 83 ++++++--- model_alias.c | 454 +++++++++++++++++++++++++++++++++++++++++++++++-- model_brush.c | 10 +- model_shared.c | 36 +++- model_shared.h | 6 + r_shadow.c | 6 +- r_sprites.c | 3 +- render.h | 17 +- todo | 5 +- 11 files changed, 847 insertions(+), 212 deletions(-) diff --git a/cl_main.c b/cl_main.c index a66560cc..bcaec418 100644 --- a/cl_main.c +++ b/cl_main.c @@ -487,32 +487,13 @@ static void CL_SoundIndexList_f(void) } } -static void CL_UpdateRenderEntity_Lighting(entity_render_t *ent) -{ - vec3_t tempdiffusenormal; - - // fetch the lighting from the worldmodel data - VectorSet(ent->modellight_ambient, r_refdef.scene.ambient * (2.0f / 128.0f), r_refdef.scene.ambient * (2.0f / 128.0f), r_refdef.scene.ambient * (2.0f / 128.0f)); - VectorClear(ent->modellight_diffuse); - VectorClear(tempdiffusenormal); - if ((ent->flags & RENDER_LIGHT) && cl.worldmodel && cl.worldmodel->brush.LightPoint) - { - vec3_t org; - Matrix4x4_OriginFromMatrix(&ent->matrix, org); - cl.worldmodel->brush.LightPoint(cl.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal); - } - else // highly rare - VectorSet(ent->modellight_ambient, 1, 1, 1); - - // move the light direction into modelspace coordinates for lighting code - Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir); - if(VectorLength2(ent->modellight_lightdir) <= 0) - VectorSet(ent->modellight_lightdir, 0, 0, 1); // have to set SOME valid vector here - VectorNormalize(ent->modellight_lightdir); -} +/* +=============== +CL_UpdateRenderEntity -//static const vec3_t nomodelmins = {-16, -16, -16}; -//static const vec3_t nomodelmaxs = {16, 16, 16}; +Updates inversematrix, animation interpolation factors, scale, and mins/maxs +=============== +*/ void CL_UpdateRenderEntity(entity_render_t *ent) { vec3_t org; @@ -564,7 +545,6 @@ void CL_UpdateRenderEntity(entity_render_t *ent) ent->maxs[1] = org[1] + 16; ent->maxs[2] = org[2] + 16; } - CL_UpdateRenderEntity_Lighting(ent); } /* diff --git a/gl_rmain.c b/gl_rmain.c index 440537ef..4cfbdddf 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -28,6 +28,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. mempool_t *r_main_mempool; rtexturepool_t *r_main_texturepool; +static int r_frame = 0; // used only by R_GetCurrentTexture + // // screen size info // @@ -2601,6 +2603,51 @@ int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, c //================================================================================== +static void R_View_UpdateEntityLighting (void) +{ + int i; + entity_render_t *ent; + vec3_t tempdiffusenormal; + + for (i = 0;i < r_refdef.scene.numentities;i++) + { + ent = r_refdef.scene.entities[i]; + + // skip unseen models + if (!r_refdef.viewcache.entityvisible[i] && r_shadows.integer != 1) + continue; + + // skip bsp models + if (ent->model && ent->model->brush.num_leafs) + { + // TODO: use modellight for r_ambient settings on world? + VectorSet(ent->modellight_ambient, 0, 0, 0); + VectorSet(ent->modellight_diffuse, 0, 0, 0); + VectorSet(ent->modellight_lightdir, 0, 0, 1); + continue; + } + + // fetch the lighting from the worldmodel data + VectorSet(ent->modellight_ambient, r_refdef.scene.ambient * (2.0f / 128.0f), r_refdef.scene.ambient * (2.0f / 128.0f), r_refdef.scene.ambient * (2.0f / 128.0f)); + VectorClear(ent->modellight_diffuse); + VectorClear(tempdiffusenormal); + if ((ent->flags & RENDER_LIGHT) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint) + { + vec3_t org; + Matrix4x4_OriginFromMatrix(&ent->matrix, org); + r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal); + } + else // highly rare + VectorSet(ent->modellight_ambient, 1, 1, 1); + + // move the light direction into modelspace coordinates for lighting code + Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir); + if(VectorLength2(ent->modellight_lightdir) == 0) + VectorSet(ent->modellight_lightdir, 0, 0, 1); // have to set SOME valid vector here + VectorNormalize(ent->modellight_lightdir); + } +} + static void R_View_UpdateEntityVisible (void) { int i, renderimask; @@ -2907,6 +2954,7 @@ void R_View_Update(void) R_View_SetFrustum(); R_View_WorldVisibility(r_refdef.view.useclipplane); R_View_UpdateEntityVisible(); + R_View_UpdateEntityLighting(); } void R_SetupView(qboolean allowwaterclippingplane) @@ -2989,7 +3037,8 @@ void R_ResetViewRendering3D(void) R_SetupGenericShader(true); } -void R_RenderScene(qboolean addwaterplanes); +void R_RenderScene(void); +void R_RenderWaterPlanes(void); static void R_Water_StartFrame(void) { @@ -3052,7 +3101,7 @@ static void R_Water_StartFrame(void) r_waterstate.numwaterplanes = 0; } -static void R_Water_AddWaterPlane(msurface_t *surface) +void R_Water_AddWaterPlane(msurface_t *surface) { int triangleindex, planeindex; const int *e; @@ -3061,6 +3110,7 @@ static void R_Water_AddWaterPlane(msurface_t *surface) vec3_t center; mplane_t plane; r_waterstate_waterplane_t *p; + texture_t *t = R_GetCurrentTexture(surface->texture); // just use the first triangle with a valid normal for any decisions VectorClear(normal); for (triangleindex = 0, e = rsurface.modelelement3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3) @@ -3080,7 +3130,7 @@ static void R_Water_AddWaterPlane(msurface_t *surface) if (PlaneDiff(r_refdef.view.origin, &plane) < 0) { // skip backfaces (except if nocullface is set) - if (!(surface->texture->currentframe->currentmaterialflags & MATERIALFLAG_NOCULLFACE)) + if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE)) return; VectorNegate(plane.normal, plane.normal); plane.dist *= -1; @@ -3106,7 +3156,7 @@ static void R_Water_AddWaterPlane(msurface_t *surface) p->pvsvalid = false; } // merge this surface's materialflags into the waterplane - p->materialflags |= surface->texture->currentframe->currentmaterialflags; + p->materialflags |= t->currentmaterialflags; // merge this surface's PVS into the waterplane VectorMAM(0.5f, surface->mins, 0.5f, surface->maxs, center); if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS @@ -3120,6 +3170,7 @@ static void R_Water_AddWaterPlane(msurface_t *surface) static void R_Water_ProcessPlanes(void) { r_refdef_view_t originalview; + r_refdef_view_t myview; int planeindex; r_waterstate_waterplane_t *p; @@ -3146,24 +3197,29 @@ static void R_Water_ProcessPlanes(void) } // render views + r_refdef.view = originalview; + r_refdef.view.showdebug = false; + r_refdef.view.width = r_waterstate.waterwidth; + r_refdef.view.height = r_waterstate.waterheight; + r_refdef.view.useclipplane = true; + myview = r_refdef.view; + r_waterstate.renderingscene = true; for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++) { - r_refdef.view.showdebug = false; - r_refdef.view.width = r_waterstate.waterwidth; - r_refdef.view.height = r_waterstate.waterheight; - r_refdef.view.useclipplane = true; - r_waterstate.renderingscene = true; - // render the normal view scene and copy into texture // (except that a clipping plane should be used to hide everything on one side of the water, and the viewer's weapon model should be omitted) if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION)) { + r_refdef.view = myview; r_refdef.view.clipplane = p->plane; VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal); r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist; PlaneClassify(&r_refdef.view.clipplane); - R_RenderScene(false); + R_ResetViewRendering3D(); + R_ClearScreen(r_refdef.fogenabled); + R_View_Update(); + R_RenderScene(); // copy view into the screen texture R_Mesh_TexBind(0, R_GetTexture(p->texture_refraction)); @@ -3174,6 +3230,7 @@ static void R_Water_ProcessPlanes(void) if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)) { + r_refdef.view = myview; // render reflected scene and copy into texture Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2); // update the r_refdef.view.origin because otherwise the sky renders at the wrong location (amongst other problems) @@ -3193,26 +3250,20 @@ static void R_Water_ProcessPlanes(void) R_ResetViewRendering3D(); R_ClearScreen(r_refdef.fogenabled); - if (r_timereport_active) - R_TimeReport("viewclear"); - - R_RenderScene(false); + R_View_Update(); + R_RenderScene(); R_Mesh_TexBind(0, R_GetTexture(p->texture_reflection)); GL_ActiveTexture(0); CHECKGLERROR qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR - - R_ResetViewRendering3D(); - R_ClearScreen(r_refdef.fogenabled); - if (r_timereport_active) - R_TimeReport("viewclear"); } - - r_refdef.view = originalview; - r_refdef.view.clear = true; - r_waterstate.renderingscene = false; } + r_waterstate.renderingscene = false; + r_refdef.view = originalview; + R_ResetViewRendering3D(); + R_ClearScreen(r_refdef.fogenabled); + R_View_Update(); return; error: r_refdef.view = originalview; @@ -3477,9 +3528,17 @@ void R_HDR_RenderBloomTexture(void) if (r_timereport_active) R_TimeReport("HDRclear"); + R_View_Update(); + if (r_timereport_active) + R_TimeReport("visibility"); + r_waterstate.numwaterplanes = 0; - R_RenderScene(r_waterstate.enabled); + if (r_waterstate.enabled) + R_RenderWaterPlanes(); + r_refdef.view.showdebug = true; + R_RenderScene(); + r_waterstate.numwaterplanes = 0; R_ResetViewRendering2D(); @@ -3646,8 +3705,6 @@ static void R_BlendView(void) } } -void R_RenderScene(qboolean addwaterplanes); - matrix4x4_t r_waterscrollmatrix; void R_UpdateFogColor(void) // needs to be called before HDR subrender too, as that changes colorscale! @@ -3837,6 +3894,9 @@ R_RenderView */ void R_RenderView(void) { + r_frame++; // used only by R_GetCurrentTexture + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity + if (r_refdef.view.isoverlay) { // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas] @@ -3848,7 +3908,7 @@ void R_RenderView(void) r_waterstate.enabled = false; r_waterstate.numwaterplanes = 0; - R_RenderScene(false); + R_RenderScene(); CHECKGLERROR return; @@ -3886,14 +3946,22 @@ void R_RenderView(void) } r_refdef.view.clear = true; - r_refdef.view.showdebug = true; - // this produces a bloom texture to be used in R_BlendView() later if (r_hdr.integer) R_HDR_RenderBloomTexture(); + r_refdef.view.showdebug = true; + + R_View_Update(); + if (r_timereport_active) + R_TimeReport("visibility"); + + r_waterstate.numwaterplanes = 0; + if (r_waterstate.enabled) + R_RenderWaterPlanes(); + + R_RenderScene(); r_waterstate.numwaterplanes = 0; - R_RenderScene(r_waterstate.enabled); R_BlendView(); if (r_timereport_active) @@ -3904,47 +3972,42 @@ void R_RenderView(void) CHECKGLERROR } -extern void R_DrawLightningBeams (void); -extern void VM_CL_AddPolygonsToMeshQueue (void); -extern void R_DrawPortals (void); -extern cvar_t cl_locs_show; -static void R_DrawLocs(void); -static void R_DrawEntityBBoxes(void); -void R_RenderScene(qboolean addwaterplanes) +void R_RenderWaterPlanes(void) { - r_refdef.stats.renders++; - - R_UpdateFogColor(); - - if (addwaterplanes) + if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes) { - R_ResetViewRendering3D(); - - R_View_Update(); + r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity); if (r_timereport_active) - R_TimeReport("watervis"); - - if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes) - { - r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity); - if (r_timereport_active) - R_TimeReport("waterworld"); - } + R_TimeReport("waterworld"); + } - // don't let sound skip if going slow - if (r_refdef.scene.extraupdate) - S_ExtraUpdate (); + // don't let sound skip if going slow + if (r_refdef.scene.extraupdate) + S_ExtraUpdate (); - R_DrawModelsAddWaterPlanes(); - if (r_timereport_active) - R_TimeReport("watermodels"); + R_DrawModelsAddWaterPlanes(); + if (r_timereport_active) + R_TimeReport("watermodels"); + if (r_waterstate.numwaterplanes) + { R_Water_ProcessPlanes(); if (r_timereport_active) R_TimeReport("waterscenes"); } +} - R_ResetViewRendering3D(); +extern void R_DrawLightningBeams (void); +extern void VM_CL_AddPolygonsToMeshQueue (void); +extern void R_DrawPortals (void); +extern cvar_t cl_locs_show; +static void R_DrawLocs(void); +static void R_DrawEntityBBoxes(void); +void R_RenderScene(void) +{ + r_refdef.stats.renders++; + + R_UpdateFogColor(); // don't let sound skip if going slow if (r_refdef.scene.extraupdate) @@ -3954,10 +4017,6 @@ void R_RenderScene(qboolean addwaterplanes) R_SkyStartFrame(); - R_View_Update(); - if (r_timereport_active) - R_TimeReport("visibility"); - Matrix4x4_CreateTranslate(&r_waterscrollmatrix, sin(r_refdef.scene.time) * 0.025 * r_waterscroll.value, sin(r_refdef.scene.time * 0.8f) * 0.025 * r_waterscroll.value, 0); if (cl.csqc_vidvars.drawworld) @@ -4555,20 +4614,20 @@ static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms) return (float)(parms[0] + parms[1] * f); } -void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) +texture_t *R_GetCurrentTexture(texture_t *t) { int w, h, idx; int i; + const entity_render_t *ent = rsurface.entity; dp_model_t *model = ent->model; float f; float tcmat[12]; q3shaderinfo_layer_tcmod_t *tcmod; - if (t->basematerialflags & MATERIALFLAG_NODRAW) - { - t->currentmaterialflags = t->basematerialflags & (MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW); - return; - } + if (t->update_lastrenderframe == r_frame && t->update_lastrenderentity == (void *)ent) + return t->currentframe; + t->update_lastrenderframe = r_frame; + t->update_lastrenderentity = (void *)ent; // switch to an alternate material if this is a q1bsp animated material { @@ -4848,14 +4907,8 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_BLENDED) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->currentskinframe->fog, &identitymatrix, r_refdef.fogcolor[0] / r_refdef.view.colorscale, r_refdef.fogcolor[1] / r_refdef.view.colorscale, r_refdef.fogcolor[2] / r_refdef.view.colorscale, t->lightmapcolor[3]); } } -} -void R_UpdateAllTextureInfo(entity_render_t *ent) -{ - int i; - if (ent->model) - for (i = 0;i < ent->model->num_texturesperskin;i++) - R_UpdateTextureInfo(ent, ent->model->data_textures + i); + return t->currentframe; } rsurfacestate_t rsurface; @@ -4885,6 +4938,9 @@ void R_Mesh_ResizeArrays(int newvertices) void RSurf_ActiveWorldEntity(void) { dp_model_t *model = r_refdef.scene.worldmodel; + //if (rsurface.entity == r_refdef.scene.worldentity) + // return; + rsurface.entity = r_refdef.scene.worldentity; if (rsurface.array_size < model->surfmesh.num_vertices) R_Mesh_ResizeArrays(model->surfmesh.num_vertices); rsurface.matrix = identitymatrix; @@ -4954,6 +5010,9 @@ void RSurf_ActiveWorldEntity(void) void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents) { dp_model_t *model = ent->model; + //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents))) + // return; + rsurface.entity = (entity_render_t *)ent; if (rsurface.array_size < model->surfmesh.num_vertices) R_Mesh_ResizeArrays(model->surfmesh.num_vertices); rsurface.matrix = ent->matrix; @@ -6561,7 +6620,22 @@ static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, msurf RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); } -static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth) +static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth) +{ + CHECKGLERROR + RSurf_SetupDepthAndCulling(); + if (r_showsurfaces.integer == 3) + R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth); + else if (r_glsl.integer && gl_support_fragment_shader) + R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth); + else if (gl_combine.integer && r_textureunits.integer >= 2) + R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist, writedepth); + else + R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist, writedepth); + CHECKGLERROR +} + +static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth) { CHECKGLERROR RSurf_SetupDepthAndCulling(); @@ -6599,8 +6673,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const j = i + 1; surface = rsurface.modelsurfaces + surfacelist[i]; texture = surface->texture; - R_UpdateTextureInfo(ent, texture); - rsurface.texture = texture->currentframe; + rsurface.texture = R_GetCurrentTexture(texture); rsurface.uselightmaptexture = surface->lightmaptexture != NULL; // scan ahead until we find a different texture endsurface = min(i + 1024, numsurfaces); @@ -6614,13 +6687,18 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const texturesurfacelist[texturenumsurfaces++] = surface; } // render the range of surfaces - R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false); + if (ent == r_refdef.scene.worldentity) + R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false); + else + R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false); } + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity GL_AlphaTest(false); } -static void R_ProcessTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity) +static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly) { + const entity_render_t *queueentity = r_refdef.scene.worldentity; CHECKGLERROR if (depthonly) { @@ -6682,23 +6760,113 @@ static void R_ProcessTextureSurfaceList(int texturenumsurfaces, msurface_t **tex else { // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier - R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)); + R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)); } CHECKGLERROR } -void R_QueueSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes) +void R_QueueWorldSurfaceList(int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly) { int i, j; texture_t *texture; - // if we're rendering water textures (extra scene renders), use a separate loop to avoid burdening the main one - if (addwaterplanes) + // break the surface list down into batches by texture and use of lightmapping + for (i = 0;i < numsurfaces;i = j) + { + j = i + 1; + // texture is the base texture pointer, rsurface.texture is the + // current frame/skin the texture is directing us to use (for example + // if a model has 2 skins and it is on skin 1, then skin 0 tells us to + // use skin 1 instead) + texture = surfacelist[i]->texture; + rsurface.texture = R_GetCurrentTexture(texture); + rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL; + if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW)) + { + // if this texture is not the kind we want, skip ahead to the next one + for (;j < numsurfaces && texture == surfacelist[j]->texture;j++) + ; + continue; + } + // simply scan ahead until we find a different texture or lightmap state + for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++) + ; + // render the range of surfaces + R_ProcessWorldTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly); + } +} + +static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity) +{ + CHECKGLERROR + if (depthonly) + { + if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST))) + return; + if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))) + return; + RSurf_SetupDepthAndCulling(); + RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); + RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + } + else if (r_showsurfaces.integer && !r_refdef.view.showdebug) + { + RSurf_SetupDepthAndCulling(); + GL_AlphaTest(false); + R_Mesh_ColorPointer(NULL, 0, 0); + R_Mesh_ResetTextureState(); + R_SetupGenericShader(false); + RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); + GL_DepthMask(true); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_Color(0, 0, 0, 1); + GL_DepthTest(writedepth); + RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + } + else if (r_showsurfaces.integer && r_showsurfaces.integer != 3) { - for (i = 0;i < numsurfaces;i++) - if (surfacelist[i]->texture->currentframe->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION)) - R_Water_AddWaterPlane(surfacelist[i]); + RSurf_SetupDepthAndCulling(); + GL_AlphaTest(false); + R_Mesh_ColorPointer(NULL, 0, 0); + R_Mesh_ResetTextureState(); + R_SetupGenericShader(false); + RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); + GL_DepthMask(true); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_DepthTest(true); + RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist); + } + else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) + R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist); + else if (!rsurface.texture->currentnumlayers) return; + else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))) && queueentity) + { + // transparent surfaces get pushed off into the transparent queue + int surfacelistindex; + const msurface_t *surface; + vec3_t tempcenter, center; + for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++) + { + surface = texturesurfacelist[surfacelistindex]; + tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f; + tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f; + tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f; + Matrix4x4_Transform(&rsurface.matrix, tempcenter, center); + R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_refdef.view.origin : center, R_DrawSurface_TransparentCallback, queueentity, surface - rsurface.modelsurfaces, rsurface.rtlight); + } + } + else + { + // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier + R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)); } + CHECKGLERROR +} + +void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly) +{ + int i, j; + texture_t *texture; // break the surface list down into batches by texture and use of lightmapping for (i = 0;i < numsurfaces;i = j) { @@ -6708,7 +6876,7 @@ void R_QueueSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surf // if a model has 2 skins and it is on skin 1, then skin 0 tells us to // use skin 1 instead) texture = surfacelist[i]->texture; - rsurface.texture = texture->currentframe; + rsurface.texture = R_GetCurrentTexture(texture); rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL; if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW)) { @@ -6721,7 +6889,7 @@ void R_QueueSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surf for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++) ; // render the range of surfaces - R_ProcessTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent); + R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent); } } @@ -6862,7 +7030,7 @@ void R_DrawDebugModel(entity_render_t *ent) { if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j]) continue; - rsurface.texture = surface->texture->currentframe; + rsurface.texture = R_GetCurrentTexture(surface->texture); if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles) { RSurf_PrepareVerticesForBatch(true, true, 1, &surface); @@ -6947,7 +7115,7 @@ void R_DrawDebugModel(entity_render_t *ent) extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface); int r_maxsurfacelist = 0; msurface_t **r_surfacelist = NULL; -void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes, qboolean debug) +void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug) { int i, j, endj, f, flagsmask; texture_t *t; @@ -6972,7 +7140,7 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep update = model->brushq1.lightmapupdateflags; // update light styles on this submodel - if (!skysurfaces && !depthonly && !addwaterplanes && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0) + if (!skysurfaces && !depthonly && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0) { model_brush_lightstyleinfo_t *style; for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++) @@ -6987,8 +7155,7 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep } } - R_UpdateAllTextureInfo(r_refdef.scene.worldentity); - flagsmask = addwaterplanes ? (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) : (skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL); + flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL; if (debug) { @@ -7003,33 +7170,26 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep rsurface.rtlight = NULL; numsurfacelist = 0; // add visible surfaces to draw list - j = model->firstmodelsurface; - endj = j + model->nummodelsurfaces; - if (update) + for (i = 0;i < model->nummodelsurfaces;i++) { - for (;j < endj;j++) - { + j = model->sortedmodelsurfaces[i]; + if (r_refdef.viewcache.world_surfacevisible[j]) + r_surfacelist[numsurfacelist++] = surfaces + j; + } + // update lightmaps if needed + if (update) + for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++) if (r_refdef.viewcache.world_surfacevisible[j]) - { - r_surfacelist[numsurfacelist++] = surfaces + j; - // update lightmap if needed if (update[j]) R_BuildLightMap(r_refdef.scene.worldentity, surfaces + j); - } - } - } - else - for (;j < endj;j++) - if (r_refdef.viewcache.world_surfacevisible[j]) - r_surfacelist[numsurfacelist++] = surfaces + j; // don't do anything if there were no surfaces if (!numsurfacelist) return; - R_QueueSurfaceList(r_refdef.scene.worldentity, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, addwaterplanes); + R_QueueWorldSurfaceList(numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly); GL_AlphaTest(false); // add to stats if desired - if (r_speeds.integer && !skysurfaces && !depthonly && !addwaterplanes) + if (r_speeds.integer && !skysurfaces && !depthonly) { r_refdef.stats.world_surfaces += numsurfacelist; for (j = 0;j < numsurfacelist;j++) @@ -7037,7 +7197,7 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep } } -void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes, qboolean debug) +void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug) { int i, j, endj, f, flagsmask; texture_t *t; @@ -7070,7 +7230,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr update = model->brushq1.lightmapupdateflags; // update light styles - if (!skysurfaces && !depthonly && !addwaterplanes && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0) + if (!skysurfaces && !depthonly && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0) { model_brush_lightstyleinfo_t *style; for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++) @@ -7085,8 +7245,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr } } - R_UpdateAllTextureInfo(ent); - flagsmask = addwaterplanes ? (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) : (skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL); + flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL; if (debug) { @@ -7101,23 +7260,21 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr rsurface.rtlight = NULL; numsurfacelist = 0; // add visible surfaces to draw list - j = model->firstmodelsurface; - endj = j + model->nummodelsurfaces; - for (;j < endj;j++) - r_surfacelist[numsurfacelist++] = surfaces + j; + for (i = 0;i < model->nummodelsurfaces;i++) + r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i]; // don't do anything if there were no surfaces if (!numsurfacelist) return; // update lightmaps if needed if (update) - for (j = model->firstmodelsurface;j < endj;j++) + for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++) if (update[j]) R_BuildLightMap(ent, surfaces + j); - R_QueueSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, addwaterplanes); + R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly); GL_AlphaTest(false); // add to stats if desired - if (r_speeds.integer && !skysurfaces && !depthonly && !addwaterplanes) + if (r_speeds.integer && !skysurfaces && !depthonly) { r_refdef.stats.entities++; r_refdef.stats.entities_surfaces += numsurfacelist; diff --git a/gl_rsurf.c b/gl_rsurf.c index df0836a6..b3557b55 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -538,20 +538,48 @@ void R_Q1BSP_DrawSky(entity_render_t *ent) if (ent->model == NULL) return; if (ent == r_refdef.scene.worldentity) - R_DrawWorldSurfaces(true, true, false, false, false); + R_DrawWorldSurfaces(true, true, false, false); else - R_DrawModelSurfaces(ent, true, true, false, false, false); + R_DrawModelSurfaces(ent, true, true, false, false); } +extern void R_Water_AddWaterPlane(msurface_t *surface); void R_Q1BSP_DrawAddWaterPlanes(entity_render_t *ent) { + int i, j, flagsmask; dp_model_t *model = ent->model; + msurface_t *surfaces; if (model == NULL) return; + if (ent == r_refdef.scene.worldentity) - R_DrawWorldSurfaces(false, false, false, true, false); + RSurf_ActiveWorldEntity(); else - R_DrawModelSurfaces(ent, false, false, false, true, false); + RSurf_ActiveModelEntity(ent, false, false); + + surfaces = model->data_surfaces; + flagsmask = MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION; + + // add visible surfaces to draw list + if (ent == r_refdef.scene.worldentity) + { + for (i = 0;i < model->nummodelsurfaces;i++) + { + j = model->sortedmodelsurfaces[i]; + if (r_refdef.viewcache.world_surfacevisible[j]) + if (surfaces[j].texture->basematerialflags & flagsmask) + R_Water_AddWaterPlane(surfaces + j); + } + } + else + { + for (i = 0;i < model->nummodelsurfaces;i++) + { + j = model->sortedmodelsurfaces[i]; + if (surfaces[j].texture->basematerialflags & flagsmask) + R_Water_AddWaterPlane(surfaces + j); + } + } } void R_Q1BSP_Draw(entity_render_t *ent) @@ -560,9 +588,9 @@ void R_Q1BSP_Draw(entity_render_t *ent) if (model == NULL) return; if (ent == r_refdef.scene.worldentity) - R_DrawWorldSurfaces(false, true, false, false, false); + R_DrawWorldSurfaces(false, true, false, false); else - R_DrawModelSurfaces(ent, false, true, false, false, false); + R_DrawModelSurfaces(ent, false, true, false, false); } void R_Q1BSP_DrawDepth(entity_render_t *ent) @@ -580,9 +608,9 @@ void R_Q1BSP_DrawDepth(entity_render_t *ent) R_Mesh_ResetTextureState(); R_SetupDepthOrShadowShader(); if (ent == r_refdef.scene.worldentity) - R_DrawWorldSurfaces(false, false, true, false, false); + R_DrawWorldSurfaces(false, false, true, false); else - R_DrawModelSurfaces(ent, false, false, true, false, false); + R_DrawModelSurfaces(ent, false, false, true, false); GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); } @@ -591,9 +619,9 @@ void R_Q1BSP_DrawDebug(entity_render_t *ent) if (ent->model == NULL) return; if (ent == r_refdef.scene.worldentity) - R_DrawWorldSurfaces(false, false, false, false, true); + R_DrawWorldSurfaces(false, false, false, true); else - R_DrawModelSurfaces(ent, false, false, false, false, true); + R_DrawModelSurfaces(ent, false, false, false, true); } typedef struct r_q1bsp_getlightinfo_s @@ -621,7 +649,7 @@ typedef struct r_q1bsp_getlightinfo_s } r_q1bsp_getlightinfo_t; -void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node) +static void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node) { int sides; mleaf_t *leaf; @@ -721,6 +749,7 @@ void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node) int leafsurfaceindex; int surfaceindex; int triangleindex, t; + int currentmaterialflags; msurface_t *surface; const int *e; const vec_t *v[3]; @@ -731,8 +760,9 @@ void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node) if (!CHECKPVSBIT(info->outsurfacepvs, surfaceindex)) { surface = info->model->data_surfaces + surfaceindex; + currentmaterialflags = R_GetCurrentTexture(surface->texture)->currentmaterialflags; if (BoxesOverlap(info->lightmins, info->lightmaxs, surface->mins, surface->maxs) - && (!info->svbsp_insertoccluder || !(surface->texture->currentframe->currentmaterialflags & MATERIALFLAG_NOSHADOW))) + && (!info->svbsp_insertoccluder || !(currentmaterialflags & MATERIALFLAG_NOSHADOW))) { qboolean addedtris = false; qboolean insidebox = BoxInsideBox(surface->mins, surface->maxs, info->lightmins, info->lightmaxs); @@ -745,9 +775,9 @@ void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node) { if (info->svbsp_insertoccluder) { - if (!(surface->texture->currentframe->currentmaterialflags & MATERIALFLAG_NOCULLFACE) && r_shadow_frontsidecasting.integer != PointInfrontOfTriangle(info->relativelightorigin, v[0], v[1], v[2])) + if (!(currentmaterialflags & MATERIALFLAG_NOCULLFACE) && r_shadow_frontsidecasting.integer != PointInfrontOfTriangle(info->relativelightorigin, v[0], v[1], v[2])) continue; - if (surface->texture->currentframe->currentmaterialflags & MATERIALFLAG_NOSHADOW) + if (currentmaterialflags & MATERIALFLAG_NOSHADOW) continue; VectorCopy(v[0], v2[0]); VectorCopy(v[1], v2[1]); @@ -766,13 +796,13 @@ void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node) if (!(SVBSP_AddPolygon(&r_svbsp, 3, v2[0], false, NULL, NULL, 0) & 2)) continue; } - if (surface->texture->currentframe->currentmaterialflags & MATERIALFLAG_NOCULLFACE) + if (currentmaterialflags & MATERIALFLAG_NOCULLFACE) { // if the material is double sided we // can't cull by direction SETPVSBIT(info->outlighttrispvs, t); addedtris = true; - if (!(surface->texture->currentframe->currentmaterialflags & MATERIALFLAG_NOSHADOW)) + if (!(currentmaterialflags & MATERIALFLAG_NOSHADOW)) SETPVSBIT(info->outshadowtrispvs, t); } else if (r_shadow_frontsidecasting.integer) @@ -784,7 +814,7 @@ void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node) continue; SETPVSBIT(info->outlighttrispvs, t); addedtris = true; - if (!(surface->texture->currentframe->currentmaterialflags & MATERIALFLAG_NOSHADOW)) + if (!(currentmaterialflags & MATERIALFLAG_NOSHADOW)) SETPVSBIT(info->outshadowtrispvs, t); } else @@ -793,7 +823,7 @@ void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node) // anything so we can't cull lit polygons SETPVSBIT(info->outlighttrispvs, t); addedtris = true; - if (!PointInfrontOfTriangle(info->relativelightorigin, v[0], v[1], v[2]) && !(surface->texture->currentframe->currentmaterialflags & MATERIALFLAG_NOSHADOW)) + if (!PointInfrontOfTriangle(info->relativelightorigin, v[0], v[1], v[2]) && !(currentmaterialflags & MATERIALFLAG_NOSHADOW)) SETPVSBIT(info->outshadowtrispvs, t); } } @@ -810,7 +840,7 @@ void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node) } } -void R_Q1BSP_CallRecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, qboolean use_svbsp) +static void R_Q1BSP_CallRecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, qboolean use_svbsp) { if (use_svbsp) { @@ -926,7 +956,7 @@ void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, floa info.pvs = info.model->brush.GetPVS(info.model, info.relativelightorigin); else info.pvs = NULL; - R_UpdateAllTextureInfo(ent); + RSurf_ActiveWorldEntity(); if (r_shadow_frontsidecasting.integer && r_shadow_compilingrtlight && r_shadow_realtime_world_compileportalculling.integer && info.model->brush.data_portals) { @@ -970,7 +1000,7 @@ void R_Q1BSP_CompileShadowVolume(entity_render_t *ent, vec3_t relativelightorigi for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) { surface = model->data_surfaces + surfacelist[surfacelistindex]; - if (surface->texture->currentframe->basematerialflags & MATERIALFLAG_NOSHADOW) + if (surface->texture->basematerialflags & MATERIALFLAG_NOSHADOW) continue; R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, relativelightdirection, r_shadow_compilingrtlight->cullmins, r_shadow_compilingrtlight->cullmaxs, surface->mins, surface->maxs); } @@ -989,7 +1019,6 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, const vec3_t relativelightor // check the box in modelspace, it was already checked in worldspace if (!BoxesOverlap(model->normalmins, model->normalmaxs, lightmins, lightmaxs)) return; - R_UpdateAllTextureInfo(ent); if (ent->model->brush.submodel) GL_PolygonOffset(r_refdef.shadowpolygonfactor + r_polygonoffset_submodel_factor.value, r_refdef.shadowpolygonoffset + r_polygonoffset_submodel_offset.value); if (model->brush.shadowmesh) @@ -998,7 +1027,7 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, const vec3_t relativelightor for (modelsurfacelistindex = 0;modelsurfacelistindex < modelnumsurfaces;modelsurfacelistindex++) { surface = model->data_surfaces + modelsurfacelist[modelsurfacelistindex]; - if (surface->texture->currentframe->currentmaterialflags & MATERIALFLAG_NOSHADOW) + if (R_GetCurrentTexture(surface->texture)->currentmaterialflags & MATERIALFLAG_NOSHADOW) continue; R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, relativelightdirection, lightmins, lightmaxs, surface->mins, surface->maxs); } @@ -1012,7 +1041,7 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, const vec3_t relativelightor for (modelsurfacelistindex = 0;modelsurfacelistindex < modelnumsurfaces;modelsurfacelistindex++) { surface = model->data_surfaces + modelsurfacelist[modelsurfacelistindex]; - rsurface.texture = surface->texture->currentframe; + rsurface.texture = R_GetCurrentTexture(surface->texture); if (rsurface.texture->currentmaterialflags & MATERIALFLAG_NOSHADOW) continue; RSurf_PrepareVerticesForBatch(false, false, 1, &surface); @@ -1041,8 +1070,7 @@ static void R_Q1BSP_DrawLight_TransparentCallback(const entity_render_t *ent, co j = i + 1; surface = rsurface.modelsurfaces + surfacelist[i]; t = surface->texture; - R_UpdateTextureInfo(ent, t); - rsurface.texture = t->currentframe; + rsurface.texture = R_GetCurrentTexture(t); endsurface = min(j + BATCHSIZE, numsurfaces); for (j = i;j < endsurface;j++) { @@ -1069,7 +1097,6 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface int batchelements[BATCHSIZE*3]; texture_t *tex; CHECKGLERROR - R_UpdateAllTextureInfo(ent); culltriangles = r_shadow_culltriangles.integer && !(ent->flags & RENDER_NOSELFSHADOW); element3i = rsurface.modelelement3i; // this is a double loop because non-visible surface skipping has to be @@ -1097,7 +1124,7 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface { surface = batchsurfacelist[k]; tex = surface->texture; - rsurface.texture = tex->currentframe; + rsurface.texture = R_GetCurrentTexture(tex); // gather surfaces into a batch range for (kend = k;kend < batchnumsurfaces && tex == batchsurfacelist[kend]->texture;kend++) ; diff --git a/model_alias.c b/model_alias.c index 0ae37d56..ad912f96 100644 --- a/model_alias.c +++ b/model_alias.c @@ -880,8 +880,8 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->nummodelsurfaces = loadmodel->num_surfaces; data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int)); loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); - loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int); - loadmodel->surfacelist[0] = 0; + loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); + loadmodel->sortedmodelsurfaces[0] = 0; loadmodel->numskins = LittleLong(pinmodel->numskins); BOUNDI(loadmodel->numskins,0,65536); @@ -1243,8 +1243,8 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->nummodelsurfaces = loadmodel->num_surfaces; data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->numframes * sizeof(animscene_t) + loadmodel->numframes * sizeof(float[6]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_triangles * sizeof(int[3])); loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); - loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int); - loadmodel->surfacelist[0] = 0; + loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); + loadmodel->sortedmodelsurfaces[0] = 0; loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t); loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]); loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]); @@ -1507,7 +1507,7 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->num_texturesperskin = loadmodel->num_surfaces; data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[2]) + meshvertices * loadmodel->numframes * sizeof(md3vertex_t)); loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); - loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int); + loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); loadmodel->surfmesh.num_vertices = meshvertices; loadmodel->surfmesh.num_triangles = meshtriangles; @@ -1530,7 +1530,7 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend) { if (memcmp(pinmesh->identifier, "IDP3", 4)) Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)"); - loadmodel->surfacelist[i] = i; + loadmodel->sortedmodelsurfaces[i] = i; surface = loadmodel->data_surfaces + i; surface->texture = loadmodel->data_textures + i; surface->num_firsttriangle = meshtriangles; @@ -1569,6 +1569,7 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend) Mod_Alias_MorphMesh_CompileFrames(); Mod_Alias_CalculateBoundingBox(); Mod_FreeSkinFiles(skinfiles); + Mod_MakeSortedSurfaces(loadmodel); loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1); @@ -1750,7 +1751,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->num_texturesperskin = loadmodel->num_surfaces; data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[14]) + meshvertices * sizeof(int[4]) + meshvertices * sizeof(float[4]) + loadmodel->num_poses * sizeof(float[12]) + loadmodel->num_bones * sizeof(float[12])); loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); - loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int); + loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); loadmodel->surfmesh.num_vertices = meshvertices; loadmodel->surfmesh.num_triangles = meshtriangles; @@ -1847,7 +1848,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend)) Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name); - loadmodel->surfacelist[i] = i; + loadmodel->sortedmodelsurfaces[i] = i; surface = loadmodel->data_surfaces + i; surface->texture = loadmodel->data_textures + i; surface->num_firsttriangle = meshtriangles; @@ -1883,6 +1884,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) Mod_FreeSkinFiles(skinfiles); Mem_Free(vertbonecounts); Mem_Free(verts); + Mod_MakeSortedSurfaces(loadmodel); // compute all the mesh information that was not loaded from the file Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__); @@ -1999,7 +2001,7 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) // do most allocations as one merged chunk data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshtriangles * sizeof(int[3]) + meshvertices * (sizeof(float[14]) + sizeof(int[4]) + sizeof(float[4])) + loadmodel->num_poses * sizeof(float[12]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t)); loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); - loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int); + loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); loadmodel->surfmesh.num_vertices = meshvertices; loadmodel->surfmesh.num_triangles = meshtriangles; @@ -2085,7 +2087,7 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) const float *intexcoord; msurface_t *surface; - loadmodel->surfacelist[i] = i; + loadmodel->sortedmodelsurfaces[i] = i; surface = loadmodel->data_surfaces + i; surface->texture = loadmodel->data_textures + i; surface->num_firsttriangle = meshtriangles; @@ -2186,6 +2188,7 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) } Z_Free(bonepose); Mod_FreeSkinFiles(skinfiles); + Mod_MakeSortedSurfaces(loadmodel); // compute all the mesh information that was not loaded from the file Mod_BuildBaseBonePoses(); @@ -2589,7 +2592,7 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) size = loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * sizeof(int[4]) + loadmodel->surfmesh.num_vertices * sizeof(float[4]) + /*loadmodel->num_poses * sizeof(float[12]) + */loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t) + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0); data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size); loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); - loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int); + loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]); loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]); @@ -2626,7 +2629,7 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) { // since psk models do not have named sections, reuse their shader name as the section name Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name); - loadmodel->surfacelist[index] = index; + loadmodel->sortedmodelsurfaces[index] = index; loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index; loadmodel->data_surfaces[index].num_firstvertex = 0; loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices; @@ -2733,6 +2736,7 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) } Mod_FreeSkinFiles(skinfiles); Mem_Free(animfilebuffer); + Mod_MakeSortedSurfaces(loadmodel); // compute all the mesh information that was not loaded from the file // TODO: honor smoothing groups somehow? @@ -2746,3 +2750,429 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1; } +void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend) +{ +#if 0 + const char *textbase = (char *)buffer, *text = textbase; + char *s; + char *argv[512]; + char line[1024]; + char materialname[MAX_QPATH]; + int j, index1, index2, index3, first, prev, index; + int argc; + int linelen; + int numtriangles = 0; + int maxtriangles = 32768; + int *element3i = Mem_Alloc(tempmempool, maxtriangles * sizeof(int[3])); + int *oldelement3i; + int numsurfaces = 0; + int maxsurfaces = 0; + msurface_t *surfaces = NULL; + int linenumber = 0; + int hashindex; + float *v, *vt, *vn; + float *oldv, *oldvt, *oldvn; + int maxv = 65536, numv = 1; + int maxvt = 65536, numvt = 1; + int maxvn = 65536, numvn = 1; + int maxverthash = 65536, numverthash = 0; + int numhashindex = 65536; + struct objverthash_s + { + struct objverthash_s *next; + int s; + int v; + int vt; + int vn; + } + *hash, **verthash = Mem_Alloc(tempmempool, numhashindex * sizeof(*verthash)), *verthashdata = Mem_Alloc(tempmempool, maxverthash * sizeof(*verthashdata)), *oldverthashdata; + skinfile_t *skinfiles; + + dpsnprintf(materialname, sizeof(materialname), "%s", loadmodel->name); + + skinfiles = Mod_LoadSkinFiles(); + + loadmodel->modeldatatypestring = "OBJ"; + + loadmodel->type = mod_alias; + loadmodel->AnimateVertices = NULL; + loadmodel->DrawSky = NULL; + loadmodel->DrawAddWaterPlanes = NULL; + loadmodel->Draw = R_Q1BSP_Draw; + loadmodel->DrawDepth = R_Q1BSP_DrawDepth; + loadmodel->DrawDebug = R_Q1BSP_DrawDebug; + loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; + loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; + loadmodel->DrawLight = R_Q1BSP_DrawLight; + loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; + loadmodel->PointSuperContents = NULL; + + // parse the OBJ text now + for(;;) + { + if (!*text) + break; + linenumber++; + linelen = 0; + for (linelen = 0;text[linelen] && text[linelen] != '\r' && text[linelen] != '\n';linelen++) + line[linelen] = text[linelen]; + line[linelen] = 0; + for (argc = 0;argc < (int)(sizeof(argv)/sizeof(argv[0]));argc++) + argv[argc] = ""; + argc = 0; + s = line; + while (*s == ' ' || *s == '\t') + s++; + while (*s) + { + argv[argc++] = s; + while (*s > ' ') + s++; + if (!*s) + break; + *s++ = 0; + while (*s == ' ' || *s == '\t') + s++; + } + if (!argc) + continue; + if (argv[0][0] == '#') + continue; + if (!strcmp(argv[0], "v")) + { + if (maxv <= numv) + { + maxv *= 2; + oldv = v; + v = Mem_Alloc(tempmempool, maxv * sizeof(float[3])); + if (oldv) + { + memcpy(v, oldv, numv * sizeof(float[3])); + Mem_Free(oldv); + } + } + v[numv*3+0] = atof(argv[1]); + v[numv*3+1] = atof(argv[2]); + v[numv*3+2] = atof(argv[3]); + numv++; + } + else if (!strcmp(argv[0], "vt")) + { + if (maxvt <= numvt) + { + maxvt *= 2; + oldvt = vt; + vt = Mem_Alloc(tempmempool, maxvt * sizeof(float[2])); + if (oldvt) + { + memcpy(vt, oldvt, numvt * sizeof(float[2])); + Mem_Free(oldvt); + } + } + vt[numvt*2+0] = atof(argv[1]); + vt[numvt*2+1] = atof(argv[2]); + numvt++; + } + else if (!strcmp(argv[0], "vn")) + { + if (maxvn <= numvn) + { + maxvn *= 2; + oldvn = vn; + vn = Mem_Alloc(tempmempool, maxvn * sizeof(float[3])); + if (oldvn) + { + memcpy(vn, oldvn, numvn * sizeof(float[3])); + Mem_Free(oldvn); + } + } + vn[numvn*3+0] = atof(argv[1]); + vn[numvn*3+1] = atof(argv[2]); + vn[numvn*3+2] = atof(argv[3]); + numvn++; + } + else if (!strcmp(argv[0], "f")) + { + if (!surface) + { + if (maxsurfaces <= numsurfaces) + { + maxsurfaces++; + oldsurfaces = surfaces; + surfaces = Mem_Alloc(tempmempool, maxsurfaces * sizeof(*surfaces)); + if (oldsurfaces) + { + memcpy(surfaces, oldsurfaces, numsurfaces * sizeof(*surfaces)); + Mem_Free(oldsurfaces); + } + } + surface = surfaces + numsurfaces++; + surface-> + } + for (j = 1;j < argc;j++) + { + index1 = atoi(argv[j]); + while(argv[j][0] && argv[j][0] != '/') + argv[j]++; + if (argv[j][0]) + argv[j]++; + if (index1 < 0) + index1 = numv + 1 - index1; + index2 = atoi(argv[j]); + if (index2 < 0) + index2 = numvt + 1 - index2; + while(argv[j][0] && argv[j][0] != '/') + argv[j]++; + if (argv[j][0]) + argv[j]++; + index3 = atoi(argv[j]); + if (index3 < 0) + index3 = numvn + 1 - index3; + hashindex = (index1 + index2 * 3571 + index3 * 42589) & (numhashindex - 1); + for (hash = verthash[hashindex];hash;hash = hash->next) + if (hash->surface == numsurfaces-1 && hash->v == index1 && hash->vt == index2 && hash->vn == index3) + break; + if (!hash) + { + if (maxverthash <= numverthash) + { + maxverthash *= 2; + oldverthashdata = verthashdata; + verthashdata = Mem_Alloc(tempmempool, maxverthash * sizeof(*verthashdata)); + if (oldverthashdata) + { + memcpy(verthashdata, oldverthashdata, numverthash * sizeof(*verthashdata)); + Mem_Free(oldverthashdata); + } + } + hash = verthashdata + numverthash++; + hash->next = verthash[hashindex]; + hash->s = numsurfaces; + hash->v = index1; + hash->vt = index2; + hash->vn = index3; + verthash[hashindex] = hash; + } + index = (int)((size_t)(hash - verthashdata)); + if (j == 1) + first = index; + else if (j >= 3) + { + if (maxtriangles <= numtriangles) + { + maxtriangles *= 2; + oldelement3i = element3i; + element3i = Mem_Alloc(tempmempool, numtriangles * sizeof(int[3])); + if (oldelement3i) + { + memcpy(element3i, oldelement3i, numtriangles * sizeof(int[3])); + Mem_Free(oldelement3i); + } + } + element3i[numtriangles*3+0] = first; + element3i[numtriangles*3+1] = prev; + element3i[numtriangles*3+2] = index; + numtriangles++; + } + prev = index; + } + } + else if (!strcmp(argv[0], "o") || !strcmp(argv[0], "g")) + surface = NULL; + else if (!!strcmp(argv[0], "usemtl")) + { + surface = NULL; + strlcpy(materialname, argv[1], sizeof(materialname); + } + text += linelen; + if (*text == '\r') + text++; + if (*text == '\n') + text++; + } + + if (skinfiles) + Mod_FreeSkinFiles(skinfiles); + + // now that we have the OBJ data loaded as-is, we can convert it + loadmodel->numskins = LittleLong(pinmodel->num_skins); + numxyz = LittleLong(pinmodel->num_xyz); + numst = LittleLong(pinmodel->num_st); + loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris); + loadmodel->numframes = LittleLong(pinmodel->num_frames); + loadmodel->surfmesh.num_morphframes = loadmodel->numframes; + loadmodel->num_poses = loadmodel->surfmesh.num_morphframes; + skinwidth = LittleLong(pinmodel->skinwidth); + skinheight = LittleLong(pinmodel->skinheight); + iskinwidth = 1.0f / skinwidth; + iskinheight = 1.0f / skinheight; + + loadmodel->num_surfaces = 1; + loadmodel->nummodelsurfaces = loadmodel->num_surfaces; + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->numframes * sizeof(animscene_t) + loadmodel->numframes * sizeof(float[6]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_triangles * sizeof(int[3])); + loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); + loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); + loadmodel->sortedmodelsurfaces[0] = 0; + loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t); + loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]); + loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]); + loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]); + + loadmodel->synctype = ST_RAND; + + // load the skins + inskin = (char *)(base + LittleLong(pinmodel->ofs_skins)); + skinfiles = Mod_LoadSkinFiles(); + if (skinfiles) + { + loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; + loadmodel->num_texturesperskin = loadmodel->num_surfaces; + loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t)); + Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", ""); + Mod_FreeSkinFiles(skinfiles); + } + else if (loadmodel->numskins) + { + // skins found (most likely not a player model) + loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; + loadmodel->num_texturesperskin = loadmodel->num_surfaces; + loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t)); + for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME) + Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP | TEXF_COMPRESS); + } + else + { + // no skins (most likely a player model) + loadmodel->numskins = 1; + loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; + loadmodel->num_texturesperskin = loadmodel->num_surfaces; + loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t)); + Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL); + } + + loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins); + for (i = 0;i < loadmodel->numskins;i++) + { + loadmodel->skinscenes[i].firstframe = i; + loadmodel->skinscenes[i].framecount = 1; + loadmodel->skinscenes[i].loop = true; + loadmodel->skinscenes[i].framerate = 10; + } + + // load the triangles and stvert data + inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st)); + intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris)); + md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash)); + md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash)); + // swap the triangle list + loadmodel->surfmesh.num_vertices = 0; + for (i = 0;i < loadmodel->surfmesh.num_triangles;i++) + { + for (j = 0;j < 3;j++) + { + xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]); + st = (unsigned short) LittleShort (intri[i].index_st[j]); + if (xyz >= numxyz) + { + Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i); + xyz = 0; + } + if (st >= numst) + { + Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i); + st = 0; + } + hashindex = (xyz * 256 + st) & 65535; + for (hash = md2verthash[hashindex];hash;hash = hash->next) + if (hash->xyz == xyz && hash->st == st) + break; + if (hash == NULL) + { + hash = md2verthashdata + loadmodel->surfmesh.num_vertices++; + hash->xyz = xyz; + hash->st = st; + hash->next = md2verthash[hashindex]; + md2verthash[hashindex] = hash; + } + loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata); + } + } + + vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int)); + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t)); + loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]); + loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t); + for (i = 0;i < loadmodel->surfmesh.num_vertices;i++) + { + int sts, stt; + hash = md2verthashdata + i; + vertremap[i] = hash->xyz; + sts = LittleShort(inst[hash->st*2+0]); + stt = LittleShort(inst[hash->st*2+1]); + if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight) + { + Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i); + sts = 0; + stt = 0; + } + loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth; + loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight; + } + + Mem_Free(md2verthash); + Mem_Free(md2verthashdata); + + // generate ushort elements array if possible + if (loadmodel->surfmesh.num_vertices <= 65536) + { + loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles); + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; + } + + // load the frames + datapointer = (base + LittleLong(pinmodel->ofs_frames)); + for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++) + { + int k; + trivertx_t *v; + trivertx_t *out; + pinframe = (md2frame_t *)datapointer; + datapointer += sizeof(md2frame_t); + // store the frame scale/translate into the appropriate array + for (j = 0;j < 3;j++) + { + loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]); + loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]); + } + // convert the vertices + v = (trivertx_t *)datapointer; + out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices; + for (k = 0;k < loadmodel->surfmesh.num_vertices;k++) + out[k] = v[vertremap[k]]; + datapointer += numxyz * sizeof(trivertx_t); + + strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name)); + loadmodel->animscenes[i].firstframe = i; + loadmodel->animscenes[i].framecount = 1; + loadmodel->animscenes[i].framerate = 10; + loadmodel->animscenes[i].loop = true; + } + + Mem_Free(vertremap); + + Mod_MakeSortedSurfaces(loadmodel); + Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); + Mod_Alias_CalculateBoundingBox(); + Mod_Alias_MorphMesh_CompileFrames(); + + surface = loadmodel->data_surfaces; + surface->texture = loadmodel->data_textures; + surface->num_firsttriangle = 0; + surface->num_triangles = loadmodel->surfmesh.num_triangles; + surface->num_firstvertex = 0; + surface->num_vertices = loadmodel->surfmesh.num_vertices; + + loadmodel->surfmesh.isanimated = false; +#endif +} diff --git a/model_brush.c b/model_brush.c index df122f60..723f4dab 100644 --- a/model_brush.c +++ b/model_brush.c @@ -3590,9 +3590,8 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) mod->nummodelsurfaces = bm->numfaces; // make the model surface list (used by shadowing/lighting) - mod->surfacelist = (int *)datapointer;datapointer += mod->nummodelsurfaces * sizeof(int); - for (j = 0;j < mod->nummodelsurfaces;j++) - mod->surfacelist[j] = mod->firstmodelsurface + j; + mod->sortedmodelsurfaces = (int *)datapointer;datapointer += mod->nummodelsurfaces * sizeof(int); + Mod_MakeSortedSurfaces(mod); // this gets altered below if sky or water is used mod->DrawSky = NULL; @@ -5983,9 +5982,8 @@ void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) mod->nummodelsurfaces = mod->brushq3.data_models[i].numfaces; mod->firstmodelbrush = mod->brushq3.data_models[i].firstbrush; mod->nummodelbrushes = mod->brushq3.data_models[i].numbrushes; - mod->surfacelist = (int *)Mem_Alloc(loadmodel->mempool, mod->nummodelsurfaces * sizeof(*mod->surfacelist)); - for (j = 0;j < mod->nummodelsurfaces;j++) - mod->surfacelist[j] = mod->firstmodelsurface + j; + mod->sortedmodelsurfaces = (int *)Mem_Alloc(loadmodel->mempool, mod->nummodelsurfaces * sizeof(*mod->sortedmodelsurfaces)); + Mod_MakeSortedSurfaces(mod); VectorCopy(mod->brushq3.data_models[i].mins, mod->normalmins); VectorCopy(mod->brushq3.data_models[i].maxs, mod->normalmaxs); diff --git a/model_shared.c b/model_shared.c index 9d5acedb..2c46c01a 100644 --- a/model_shared.c +++ b/model_shared.c @@ -320,7 +320,8 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk, q num = LittleLong(*((int *)buf)); // call the apropriate loader loadmodel = mod; - if (!memcmp(buf, "IDPO", 4)) Mod_IDP0_Load(mod, buf, bufend); + if (!strcasecmp(FS_FileExtension(mod->name), "obj")) Mod_OBJ_Load(mod, buf, bufend); + else if (!memcmp(buf, "IDPO", 4)) Mod_IDP0_Load(mod, buf, bufend); else if (!memcmp(buf, "IDP2", 4)) Mod_IDP2_Load(mod, buf, bufend); else if (!memcmp(buf, "IDP3", 4)) Mod_IDP3_Load(mod, buf, bufend); else if (!memcmp(buf, "IDSP", 4)) Mod_IDSP_Load(mod, buf, bufend); @@ -2168,6 +2169,39 @@ void Mod_VertexRangeFromElements(int numelements, const int *elements, int *firs *lastvertexpointer = lastvertex; } +void Mod_MakeSortedSurfaces(dp_model_t *mod) +{ + // make an optimal set of texture-sorted batches to draw... + int j, t; + int *firstsurfacefortexture; + int *numsurfacesfortexture; + if (!mod->sortedmodelsurfaces) + mod->sortedmodelsurfaces = Mem_Alloc(tempmempool, mod->nummodelsurfaces * sizeof(*mod->sortedmodelsurfaces)); + firstsurfacefortexture = Mem_Alloc(tempmempool, mod->num_textures * sizeof(*firstsurfacefortexture)); + numsurfacesfortexture = Mem_Alloc(tempmempool, mod->num_textures * sizeof(*numsurfacesfortexture)); + memset(numsurfacesfortexture, 0, mod->num_textures * sizeof(*numsurfacesfortexture)); + for (j = 0;j < mod->nummodelsurfaces;j++) + { + const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface; + int t = (int)(surface->texture - mod->data_textures); + numsurfacesfortexture[t]++; + } + j = 0; + for (t = 0;t < mod->num_textures;t++) + { + firstsurfacefortexture[t] = j; + j += numsurfacesfortexture[t]; + } + for (j = 0;j < mod->nummodelsurfaces;j++) + { + const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface; + int t = (int)(surface->texture - mod->data_textures); + mod->sortedmodelsurfaces[firstsurfacefortexture[t]++] = j + mod->firstmodelsurface; + } + Mem_Free(firstsurfacefortexture); + Mem_Free(numsurfacesfortexture); +} + static void Mod_BuildVBOs(void) { if (!gl_support_arb_vertex_buffer_object) diff --git a/model_shared.h b/model_shared.h index aca35010..3476a4a8 100644 --- a/model_shared.h +++ b/model_shared.h @@ -456,6 +456,9 @@ typedef struct texture_s // (this is an optimization in the renderer) int animated; + // renderer checks if this texture needs updating... + int update_lastrenderframe; + void *update_lastrenderentity; // the current alpha of this texture (may be affected by r_wateralpha) float currentalpha; // the current texture frame in animation @@ -829,6 +832,7 @@ typedef struct model_s // range of surface numbers in this (sub)model int firstmodelsurface; int nummodelsurfaces; + int *sortedmodelsurfaces; // range of collision brush numbers in this (sub)model int firstmodelbrush; int nummodelbrushes; @@ -925,6 +929,7 @@ void Mod_BuildNormals(int firstvertex, int numvertices, int numtriangles, const void Mod_BuildTextureVectorsFromNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const float *texcoord2f, const float *normal3f, const int *elements, float *svector3f, float *tvector3f, qboolean areaweighting); void Mod_AllocSurfMesh(mempool_t *mempool, int numvertices, int numtriangles, qboolean lightmapoffsets, qboolean vertexcolors, qboolean neighbors); +void Mod_MakeSortedSurfaces(dp_model_t *mod); 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); @@ -997,6 +1002,7 @@ void Mod_SpriteInit(void); void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend); void Mod_IBSP_Load(dp_model_t *mod, void *buffer, void *bufferend); void Mod_MAP_Load(dp_model_t *mod, void *buffer, void *bufferend); +void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend); void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend); void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend); void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend); diff --git a/r_shadow.c b/r_shadow.c index c8b01158..02a90e7f 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -3010,7 +3010,7 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent) relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius; relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius; relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius; - ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs); + ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs); } void R_Shadow_SetupEntityLight(const entity_render_t *ent) @@ -3052,7 +3052,7 @@ void R_Shadow_DrawEntityLight(entity_render_t *ent) R_Shadow_SetupEntityLight(ent); - model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL); + model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL); } void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) @@ -3461,7 +3461,7 @@ void R_DrawModelShadows(void) VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin); RSurf_ActiveModelEntity(ent, false, false); - ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs); + ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs); } } diff --git a/r_sprites.c b/r_sprites.c index 444d1668..88238522 100644 --- a/r_sprites.c +++ b/r_sprites.c @@ -360,11 +360,10 @@ void R_Model_Sprite_Draw_TransparentCallback(const entity_render_t *ent, const r if (ent->frameblend[i].lerp >= 0.01f) { mspriteframe_t *frame = model->sprite.sprdata_frames + ent->frameblend[i].frame; - texture_t *texture = model->data_textures + ent->frameblend[i].frame; + texture_t *texture = R_GetCurrentTexture(model->data_textures + ent->frameblend[i].frame); #if 0 vec3_t o, l, u; #endif - R_UpdateTextureInfo(ent, texture); // SPR_LABEL should not use depth test AT ALL if(model->sprite.sprnum_type == SPR_LABEL || model->sprite.sprnum_type == SPR_LABEL_SCALE) diff --git a/render.h b/render.h index f2b617b9..b6754e98 100644 --- a/render.h +++ b/render.h @@ -340,6 +340,11 @@ typedef struct rsurfacestate_s matrix4x4_t entitytoattenuationxyz; // this transforms only the Z to S, and T is always 0.5 matrix4x4_t entitytoattenuationz; + + // pointer to an entity_render_t used only by R_GetCurrentTexture and + // RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity as a unique id within + // each frame (see r_frame also) + entity_render_t *entity; } rsurfacestate_t; @@ -351,14 +356,10 @@ void RSurf_SetupDepthAndCulling(void); void R_Mesh_ResizeArrays(int newvertices); -struct entity_render_s; -struct texture_s; -struct msurface_s; -void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t); -void R_UpdateAllTextureInfo(entity_render_t *ent); -void R_QueueTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist); -void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes, qboolean debug); -void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes, qboolean debug); +texture_t *R_GetCurrentTexture(texture_t *t); +void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug); +void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug); +void R_AddWaterPlanes(entity_render_t *ent); void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, msurface_t **texturesurfacelist); void RSurf_DrawBatch_Simple(int texturenumsurfaces, msurface_t **texturesurfacelist); diff --git a/todo b/todo index c6cff8a3..b386a098 100644 --- a/todo +++ b/todo @@ -1,7 +1,10 @@ - todo: difficulty ratings are: 0 = trivial, 1 = easy, 2 = easy-moderate, 3 = moderate, 4 = moderate-hard, 5 = hard, 6 = hard++, 7 = nightmare, d = done, -d = done but have not notified the people who asked for it, f = failed, -f = failed but have not notified the people who asked for it 0 feature darkplaces client rtlights: ChrisP has a suggestion of selecting rtlight properties using the number keys, and increasing/decreasing their value using the mouse wheel (cvars needed for amounts to adjust by), and ability to right click a light to delete it, left click to select a light, left drag to move a light on the XY plane it is on (ChrisP) 0 feature darkplaces client particles: effectinfo.txt should have a "particlefont" command specifying a filename, number of cells per row, number of rows, number of bottom rows that are beams, this would allow more particle images to be used (ChrisP) -d feature darkplaces client extensions: EF_NOSELFSHADOW flag (ChrisP) +d feature darkplaces client extensions: DP_EF_NOSELFSHADOW extension (ChrisP) +0 feature darkplaces client csqc: DP_CSQC_SOUNDLENGTH extension which defines a builtin float(float f) soundlength = #??; which returns the sound length in seconds, or 0 if the sound is not loaded, or the engine was started with -nosound (ChrisP) +0 feature darkplaces client coronas: r_coronas_fadetime cvar and r_coronas_raisetime cvar which control fading of coronas when they come into view and pass out of view (ChrisP) +0 feature darkplaces client text: support for font rasterizing at pixel-accurate sizes and caching them to disk, support freetype2 for this purpose if it is present (ChrisP) 0 bug darkplaces client csqc: engine prediction function is not implemented - could just return the engine's current cl.movement_origin (Spike) 0 bug darkplaces client csqc: entities not being drawn with VF_PERSPECTIVE 0? (daemon) 0 bug darkplaces client csqc: input queue functions needed for csqc prediction aren't implemented (Spike) -- 2.39.2