"dynamic_surfaces_because_derived",
"dynamic_vertices_because_derived",
"dynamic_triangles_because_derived",
+ "entitycache_count",
+ "entitycache_surfaces",
+ "entitycache_vertices",
+ "entitycache_triangles",
+ "entityanimate_count",
+ "entityanimate_surfaces",
+ "entityanimate_vertices",
+ "entityanimate_triangles",
+ "entityskeletal_count",
+ "entityskeletal_surfaces",
+ "entityskeletal_vertices",
+ "entityskeletal_triangles",
+ "entitystatic_count",
+ "entitystatic_surfaces",
+ "entitystatic_vertices",
+ "entitystatic_triangles",
+ "entitycustom_count",
+ "entitycustom_surfaces",
+ "entitycustom_vertices",
+ "entitycustom_triangles",
};
char r_speeds_timestring[4096];
r_stat_batch_dynamic_surfaces_because_derived,
r_stat_batch_dynamic_vertices_because_derived,
r_stat_batch_dynamic_triangles_because_derived,
+ r_stat_batch_entitycache_count,
+ r_stat_batch_entitycache_surfaces,
+ r_stat_batch_entitycache_vertices,
+ r_stat_batch_entitycache_triangles,
+ r_stat_batch_entityanimate_count,
+ r_stat_batch_entityanimate_surfaces,
+ r_stat_batch_entityanimate_vertices,
+ r_stat_batch_entityanimate_triangles,
+ r_stat_batch_entityskeletal_count,
+ r_stat_batch_entityskeletal_surfaces,
+ r_stat_batch_entityskeletal_vertices,
+ r_stat_batch_entityskeletal_triangles,
+ r_stat_batch_entitystatic_count,
+ r_stat_batch_entitystatic_surfaces,
+ r_stat_batch_entitystatic_vertices,
+ r_stat_batch_entitystatic_triangles,
+ r_stat_batch_entitycustom_count,
+ r_stat_batch_entitycustom_surfaces,
+ r_stat_batch_entitycustom_vertices,
+ r_stat_batch_entitycustom_triangles,
r_stat_count // size of array
}
r_stat_t;
qboolean r_loadfog;
static qboolean r_loaddds;
static qboolean r_savedds;
+static qboolean r_gpuskeletal;
//
// screen size info
dp_model_t *model = ent->model;
int numvertices;
- // cache skeletal animation data first (primarily for gpu-skinning)
- if (!ent->animcache_skeletaltransform3x4 && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
+ // see if this ent is worth caching
+ if (!model || !model->Draw || !model->AnimateVertices)
+ return false;
+ // nothing to cache if it contains no animations and has no skeleton
+ if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
+ return false;
+ // see if it is already cached for gpuskeletal
+ if (ent->animcache_skeletaltransform3x4)
+ return false;
+ // see if it is already cached as a mesh
+ if (ent->animcache_vertex3f)
+ {
+ // check if we need to add normals or tangents
+ if (ent->animcache_normal3f)
+ wantnormals = false;
+ if (ent->animcache_svector3f)
+ wanttangents = false;
+ if (!wantnormals && !wanttangents)
+ return false;
+ }
+
+ // check which kind of cache we need to generate
+ if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
{
+ // cache the skeleton so the vertex shader can use it
int i;
int blends;
const skeleton_t *skeleton = ent->skeleton;
}
}
}
-
- // see if it's already cached this frame
- if (ent->animcache_vertex3f)
+ else if (ent->animcache_vertex3f)
{
- // add normals/tangents if needed (this only happens with multiple views, reflections, cameras, etc)
+ // mesh was already cached but we may need to add normals/tangents
+ // (this only happens with multiple views, reflections, cameras, etc)
if (wantnormals || wanttangents)
{
- if (ent->animcache_normal3f)
- wantnormals = false;
- if (ent->animcache_svector3f)
- wanttangents = false;
- if (wantnormals || wanttangents)
+ numvertices = model->surfmesh.num_vertices;
+ if (wantnormals)
+ ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
+ if (wanttangents)
{
- numvertices = model->surfmesh.num_vertices;
- if (wantnormals)
- ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
- if (wanttangents)
- {
- ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
- ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
- }
- model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
- R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
- r_refdef.stats[r_stat_animcache_shade_count] += 1;
- r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
- r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
+ ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
+ ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
}
+ model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
+ R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
+ r_refdef.stats[r_stat_animcache_shade_count] += 1;
+ r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
+ r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
}
}
else
{
- // see if this ent is worth caching
- if (!model || !model->Draw || !model->surfmesh.isanimated || !model->AnimateVertices)
- return false;
- // skip entity if the shader backend has a cheaper way
- if (model->surfmesh.data_skeletalindex4ub && r_glsl_skeletal.integer && !r_showsurfaces.integer) // FIXME add r_showsurfaces support to GLSL skeletal!
- {
- switch (vid.renderpath)
- {
- case RENDERPATH_GL20:
- return false;
- case RENDERPATH_GL11:
- case RENDERPATH_GL13:
- case RENDERPATH_GLES1:
- case RENDERPATH_GLES2:
- case RENDERPATH_D3D9:
- case RENDERPATH_D3D10:
- case RENDERPATH_D3D11:
- case RENDERPATH_SOFT:
- break;
- }
- }
- // get some memory for this entity and generate mesh data
+ // generate mesh cache
numvertices = model->surfmesh.num_vertices;
ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
if (wantnormals)
r_refdef.lightmapintensity = 0;
}
+ r_gpuskeletal = false;
switch(vid.renderpath)
{
case RENDERPATH_GL20:
+ r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer; // FIXME add r_showsurfaces support to GLSL skeletal!
case RENDERPATH_D3D9:
case RENDERPATH_D3D10:
case RENDERPATH_D3D11:
{
if (ent->animcache_vertex3f)
{
+ r_refdef.stats[r_stat_batch_entitycache_count]++;
+ r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
+ r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
+ r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
rsurface.modelvertex3f = ent->animcache_vertex3f;
rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
}
else if (wanttangents)
{
+ r_refdef.stats[r_stat_batch_entityanimate_count]++;
+ r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
+ r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
+ r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
}
else if (wantnormals)
{
+ r_refdef.stats[r_stat_batch_entityanimate_count]++;
+ r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
+ r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
+ r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
rsurface.modelsvector3f = NULL;
rsurface.modeltvector3f = NULL;
}
else
{
+ r_refdef.stats[r_stat_batch_entityanimate_count]++;
+ r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
+ r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
+ r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
rsurface.modelsvector3f = NULL;
rsurface.modeltvector3f = NULL;
}
else
{
+ if (rsurface.entityskeletaltransform3x4)
+ {
+ r_refdef.stats[r_stat_batch_entityskeletal_count]++;
+ r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
+ r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
+ r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
+ }
+ else
+ {
+ r_refdef.stats[r_stat_batch_entitystatic_count]++;
+ r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
+ r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
+ r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
+ }
rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
rsurface.basepolygonoffset = r_refdef.polygonoffset;
rsurface.entityskeletaltransform3x4 = NULL;
rsurface.entityskeletalnumtransforms = 0;
+ r_refdef.stats[r_stat_batch_entitycustom_count]++;
+ r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
+ r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
+ r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
if (wanttangents)
{
rsurface.modelvertex3f = (float *)vertex3f;
// when the model data has no vertex buffer (dynamic mesh), we need to
// eliminate gaps
- if (vid.useinterleavedarrays ? !rsurface.modelvertexmeshbuffer : !rsurface.modelvertex3f_vertexbuffer)
+ if (vid.useinterleavedarrays && !rsurface.modelvertexmeshbuffer)
batchneed |= BATCHNEED_NOGAPS;
// the caller can specify BATCHNEED_NOGAPS to force a batch with
Mem_Free(basebonepose);
}
-static void Mod_Alias_CalculateBoundingBox(void)
+static qboolean Mod_Alias_CalculateBoundingBox(void)
{
int vnum;
qboolean firstvertex = true;
float dist, yawradius, radius;
float *v;
+ qboolean isanimated = false;
VectorClear(loadmodel->normalmins);
VectorClear(loadmodel->normalmaxs);
yawradius = 0;
radius = 0;
if (loadmodel->AnimateVertices)
{
- float *vertex3f;
+ float *vertex3f, *refvertex3f;
frameblend_t frameblend[MAX_FRAMEBLENDS];
memset(frameblend, 0, sizeof(frameblend));
frameblend[0].lerp = 1;
- vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
+ vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]) * 2);
+ refvertex3f = NULL;
for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
{
loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL);
+ if (!refvertex3f)
+ {
+ // make a copy of the first frame for comparing all others
+ refvertex3f = vertex3f + loadmodel->surfmesh.num_vertices * 3;
+ memcpy(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
+ }
+ else
+ {
+ if (!isanimated && memcmp(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3])))
+ isanimated = true;
+ }
for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
{
if (firstvertex)
loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
loadmodel->radius = radius;
loadmodel->radius2 = radius * radius;
+ return isanimated;
}
static void Mod_Alias_MorphMesh_CompileFrames(void)
loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
// FIXME add TraceBrush!
loadmodel->PointSuperContents = NULL;
+ loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
loadmodel->num_surfaces = 1;
loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
}
Mod_MDL_LoadFrames (startframes, numverts, vertremap);
- loadmodel->AnimateVertices = Mod_MDL_AnimateVertices; // needed during loading, may be cleared by code later in this function
if (loadmodel->surfmesh.data_neighbor3i)
Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
- Mod_Alias_CalculateBoundingBox();
+ loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
Mod_Alias_MorphMesh_CompileFrames();
Mem_Free(vertst);
surface->num_firstvertex = 0;
surface->num_vertices = loadmodel->surfmesh.num_vertices;
- loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
if(mod_alias_force_animated.string[0])
loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
- loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MDL_AnimateVertices : NULL;
if (!loadmodel->surfmesh.isanimated)
{
loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
loadmodel->PointSuperContents = NULL;
+ loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
Mem_Free(vertremap);
- loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
- if(mod_alias_force_animated.string[0])
- loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
- loadmodel->AnimateVertices = Mod_MDL_AnimateVertices; // needed during loading, may be cleared by code later in this function
if (loadmodel->surfmesh.data_neighbor3i)
Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
- Mod_Alias_CalculateBoundingBox();
+ loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
Mod_Alias_MorphMesh_CompileFrames();
- loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MDL_AnimateVertices : NULL;
+ if(mod_alias_force_animated.string[0])
+ loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
surface = loadmodel->data_surfaces;
surface->texture = loadmodel->data_textures;
loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
loadmodel->PointSuperContents = NULL;
+ loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
loadmodel->synctype = ST_RAND;
// convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
i = LittleLong (pinmodel->flags);
if (loadmodel->surfmesh.data_element3s)
for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
- loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
- if(mod_alias_force_animated.string[0])
- loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
- loadmodel->AnimateVertices = Mod_MD3_AnimateVertices; // needed during loading, may be cleared by code later in this function
if (loadmodel->surfmesh.data_neighbor3i)
Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
Mod_Alias_MorphMesh_CompileFrames();
- Mod_Alias_CalculateBoundingBox();
+ loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
Mod_FreeSkinFiles(skinfiles);
Mod_MakeSortedSurfaces(loadmodel);
- loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MD3_AnimateVertices : NULL;
+ if(mod_alias_force_animated.string[0])
+ loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
if (!loadmodel->surfmesh.isanimated)
{
loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
loadmodel->PointSuperContents = NULL;
+ loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
loadmodel->numframes = pheader->numscenes;
loadmodel->num_surfaces = pheader->numshaders;
}
// model bbox
+ // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
modelradius = pheader->radius;
for (i = 0;i < 3;i++)
{
meshvertices = pheader->numverts;
meshtriangles = pheader->numtris;
- loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
- if(mod_alias_force_animated.string[0])
- loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
- loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
loadmodel->num_texturesperskin = loadmodel->num_surfaces;
Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
if (loadmodel->surfmesh.data_neighbor3i)
Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
+ loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
+ if(mod_alias_force_animated.string[0])
+ loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
if (!loadmodel->surfmesh.isanimated)
{
loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
loadmodel->PointSuperContents = NULL;
+ loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
// model bbox
+ // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
for (i = 0;i < 3;i++)
{
loadmodel->normalmins[i] = pheader->mins[i];
loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
loadmodel->num_texturesperskin = loadmodel->num_surfaces;
- loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
- if(mod_alias_force_animated.string[0])
- loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
- loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
// 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) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4])) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + 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);
Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
if (loadmodel->surfmesh.data_neighbor3i)
Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
+ loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
+ if(mod_alias_force_animated.string[0])
+ loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
if (!loadmodel->surfmesh.isanimated)
{
loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
loadmodel->PointSuperContents = NULL;
+ loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
loadmodel->synctype = ST_RAND;
FS_StripExtension(loadmodel->name, animname, sizeof(animname));
loadmodel->num_texturesperskin = loadmodel->num_surfaces;
loadmodel->surfmesh.num_vertices = meshvertices;
loadmodel->surfmesh.num_triangles = meshtriangles;
- loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
- if(mod_alias_force_animated.string[0])
- loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
- loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
// do most allocations as one merged chunk
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]) + (r_enableshadowvolumes.integer ? loadmodel->surfmesh.num_triangles * sizeof(int[3]) : 0) + 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(unsigned char[4]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned short) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + 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);
Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
if (loadmodel->surfmesh.data_neighbor3i)
Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
- Mod_Alias_CalculateBoundingBox();
+ loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
+ if(mod_alias_force_animated.string[0])
+ loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
if (!loadmodel->surfmesh.isanimated)
{
loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
loadmodel->PointSuperContents = NULL;
+ loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
// load external .skin files if present
skinfiles = Mod_LoadSkinFiles();
loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
loadmodel->num_texturesperskin = loadmodel->num_surfaces;
- loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices; // updated later
meshvertices = header.num_vertexes;
meshtriangles = header.num_triangles;
loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
if(mod_alias_force_animated.string[0])
loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
- loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
biggestorigin = 0;
if (header.version == 1)
// cache all the animated entities that cast a shadow but are not visible
for (i = 0;i < numshadowentities;i++)
- if (!shadowentities[i]->animcache_vertex3f)
- R_AnimCache_GetEntity(shadowentities[i], false, false);
+ R_AnimCache_GetEntity(shadowentities[i], false, false);
for (i = 0;i < numshadowentities_noselfshadow;i++)
- if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
- R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
+ R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
// allocate some temporary memory for rendering this light later in the frame
// reusable buffers need to be copied, static data can be used as-is
R_Shadow_RenderMode_End();
}
+#define MAX_MODELSHADOWS 1024
+static int r_shadow_nummodelshadows;
+static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
+
void R_Shadow_PrepareModelShadows(void)
{
int i;
vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
entity_render_t *ent;
+ r_shadow_nummodelshadows = 0;
if (!r_refdef.scene.numentities)
return;
break;
// fall through
case R_SHADOW_SHADOWMODE_STENCIL:
+ if (!vid.stencil)
+ return;
for (i = 0;i < r_refdef.scene.numentities;i++)
{
ent = r_refdef.scene.entities[i];
- if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
+ if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
+ {
+ if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
+ break;
+ r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
R_AnimCache_GetEntity(ent, false, false);
+ }
}
return;
default:
if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
continue;
// cast shadows from anything of the map (submodels are optional)
- if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
+ if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
+ {
+ if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
+ break;
+ r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
R_AnimCache_GetEntity(ent, false, false);
+ }
}
}
GLuint shadowfbo = 0;
float clearcolor[4];
- if (!r_refdef.scene.numentities)
+ if (!r_shadow_nummodelshadows)
return;
switch (r_shadow_shadowmode)
// outside the usable area
GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
- for (i = 0;i < r_refdef.scene.numentities;i++)
- {
- ent = r_refdef.scene.entities[i];
-
- // cast shadows from anything of the map (submodels are optional)
- if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
- {
- relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
- Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
- Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
- Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
- Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
- relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
- relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
- relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
- relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
- relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
- relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
- RSurf_ActiveModelEntity(ent, false, false, false);
- ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
- rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
- }
+ for (i = 0;i < r_shadow_nummodelshadows;i++)
+ {
+ ent = r_shadow_modelshadows[i];
+ relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
+ Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
+ Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
+ Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
+ Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
+ relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
+ relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
+ relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
+ relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
+ relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
+ relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
+ RSurf_ActiveModelEntity(ent, false, false, false);
+ ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
+ rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
}
#if 0
vec3_t tmp, shadowdir;
prvm_vec3_t prvmshadowdir;
- if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
+ if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
return;
r_shadow_fb_fbo = fbo;
R_Shadow_ClearStencil();
- for (i = 0;i < r_refdef.scene.numentities;i++)
+ for (i = 0;i < r_shadow_nummodelshadows;i++)
{
- ent = r_refdef.scene.entities[i];
+ ent = r_shadow_modelshadows[i];
// cast shadows from anything of the map (submodels are optional)
- if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
+ relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
+ VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
+ VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
+ if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
+ Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
+ else
{
- relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
- VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
- VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
- if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
- Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
- else
+ if(ent->entitynumber != 0)
{
- if(ent->entitynumber != 0)
+ if(ent->entitynumber >= MAX_EDICTS) // csqc entity
+ {
+ // FIXME handle this
+ VectorNegate(ent->modellight_lightdir, relativelightdirection);
+ }
+ else
{
- if(ent->entitynumber >= MAX_EDICTS) // csqc entity
+ // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
+ int entnum, entnum2, recursion;
+ entnum = entnum2 = ent->entitynumber;
+ for(recursion = 32; recursion > 0; --recursion)
{
- // FIXME handle this
- VectorNegate(ent->modellight_lightdir, relativelightdirection);
+ entnum2 = cl.entities[entnum].state_current.tagentity;
+ if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
+ entnum = entnum2;
+ else
+ break;
}
- else
+ if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
{
- // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
- int entnum, entnum2, recursion;
- entnum = entnum2 = ent->entitynumber;
- for(recursion = 32; recursion > 0; --recursion)
- {
- entnum2 = cl.entities[entnum].state_current.tagentity;
- if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
- entnum = entnum2;
- else
- break;
- }
- if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
- {
- VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
- // transform into modelspace of OUR entity
- Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
- Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
- }
- else
- VectorNegate(ent->modellight_lightdir, relativelightdirection);
+ VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
+ // transform into modelspace of OUR entity
+ Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
+ Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
}
+ else
+ VectorNegate(ent->modellight_lightdir, relativelightdirection);
}
- else
- VectorNegate(ent->modellight_lightdir, relativelightdirection);
}
-
- VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
- RSurf_ActiveModelEntity(ent, false, false, false);
- ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
- rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
+ else
+ VectorNegate(ent->modellight_lightdir, relativelightdirection);
}
+
+ VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
+ RSurf_ActiveModelEntity(ent, false, false, false);
+ ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
+ rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
}
// not really the right mode, but this will disable any silly stencil features