return Mod_Skeletal_AnimateVertices_bonepose;
}
+void Mod_Skeletal_BuildTransforms(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT bonepose, float * RESTRICT boneposerelative)
+{
+ int i, blends;
+ float m[12];
+
+ if (!bonepose)
+ bonepose = (float * RESTRICT) Mod_Skeletal_AnimateVertices_AllocBuffers(sizeof(float[12]) * model->num_bones);
+
+ if (skeleton && !skeleton->relativetransforms)
+ skeleton = NULL;
+
+ // interpolate matrices
+ if (skeleton)
+ {
+ for (i = 0;i < model->num_bones;i++)
+ {
+ Matrix4x4_ToArray12FloatD3D(&skeleton->relativetransforms[i], m);
+ if (model->data_bones[i].parent >= 0)
+ R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12);
+ else
+ memcpy(bonepose + i * 12, m, sizeof(m));
+
+ // create a relative deformation matrix to describe displacement
+ // from the base mesh, which is used by the actual weighting
+ R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
+ }
+ }
+ else
+ {
+ for (i = 0;i < model->num_bones;i++)
+ {
+ // blend by transform each quaternion/translation into a dual-quaternion first, then blending
+ const short * RESTRICT firstpose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i);
+ float firstlerp = frameblend[0].lerp,
+ firsttx = firstpose7s[0], firstty = firstpose7s[1], firsttz = firstpose7s[2],
+ rx = firstpose7s[3] * firstlerp,
+ ry = firstpose7s[4] * firstlerp,
+ rz = firstpose7s[5] * firstlerp,
+ rw = firstpose7s[6] * firstlerp,
+ dx = firsttx*rw + firstty*rz - firsttz*ry,
+ dy = -firsttx*rz + firstty*rw + firsttz*rx,
+ dz = firsttx*ry - firstty*rx + firsttz*rw,
+ dw = -firsttx*rx - firstty*ry - firsttz*rz,
+ scale, sx, sy, sz, sw;
+ for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
+ {
+ const short * RESTRICT blendpose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i);
+ float blendlerp = frameblend[blends].lerp,
+ blendtx = blendpose7s[0], blendty = blendpose7s[1], blendtz = blendpose7s[2],
+ qx = blendpose7s[3], qy = blendpose7s[4], qz = blendpose7s[5], qw = blendpose7s[6];
+ if(rx*qx + ry*qy + rz*qz + rw*qw < 0) blendlerp = -blendlerp;
+ qx *= blendlerp;
+ qy *= blendlerp;
+ qz *= blendlerp;
+ qw *= blendlerp;
+ rx += qx;
+ ry += qy;
+ rz += qz;
+ rw += qw;
+ dx += blendtx*qw + blendty*qz - blendtz*qy;
+ dy += -blendtx*qz + blendty*qw + blendtz*qx;
+ dz += blendtx*qy - blendty*qx + blendtz*qw;
+ dw += -blendtx*qx - blendty*qy - blendtz*qz;
+ }
+ // generate a matrix from the dual-quaternion, implicitly normalizing it in the process
+ scale = 1.0f / (rx*rx + ry*ry + rz*rz + rw*rw);
+ sx = rx * scale;
+ sy = ry * scale;
+ sz = rz * scale;
+ sw = rw * scale;
+ m[0] = sw*rw + sx*rx - sy*ry - sz*rz;
+ m[1] = 2*(sx*ry - sw*rz);
+ m[2] = 2*(sx*rz + sw*ry);
+ m[3] = model->num_posescale*(dx*sw - dy*sz + dz*sy - dw*sx);
+ m[4] = 2*(sx*ry + sw*rz);
+ m[5] = sw*rw + sy*ry - sx*rx - sz*rz;
+ m[6] = 2*(sy*rz - sw*rx);
+ m[7] = model->num_posescale*(dx*sz + dy*sw - dz*sx - dw*sy);
+ m[8] = 2*(sx*rz - sw*ry);
+ m[9] = 2*(sy*rz + sw*rx);
+ m[10] = sw*rw + sz*rz - sx*rx - sy*ry;
+ m[11] = model->num_posescale*(dy*sx + dz*sw - dx*sy - dw*sz);
+ if (i == r_skeletal_debugbone.integer)
+ m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value;
+ m[3] *= r_skeletal_debugtranslatex.value;
+ m[7] *= r_skeletal_debugtranslatey.value;
+ m[11] *= r_skeletal_debugtranslatez.value;
+ if (model->data_bones[i].parent >= 0)
+ R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12);
+ else
+ memcpy(bonepose + i * 12, m, sizeof(m));
+ // create a relative deformation matrix to describe displacement
+ // from the base mesh, which is used by the actual weighting
+ R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
+ }
+ }
+}
+
static void Mod_Skeletal_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
{
}
}
-static void Mod_MDLMD2MD3_TraceLine(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask)
+static void Mod_MDLMD2MD3_TraceLine(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
{
int i;
float segmentmins[3], segmentmaxs[3];
msurface_t *surface;
- float vertex3fbuf[1024*3];
+ float vertex3fbuf[1024 * 3];
float *vertex3f = vertex3fbuf;
+ float *freevertex3f = NULL;
+ // for static cases we can just call CollisionBIH which is much faster
+ if ((frameblend == NULL || (frameblend[0].subframe == 0 && frameblend[1].lerp == 0)) && (skeleton == NULL || skeleton->relativetransforms == NULL))
+ {
+ Mod_CollisionBIH_TraceLine(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
+ return;
+ }
memset(trace, 0, sizeof(*trace));
trace->fraction = 1;
- trace->realfraction = 1;
trace->hitsupercontentsmask = hitsupercontentsmask;
- if (model->surfmesh.num_vertices > 1024)
- vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
+ trace->skipsupercontentsmask = skipsupercontentsmask;
+ trace->skipmaterialflagsmask = skipmaterialflagsmask;
segmentmins[0] = min(start[0], end[0]) - 1;
segmentmins[1] = min(start[1], end[1]) - 1;
segmentmins[2] = min(start[2], end[2]) - 1;
segmentmaxs[0] = max(start[0], end[0]) + 1;
segmentmaxs[1] = max(start[1], end[1]) + 1;
segmentmaxs[2] = max(start[2], end[2]) + 1;
- model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
+ if (frameblend == NULL || frameblend[0].subframe != 0 || frameblend[0].lerp != 0 || skeleton != NULL)
+ {
+ if (model->surfmesh.num_vertices > 1024)
+ vertex3f = freevertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
+ model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
+ }
+ else
+ vertex3f = model->surfmesh.data_vertex3f;
for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
Collision_TraceLineTriangleMeshFloat(trace, start, end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
- if (vertex3f != vertex3fbuf)
- Mem_Free(vertex3f);
+ if (freevertex3f)
+ Mem_Free(freevertex3f);
}
-static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask)
+static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
{
int i;
vec3_t shiftstart, shiftend;
{
VectorAdd(start, boxmins, shiftstart);
VectorAdd(end, boxmins, shiftend);
- Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask);
+ Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
VectorSubtract(trace->endpos, boxmins, trace->endpos);
return;
}
+ // for static cases we can just call CollisionBIH which is much faster
+ if ((frameblend == NULL || (frameblend[0].subframe == 0 && frameblend[1].lerp == 0)) && (skeleton == NULL || skeleton->relativetransforms == NULL))
+ {
+ Mod_CollisionBIH_TraceBox(model, frameblend, skeleton, trace, start, boxmins, boxmaxs, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
+ return;
+ }
+
// box trace, performed as brush trace
memset(trace, 0, sizeof(*trace));
trace->fraction = 1;
- trace->realfraction = 1;
trace->hitsupercontentsmask = hitsupercontentsmask;
+ trace->skipsupercontentsmask = skipsupercontentsmask;
+ trace->skipmaterialflagsmask = skipmaterialflagsmask;
if (model->surfmesh.num_vertices > 1024)
vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
}
}
-static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *skinframe)
-{
- if (cls.state == ca_dedicated)
- return;
- // hack
- if (!skinframe)
- skinframe = R_SkinFrame_LoadMissing();
- memset(texture, 0, sizeof(*texture));
- texture->currentframe = texture;
- //texture->animated = false;
- texture->numskinframes = 1;
- texture->skinframerate = 1;
- texture->skinframes[0] = skinframe;
- texture->currentskinframe = skinframe;
- //texture->backgroundnumskinframes = 0;
- //texture->customblendfunc[0] = 0;
- //texture->customblendfunc[1] = 0;
- //texture->surfaceflags = 0;
- //texture->supercontents = 0;
- //texture->surfaceparms = 0;
- //texture->textureflags = 0;
-
- texture->basematerialflags = MATERIALFLAG_WALL;
- if (texture->currentskinframe->hasalpha)
- texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
- texture->currentmaterialflags = texture->basematerialflags;
- texture->offsetmapping = OFFSETMAPPING_DEFAULT;
- texture->offsetscale = 1;
- texture->offsetbias = 0;
- texture->specularscalemod = 1;
- texture->specularpowermod = 1;
- texture->surfaceflags = 0;
- texture->supercontents = SUPERCONTENTS_SOLID;
- if (!(texture->basematerialflags & MATERIALFLAG_BLENDED))
- texture->supercontents |= SUPERCONTENTS_OPAQUE;
- texture->transparentsort = TRANSPARENTSORT_DISTANCE;
- // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
- // JUST GREP FOR "specularscalemod = 1".
-}
-
void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
{
int i;
Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
if(developer_extra.integer)
Con_DPrintf("--> got %s from skin file\n", stripbuf);
- Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
+ Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
break;
}
}
if (!skinfileitem)
{
// don't render unmentioned meshes
- Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
+ Mod_LoadCustomMaterial(loadmodel->mempool, skin, meshname, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
if(developer_extra.integer)
Con_DPrintf("--> skipping\n");
skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
if(developer_extra.integer)
Con_DPrintf("--> using default\n");
Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
- Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
+ Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
}
}
float *vertst;
int *vertonseam, *vertremap;
skinfile_t *skinfiles;
- char vabuf[1024];
datapointer = (unsigned char *)buffer;
pinmodel = (mdl_t *)datapointer;
dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
else
dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
- if (!Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS))
- Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight));
+ if (!Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, false, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL))
+ Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight));
datapointer += skinwidth * skinheight;
totalskins++;
}
// check for skins that don't exist in the model, but do exist as external images
// (this was added because yummyluv kept pestering me about support for it)
// TODO: support shaders here?
- while ((tempskinframe = R_SkinFrame_LoadExternal(va(vabuf, sizeof(vabuf), "%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false)))
+ for (;;)
{
+ dpsnprintf(name, sizeof(name), "%s_%i", loadmodel->name, loadmodel->numskins);
+ tempskinframe = R_SkinFrame_LoadExternal(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false, false);
+ if (!tempskinframe)
+ break;
// expand the arrays to make room
tempskinscenes = loadmodel->skinscenes;
loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
Mem_Free(tempaliasskins);
// store the info about the new skin
- Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
+ Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, tempskinframe);
strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
loadmodel->skinscenes[loadmodel->numskins].loop = true;
//increase skin counts
+ loadmodel->num_textures++;
loadmodel->numskins++;
totalskins++;
if(mod_alias_force_animated.string[0])
loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
+ // Always make a BIH for the first frame, we can use it where possible.
+ Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
if (!loadmodel->surfmesh.isanimated)
{
- Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
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_PICMIP | TEXF_COMPRESS);
+ Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
}
else
{
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);
+ Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures, loadmodel->name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
}
loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
surface->num_firstvertex = 0;
surface->num_vertices = loadmodel->surfmesh.num_vertices;
+ // Always make a BIH for the first frame, we can use it where possible.
+ Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
if (!loadmodel->surfmesh.isanimated)
{
- Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
if(mod_alias_force_animated.string[0])
loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
+ // Always make a BIH for the first frame, we can use it where possible.
+ Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
if (!loadmodel->surfmesh.isanimated)
{
- Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
if(mod_alias_force_animated.string[0])
loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
+ // Always make a BIH for the first frame, we can use it where possible.
+ Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
if (!loadmodel->surfmesh.isanimated)
{
- Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
if(mod_alias_force_animated.string[0])
loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
+ // Always make a BIH for the first frame, we can use it where possible.
+ Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
if (!loadmodel->surfmesh.isanimated)
{
- Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
if(mod_alias_force_animated.string[0])
loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
+ // Always make a BIH for the first frame, we can use it where possible.
+ Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
if (!loadmodel->surfmesh.isanimated)
{
- Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
if (!header.ofs_bounds)
Mod_Alias_CalculateBoundingBox();
- if (!loadmodel->surfmesh.isanimated && loadmodel->surfmesh.num_triangles >= 1)
+ // Always make a BIH for the first frame, we can use it where possible.
+ Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
+ if (!loadmodel->surfmesh.isanimated)
{
- Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;