}
}
-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;
ent->maxs[1] = org[1] + 16;
ent->maxs[2] = org[2] + 16;
}
- CL_UpdateRenderEntity_Lighting(ent);
}
/*
mempool_t *r_main_mempool;
rtexturepool_t *r_main_texturepool;
+static int r_frame = 0; // used only by R_GetCurrentTexture
+
//
// screen size info
//
//==================================================================================
+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;
R_View_SetFrustum();
R_View_WorldVisibility(r_refdef.view.useclipplane);
R_View_UpdateEntityVisible();
+ R_View_UpdateEntityLighting();
}
void R_SetupView(qboolean allowwaterclippingplane)
R_SetupGenericShader(true);
}
-void R_RenderScene(qboolean addwaterplanes);
+void R_RenderScene(void);
+void R_RenderWaterPlanes(void);
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;
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)
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;
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
static void R_Water_ProcessPlanes(void)
{
r_refdef_view_t originalview;
+ r_refdef_view_t myview;
int planeindex;
r_waterstate_waterplane_t *p;
}
// 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));
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)
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;
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();
}
}
-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!
*/
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]
r_waterstate.enabled = false;
r_waterstate.numwaterplanes = 0;
- R_RenderScene(false);
+ R_RenderScene();
CHECKGLERROR
return;
}
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)
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)
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)
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
{
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;
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;
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;
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();
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);
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)
{
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)
{
// 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))
{
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);
}
}
{
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);
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;
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++)
}
}
- 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)
{
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++)
}
}
-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;
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++)
}
}
- R_UpdateAllTextureInfo(ent);
- flagsmask = addwaterplanes ? (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) : (skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL);
+ flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
if (debug)
{
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;
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)
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)
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);
}
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
}
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;
int leafsurfaceindex;
int surfaceindex;
int triangleindex, t;
+ int currentmaterialflags;
msurface_t *surface;
const int *e;
const vec_t *v[3];
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);
{
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]);
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)
continue;
SETPVSBIT(info->outlighttrispvs, t);
addedtris = true;
- if (!(surface->texture->currentframe->currentmaterialflags & MATERIALFLAG_NOSHADOW))
+ if (!(currentmaterialflags & MATERIALFLAG_NOSHADOW))
SETPVSBIT(info->outshadowtrispvs, t);
}
else
// 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);
}
}
}
}
-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)
{
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)
{
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);
}
// 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)
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);
}
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);
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++)
{
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
{
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++)
;
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);
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]);
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;
{
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;
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);
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;
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;
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__);
// 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;
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;
}
Z_Free(bonepose);
Mod_FreeSkinFiles(skinfiles);
+ Mod_MakeSortedSurfaces(loadmodel);
// compute all the mesh information that was not loaded from the file
Mod_BuildBaseBonePoses();
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]);
{
// 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;
}
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?
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
+}
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;
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);
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);
*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)
// (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
// 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;
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);
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);
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)
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)
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);
}
}
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)
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;
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);
- 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)