2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 cvar_t r_skeletal_debugbone = {0, "r_skeletal_debugbone", "-1", "development cvar for testing skeletal model code"};
26 cvar_t r_skeletal_debugbonecomponent = {0, "r_skeletal_debugbonecomponent", "3", "development cvar for testing skeletal model code"};
27 cvar_t r_skeletal_debugbonevalue = {0, "r_skeletal_debugbonevalue", "100", "development cvar for testing skeletal model code"};
28 cvar_t r_skeletal_debugtranslatex = {0, "r_skeletal_debugtranslatex", "1", "development cvar for testing skeletal model code"};
29 cvar_t r_skeletal_debugtranslatey = {0, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"};
30 cvar_t r_skeletal_debugtranslatez = {0, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"};
31 cvar_t mod_alias_supporttagscale = {0, "mod_alias_supporttagscale", "1", "support scaling factors in bone/tag attachment matrices as supported by MD3"};
33 float mod_md3_sin[320];
35 void Mod_AliasInit (void)
38 Cvar_RegisterVariable(&r_skeletal_debugbone);
39 Cvar_RegisterVariable(&r_skeletal_debugbonecomponent);
40 Cvar_RegisterVariable(&r_skeletal_debugbonevalue);
41 Cvar_RegisterVariable(&r_skeletal_debugtranslatex);
42 Cvar_RegisterVariable(&r_skeletal_debugtranslatey);
43 Cvar_RegisterVariable(&r_skeletal_debugtranslatez);
44 Cvar_RegisterVariable(&mod_alias_supporttagscale);
45 for (i = 0;i < 320;i++)
46 mod_md3_sin[i] = sin(i * M_PI * 2.0f / 256.0);
49 void Mod_Skeletal_AnimateVertices(const dp_model_t *model, const frameblend_t *frameblend, float *vertex3f, float *normal3f, float *svector3f, float *tvector3f)
52 // vertex weighted skeletal
55 float desiredscale[3];
56 float boneposerelative[MAX_BONES][12];
57 float *matrix, m[12], bonepose[MAX_BONES][12];
59 // interpolate matrices and concatenate them to their parents
60 for (i = 0;i < model->num_bones;i++)
62 for (k = 0;k < 12;k++)
64 VectorClear(desiredscale);
65 for (blends = 0;blends < 4 && frameblend[blends].lerp > 0;blends++)
67 matrix = model->data_poses + (frameblend[blends].frame * model->num_bones + i) * 12;
68 for (k = 0;k < 12;k++)
69 m[k] += matrix[k] * frameblend[blends].lerp;
70 desiredscale[0] += frameblend[blends].lerp * VectorLength(matrix );
71 desiredscale[1] += frameblend[blends].lerp * VectorLength(matrix + 4);
72 desiredscale[2] += frameblend[blends].lerp * VectorLength(matrix + 8);
75 VectorNormalize(m + 4);
76 VectorNormalize(m + 8);
77 VectorScale(m , desiredscale[0], m );
78 VectorScale(m + 4, desiredscale[1], m + 4);
79 VectorScale(m + 8, desiredscale[2], m + 8);
80 if (i == r_skeletal_debugbone.integer)
81 m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value;
82 m[3] *= r_skeletal_debugtranslatex.value;
83 m[7] *= r_skeletal_debugtranslatey.value;
84 m[11] *= r_skeletal_debugtranslatez.value;
85 if (model->data_bones[i].parent >= 0)
86 R_ConcatTransforms(bonepose[model->data_bones[i].parent], m, bonepose[i]);
88 for (k = 0;k < 12;k++)
89 bonepose[i][k] = m[k];
90 // create a relative deformation matrix to describe displacement
91 // from the base mesh, which is used by the actual weighting
92 R_ConcatTransforms(bonepose[i], model->data_baseboneposeinverse + i * 12, boneposerelative[i]);
94 // blend the vertex bone weights
95 // special case for the extremely common wf[0] == 1 because it saves 3 multiplies per array when compared to the other case (w[0] is always 1 if only one bone controls this vertex, artists only use multiple bones for certain special cases)
96 // special case for the first bone because it avoids the need to memset the arrays before filling
98 const float *v = model->surfmesh.data_vertex3f;
99 const int *wi = model->surfmesh.data_vertexweightindex4i;
100 const float *wf = model->surfmesh.data_vertexweightinfluence4f;
101 memset(vertex3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices);
102 for (i = 0;i < model->surfmesh.num_vertices;i++, v += 3, wi += 4, wf += 4, vertex3f += 3)
106 const float *m = boneposerelative[wi[0]];
107 vertex3f[0] = (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
108 vertex3f[1] = (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
109 vertex3f[2] = (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
113 const float *m = boneposerelative[wi[0]];
115 vertex3f[0] = f * (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
116 vertex3f[1] = f * (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
117 vertex3f[2] = f * (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
118 for (k = 1;k < 4 && wf[k];k++)
120 const float *m = boneposerelative[wi[k]];
122 vertex3f[0] += f * (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
123 vertex3f[1] += f * (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
124 vertex3f[2] += f * (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
131 const float *n = model->surfmesh.data_normal3f;
132 const int *wi = model->surfmesh.data_vertexweightindex4i;
133 const float *wf = model->surfmesh.data_vertexweightinfluence4f;
134 memset(normal3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices);
135 for (i = 0;i < model->surfmesh.num_vertices;i++, n += 3, wi += 4, wf += 4, normal3f += 3)
139 const float *m = boneposerelative[wi[0]];
140 normal3f[0] = (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
141 normal3f[1] = (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]);
142 normal3f[2] = (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]);
146 const float *m = boneposerelative[wi[0]];
148 normal3f[0] = f * (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
149 normal3f[1] = f * (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]);
150 normal3f[2] = f * (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]);
151 for (k = 1;k < 4 && wf[k];k++)
153 const float *m = boneposerelative[wi[k]];
155 normal3f[0] += f * (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
156 normal3f[1] += f * (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]);
157 normal3f[2] += f * (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]);
164 const float *sv = model->surfmesh.data_svector3f;
165 const int *wi = model->surfmesh.data_vertexweightindex4i;
166 const float *wf = model->surfmesh.data_vertexweightinfluence4f;
167 memset(svector3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices);
168 for (i = 0;i < model->surfmesh.num_vertices;i++, sv += 3, wi += 4, wf += 4, svector3f += 3)
172 const float *m = boneposerelative[wi[0]];
173 svector3f[0] = (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]);
174 svector3f[1] = (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]);
175 svector3f[2] = (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]);
179 const float *m = boneposerelative[wi[0]];
181 svector3f[0] = f * (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]);
182 svector3f[1] = f * (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]);
183 svector3f[2] = f * (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]);
184 for (k = 1;k < 4 && wf[k];k++)
186 const float *m = boneposerelative[wi[k]];
188 svector3f[0] += f * (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]);
189 svector3f[1] += f * (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]);
190 svector3f[2] += f * (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]);
197 const float *tv = model->surfmesh.data_tvector3f;
198 const int *wi = model->surfmesh.data_vertexweightindex4i;
199 const float *wf = model->surfmesh.data_vertexweightinfluence4f;
200 memset(tvector3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices);
201 for (i = 0;i < model->surfmesh.num_vertices;i++, tv += 3, wi += 4, wf += 4, tvector3f += 3)
205 const float *m = boneposerelative[wi[0]];
206 tvector3f[0] = (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]);
207 tvector3f[1] = (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]);
208 tvector3f[2] = (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]);
212 const float *m = boneposerelative[wi[0]];
214 tvector3f[0] = f * (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]);
215 tvector3f[1] = f * (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]);
216 tvector3f[2] = f * (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]);
217 for (k = 1;k < 4 && wf[k];k++)
219 const float *m = boneposerelative[wi[k]];
221 tvector3f[0] += f * (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]);
222 tvector3f[1] += f * (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]);
223 tvector3f[2] += f * (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]);
230 void Mod_MD3_AnimateVertices(const dp_model_t *model, const frameblend_t *frameblend, float *vertex3f, float *normal3f, float *svector3f, float *tvector3f)
233 int i, numblends, blendnum;
234 int numverts = model->surfmesh.num_vertices;
236 for (blendnum = 0;blendnum < 4;blendnum++)
238 //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate);
239 if (frameblend[blendnum].lerp > 0)
240 numblends = blendnum + 1;
242 // special case for the first blend because it avoids some adds and the need to memset the arrays first
243 for (blendnum = 0;blendnum < numblends;blendnum++)
245 const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].frame;
246 float scale = frameblend[blendnum].lerp * (1.0f / 64.0f);
249 for (i = 0;i < numverts;i++)
251 vertex3f[i * 3 + 0] = verts[i].origin[0] * scale;
252 vertex3f[i * 3 + 1] = verts[i].origin[1] * scale;
253 vertex3f[i * 3 + 2] = verts[i].origin[2] * scale;
258 for (i = 0;i < numverts;i++)
260 vertex3f[i * 3 + 0] += verts[i].origin[0] * scale;
261 vertex3f[i * 3 + 1] += verts[i].origin[1] * scale;
262 vertex3f[i * 3 + 2] += verts[i].origin[2] * scale;
265 // the yaw and pitch stored in md3 models are 8bit quantized angles
266 // (0-255), and as such a lookup table is very well suited to
267 // decoding them, and since cosine is equivilant to sine with an
268 // extra 45 degree rotation, this uses one lookup table for both
269 // sine and cosine with a +64 bias to get cosine.
272 float lerp = frameblend[blendnum].lerp;
275 for (i = 0;i < numverts;i++)
277 normal3f[i * 3 + 0] = mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp;
278 normal3f[i * 3 + 1] = mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp;
279 normal3f[i * 3 + 2] = mod_md3_sin[verts[i].pitch + 64] * lerp;
284 for (i = 0;i < numverts;i++)
286 normal3f[i * 3 + 0] += mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp;
287 normal3f[i * 3 + 1] += mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp;
288 normal3f[i * 3 + 2] += mod_md3_sin[verts[i].pitch + 64] * lerp;
294 const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].frame;
295 float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
298 for (i = 0;i < numverts;i++, texvecvert++)
300 VectorScale(texvecvert->svec, f, svector3f + i*3);
301 VectorScale(texvecvert->tvec, f, tvector3f + i*3);
306 for (i = 0;i < numverts;i++, texvecvert++)
308 VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
309 VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
316 void Mod_MDL_AnimateVertices(const dp_model_t *model, const frameblend_t *frameblend, float *vertex3f, float *normal3f, float *svector3f, float *tvector3f)
319 int i, numblends, blendnum;
320 int numverts = model->surfmesh.num_vertices;
322 VectorClear(translate);
324 // blend the frame translates to avoid redundantly doing so on each vertex
325 // (a bit of a brain twister but it works)
326 for (blendnum = 0;blendnum < 4;blendnum++)
328 if (model->surfmesh.data_morphmd2framesize6f)
329 VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].frame * 6 + 3, translate);
331 VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate);
332 if (frameblend[blendnum].lerp > 0)
333 numblends = blendnum + 1;
335 // special case for the first blend because it avoids some adds and the need to memset the arrays first
336 for (blendnum = 0;blendnum < numblends;blendnum++)
338 const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].frame;
340 if (model->surfmesh.data_morphmd2framesize6f)
341 VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].frame * 6, frameblend[blendnum].lerp, scale);
343 VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale);
346 for (i = 0;i < numverts;i++)
348 vertex3f[i * 3 + 0] = translate[0] + verts[i].v[0] * scale[0];
349 vertex3f[i * 3 + 1] = translate[1] + verts[i].v[1] * scale[1];
350 vertex3f[i * 3 + 2] = translate[2] + verts[i].v[2] * scale[2];
355 for (i = 0;i < numverts;i++)
357 vertex3f[i * 3 + 0] += verts[i].v[0] * scale[0];
358 vertex3f[i * 3 + 1] += verts[i].v[1] * scale[1];
359 vertex3f[i * 3 + 2] += verts[i].v[2] * scale[2];
362 // the vertex normals in mdl models are an index into a table of
363 // 162 unique values, this very crude quantization reduces the
364 // vertex normal to only one byte, which saves a lot of space but
365 // also makes lighting pretty coarse
368 float lerp = frameblend[blendnum].lerp;
371 for (i = 0;i < numverts;i++)
373 const float *vn = m_bytenormals[verts[i].lightnormalindex];
374 VectorScale(vn, lerp, normal3f + i*3);
379 for (i = 0;i < numverts;i++)
381 const float *vn = m_bytenormals[verts[i].lightnormalindex];
382 VectorMA(normal3f + i*3, lerp, vn, normal3f + i*3);
388 const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].frame;
389 float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
392 for (i = 0;i < numverts;i++, texvecvert++)
394 VectorScale(texvecvert->svec, f, svector3f + i*3);
395 VectorScale(texvecvert->tvec, f, tvector3f + i*3);
400 for (i = 0;i < numverts;i++, texvecvert++)
402 VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
403 VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
410 int Mod_Alias_GetTagMatrix(const dp_model_t *model, int poseframe, int tagindex, matrix4x4_t *outmatrix)
412 const float *boneframe;
413 float tempbonematrix[12], bonematrix[12];
414 *outmatrix = identitymatrix;
415 if (model->num_bones)
417 if (tagindex < 0 || tagindex >= model->num_bones)
419 if (poseframe >= model->num_poses)
421 boneframe = model->data_poses + poseframe * model->num_bones * 12;
422 memcpy(bonematrix, boneframe + tagindex * 12, sizeof(float[12]));
423 while (model->data_bones[tagindex].parent >= 0)
425 memcpy(tempbonematrix, bonematrix, sizeof(float[12]));
426 R_ConcatTransforms(boneframe + model->data_bones[tagindex].parent * 12, tempbonematrix, bonematrix);
427 tagindex = model->data_bones[tagindex].parent;
429 Matrix4x4_FromArray12FloatD3D(outmatrix, bonematrix);
431 else if (model->num_tags)
433 if (tagindex < 0 || tagindex >= model->num_tags)
435 if (poseframe >= model->num_tagframes)
437 Matrix4x4_FromArray12FloatGL(outmatrix, model->data_tags[poseframe * model->num_tags + tagindex].matrixgl);
440 if(!mod_alias_supporttagscale.integer)
441 Matrix4x4_Normalize3(outmatrix, outmatrix);
446 int Mod_Alias_GetTagIndexForName(const dp_model_t *model, unsigned int skin, const char *tagname)
449 if(skin >= (unsigned int)model->numskins)
451 if (model->num_bones)
452 for (i = 0;i < model->num_bones;i++)
453 if (!strcasecmp(tagname, model->data_bones[i].name))
456 for (i = 0;i < model->num_tags;i++)
457 if (!strcasecmp(tagname, model->data_tags[i].name))
462 static void Mod_BuildBaseBonePoses(void)
466 float *basebonepose = (float *) Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(float[12]));
467 float *in12f = loadmodel->data_poses;
468 float *out12f = basebonepose;
469 float *outinv12f = loadmodel->data_baseboneposeinverse;
470 for (i = 0;i < loadmodel->num_bones;i++, in12f += 12, out12f += 12, outinv12f += 12)
472 if (loadmodel->data_bones[i].parent >= 0)
473 R_ConcatTransforms(basebonepose + 12 * loadmodel->data_bones[i].parent, in12f, out12f);
475 for (k = 0;k < 12;k++)
476 out12f[k] = in12f[k];
480 // we only support uniform scaling, so assume the first row is enough
481 // (note the lack of sqrt here, because we're trying to undo the scaling,
482 // this means multiplying by the inverse scale twice - squaring it, which
483 // makes the sqrt a waste of time)
484 scale = 1.0 / (out12f[ 0] * out12f[ 0] + out12f[ 1] * out12f[ 1] + out12f[ 2] * out12f[ 2]);
486 // invert the rotation by transposing and multiplying by the squared
487 // recipricol of the input matrix scale as described above
488 outinv12f[ 0] = (float)(out12f[ 0] * scale);
489 outinv12f[ 1] = (float)(out12f[ 4] * scale);
490 outinv12f[ 2] = (float)(out12f[ 8] * scale);
491 outinv12f[ 4] = (float)(out12f[ 1] * scale);
492 outinv12f[ 5] = (float)(out12f[ 5] * scale);
493 outinv12f[ 6] = (float)(out12f[ 9] * scale);
494 outinv12f[ 8] = (float)(out12f[ 2] * scale);
495 outinv12f[ 9] = (float)(out12f[ 6] * scale);
496 outinv12f[10] = (float)(out12f[10] * scale);
498 // invert the translate
499 outinv12f[ 3] = -(out12f[ 3] * outinv12f[ 0] + out12f[ 7] * outinv12f[ 1] + out12f[11] * outinv12f[ 2]);
500 outinv12f[ 7] = -(out12f[ 3] * outinv12f[ 4] + out12f[ 7] * outinv12f[ 5] + out12f[11] * outinv12f[ 6]);
501 outinv12f[11] = -(out12f[ 3] * outinv12f[ 8] + out12f[ 7] * outinv12f[ 9] + out12f[11] * outinv12f[10]);
503 Mem_Free(basebonepose);
506 static void Mod_Alias_CalculateBoundingBox(void)
509 qboolean firstvertex = true;
510 float dist, yawradius, radius;
513 frameblend_t frameblend[4];
514 memset(frameblend, 0, sizeof(frameblend));
515 frameblend[0].lerp = 1;
516 vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
517 VectorClear(loadmodel->normalmins);
518 VectorClear(loadmodel->normalmaxs);
521 for (frameblend[0].frame = 0;frameblend[0].frame < loadmodel->num_poses;frameblend[0].frame++)
523 loadmodel->AnimateVertices(loadmodel, frameblend, vertex3f, NULL, NULL, NULL);
524 for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
529 VectorCopy(v, loadmodel->normalmins);
530 VectorCopy(v, loadmodel->normalmaxs);
534 if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
535 if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
536 if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
537 if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
538 if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
539 if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
541 dist = v[0] * v[0] + v[1] * v[1];
542 if (yawradius < dist)
550 radius = sqrt(radius);
551 yawradius = sqrt(yawradius);
552 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
553 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius;
554 loadmodel->yawmins[2] = loadmodel->normalmins[2];
555 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
556 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
557 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
558 loadmodel->radius = radius;
559 loadmodel->radius2 = radius * radius;
562 static void Mod_Alias_MorphMesh_CompileFrames(void)
565 frameblend_t frameblend[4] = {{0, 1}, {0, 0}, {0, 0}, {0, 0}};
566 unsigned char *datapointer;
567 datapointer = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * (sizeof(float[3]) * 4 + loadmodel->surfmesh.num_morphframes * sizeof(texvecvertex_t)));
568 loadmodel->surfmesh.data_vertex3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
569 loadmodel->surfmesh.data_svector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
570 loadmodel->surfmesh.data_tvector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
571 loadmodel->surfmesh.data_normal3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
572 loadmodel->surfmesh.data_morphtexvecvertex = (texvecvertex_t *)datapointer;datapointer += loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices * sizeof(texvecvertex_t);
573 // this counts down from the last frame to the first so that the final data in surfmesh is for frame zero (which is what the renderer expects to be there)
574 for (i = loadmodel->surfmesh.num_morphframes-1;i >= 0;i--)
576 frameblend[0].frame = i;
577 loadmodel->AnimateVertices(loadmodel, frameblend, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL);
578 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);
579 // encode the svector and tvector in 3 byte format for permanent storage
580 for (j = 0;j < loadmodel->surfmesh.num_vertices;j++)
582 VectorScale(loadmodel->surfmesh.data_svector3f + j * 3, 127.0f, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].svec);
583 VectorScale(loadmodel->surfmesh.data_tvector3f + j * 3, 127.0f, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].tvec);
588 static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, int frame, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask)
591 float segmentmins[3], segmentmaxs[3];
592 frameblend_t frameblend[4];
594 static int maxvertices = 0;
595 static float *vertex3f = NULL;
596 memset(trace, 0, sizeof(*trace));
598 trace->realfraction = 1;
599 trace->hitsupercontentsmask = hitsupercontentsmask;
600 memset(frameblend, 0, sizeof(frameblend));
601 frameblend[0].frame = frame;
602 frameblend[0].lerp = 1;
603 if (maxvertices < model->surfmesh.num_vertices)
607 maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
608 vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3]));
610 if (VectorLength2(boxmins) + VectorLength2(boxmaxs) == 0)
613 segmentmins[0] = min(start[0], end[0]) - 1;
614 segmentmins[1] = min(start[1], end[1]) - 1;
615 segmentmins[2] = min(start[2], end[2]) - 1;
616 segmentmaxs[0] = max(start[0], end[0]) + 1;
617 segmentmaxs[1] = max(start[1], end[1]) + 1;
618 segmentmaxs[2] = max(start[2], end[2]) + 1;
619 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
621 model->AnimateVertices(model, frameblend, vertex3f, NULL, NULL, NULL);
622 Collision_TraceLineTriangleMeshFloat(trace, start, end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, SUPERCONTENTS_SOLID, 0, surface->texture, segmentmins, segmentmaxs);
627 // box trace, performed as brush trace
628 colbrushf_t *thisbrush_start, *thisbrush_end;
629 vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
630 segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
631 segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
632 segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
633 segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
634 segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
635 segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
636 VectorAdd(start, boxmins, boxstartmins);
637 VectorAdd(start, boxmaxs, boxstartmaxs);
638 VectorAdd(end, boxmins, boxendmins);
639 VectorAdd(end, boxmaxs, boxendmaxs);
640 thisbrush_start = Collision_BrushForBox(&identitymatrix, boxstartmins, boxstartmaxs, 0, 0, NULL);
641 thisbrush_end = Collision_BrushForBox(&identitymatrix, boxendmins, boxendmaxs, 0, 0, NULL);
642 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
644 if (maxvertices < model->surfmesh.num_vertices)
648 maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
649 vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3]));
651 model->AnimateVertices(model, frameblend, vertex3f, NULL, NULL, NULL);
652 Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, SUPERCONTENTS_SOLID, 0, surface->texture, segmentmins, segmentmaxs);
657 static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
660 for (i = 0;i < inverts;i++)
662 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
664 j = vertremap[i]; // not onseam
667 j = vertremap[i+inverts]; // onseam
673 static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
675 int i, f, pose, groupframes;
677 daliasframetype_t *pframetype;
678 daliasframe_t *pinframe;
679 daliasgroup_t *group;
680 daliasinterval_t *intervals;
683 scene = loadmodel->animscenes;
684 for (f = 0;f < loadmodel->numframes;f++)
686 pframetype = (daliasframetype_t *)datapointer;
687 datapointer += sizeof(daliasframetype_t);
688 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
690 // a single frame is still treated as a group
697 group = (daliasgroup_t *)datapointer;
698 datapointer += sizeof(daliasgroup_t);
699 groupframes = LittleLong (group->numframes);
701 // intervals (time per frame)
702 intervals = (daliasinterval_t *)datapointer;
703 datapointer += sizeof(daliasinterval_t) * groupframes;
705 interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
706 if (interval < 0.01f)
708 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
713 // get scene name from first frame
714 pinframe = (daliasframe_t *)datapointer;
716 strlcpy(scene->name, pinframe->name, sizeof(scene->name));
717 scene->firstframe = pose;
718 scene->framecount = groupframes;
719 scene->framerate = 1.0f / interval;
724 for (i = 0;i < groupframes;i++)
726 pinframe = (daliasframe_t *)datapointer;
727 datapointer += sizeof(daliasframe_t);
728 Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
729 datapointer += sizeof(trivertx_t) * inverts;
735 static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *skinframe)
737 if (cls.state == ca_dedicated)
741 skinframe = R_SkinFrame_LoadMissing();
742 memset(texture, 0, sizeof(*texture));
743 texture->currentframe = texture;
744 //texture->animated = false;
745 texture->numskinframes = 1;
746 texture->skinframerate = 1;
747 texture->skinframes[0] = skinframe;
748 texture->currentskinframe = skinframe;
749 //texture->backgroundnumskinframes = 0;
750 //texture->customblendfunc[0] = 0;
751 //texture->customblendfunc[1] = 0;
752 //texture->surfaceflags = 0;
753 //texture->supercontents = 0;
754 //texture->surfaceparms = 0;
755 //texture->textureflags = 0;
757 texture->basematerialflags = MATERIALFLAG_WALL;
758 if (texture->currentskinframe->fog)
759 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
760 texture->currentmaterialflags = texture->basematerialflags;
763 static void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
766 skinfileitem_t *skinfileitem;
769 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
770 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
772 memset(skin, 0, sizeof(*skin));
774 for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
776 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
777 if (!strcmp(skinfileitem->name, meshname))
779 Mod_LoadTextureFromQ3Shader(skin, skinfileitem->replacement, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP | TEXF_COMPRESS);
785 // don't render unmentioned meshes
786 Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
787 skin->basematerialflags = skin->currentmaterialflags = 0;
792 Mod_LoadTextureFromQ3Shader(skin, shadername, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP | TEXF_COMPRESS);
795 #define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)", loadmodel->name, VALUE, MIN, MAX);
796 #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)", loadmodel->name, VALUE, MIN, MAX);
797 void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
799 int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
800 float scales, scalet, interval;
804 stvert_t *pinstverts;
805 dtriangle_t *pintriangles;
806 daliasskintype_t *pinskintype;
807 daliasskingroup_t *pinskingroup;
808 daliasskininterval_t *pinskinintervals;
809 daliasframetype_t *pinframetype;
810 daliasgroup_t *pinframegroup;
811 unsigned char *datapointer, *startframes, *startskins;
812 char name[MAX_QPATH];
813 skinframe_t *tempskinframe;
814 animscene_t *tempskinscenes;
815 texture_t *tempaliasskins;
817 int *vertonseam, *vertremap;
818 skinfile_t *skinfiles;
820 datapointer = (unsigned char *)buffer;
821 pinmodel = (mdl_t *)datapointer;
822 datapointer += sizeof(mdl_t);
824 version = LittleLong (pinmodel->version);
825 if (version != ALIAS_VERSION)
826 Host_Error ("%s has wrong version number (%i should be %i)",
827 loadmodel->name, version, ALIAS_VERSION);
829 loadmodel->modeldatatypestring = "MDL";
831 loadmodel->type = mod_alias;
832 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
833 loadmodel->DrawSky = NULL;
834 loadmodel->DrawAddWaterPlanes = NULL;
835 loadmodel->Draw = R_Q1BSP_Draw;
836 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
837 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
838 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
839 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
840 loadmodel->DrawLight = R_Q1BSP_DrawLight;
841 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
842 loadmodel->PointSuperContents = NULL;
844 loadmodel->num_surfaces = 1;
845 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
846 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
847 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
848 loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
849 loadmodel->surfacelist[0] = 0;
851 loadmodel->numskins = LittleLong(pinmodel->numskins);
852 BOUNDI(loadmodel->numskins,0,65536);
853 skinwidth = LittleLong (pinmodel->skinwidth);
854 BOUNDI(skinwidth,0,65536);
855 skinheight = LittleLong (pinmodel->skinheight);
856 BOUNDI(skinheight,0,65536);
857 numverts = LittleLong(pinmodel->numverts);
858 BOUNDI(numverts,0,65536);
859 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
860 BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
861 loadmodel->numframes = LittleLong(pinmodel->numframes);
862 BOUNDI(loadmodel->numframes,0,65536);
863 loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
864 BOUNDI(loadmodel->synctype,0,2);
865 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
866 i = LittleLong (pinmodel->flags);
867 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
869 for (i = 0;i < 3;i++)
871 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
872 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
875 startskins = datapointer;
877 for (i = 0;i < loadmodel->numskins;i++)
879 pinskintype = (daliasskintype_t *)datapointer;
880 datapointer += sizeof(daliasskintype_t);
881 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
885 pinskingroup = (daliasskingroup_t *)datapointer;
886 datapointer += sizeof(daliasskingroup_t);
887 groupskins = LittleLong(pinskingroup->numskins);
888 datapointer += sizeof(daliasskininterval_t) * groupskins;
891 for (j = 0;j < groupskins;j++)
893 datapointer += skinwidth * skinheight;
898 pinstverts = (stvert_t *)datapointer;
899 datapointer += sizeof(stvert_t) * numverts;
901 pintriangles = (dtriangle_t *)datapointer;
902 datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
904 startframes = datapointer;
905 loadmodel->surfmesh.num_morphframes = 0;
906 for (i = 0;i < loadmodel->numframes;i++)
908 pinframetype = (daliasframetype_t *)datapointer;
909 datapointer += sizeof(daliasframetype_t);
910 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
914 pinframegroup = (daliasgroup_t *)datapointer;
915 datapointer += sizeof(daliasgroup_t);
916 groupframes = LittleLong(pinframegroup->numframes);
917 datapointer += sizeof(daliasinterval_t) * groupframes;
920 for (j = 0;j < groupframes;j++)
922 datapointer += sizeof(daliasframe_t);
923 datapointer += sizeof(trivertx_t) * numverts;
924 loadmodel->surfmesh.num_morphframes++;
927 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
929 // store texture coordinates into temporary array, they will be stored
930 // after usage is determined (triangle data)
931 vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
932 vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
933 vertonseam = vertremap + numverts * 2;
935 scales = 1.0 / skinwidth;
936 scalet = 1.0 / skinheight;
937 for (i = 0;i < numverts;i++)
939 vertonseam[i] = LittleLong(pinstverts[i].onseam);
940 vertst[i*2+0] = (LittleLong(pinstverts[i].s) + 0.5) * scales;
941 vertst[i*2+1] = (LittleLong(pinstverts[i].t) + 0.5) * scalet;
942 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
943 vertst[(i+numverts)*2+1] = vertst[i*2+1];
946 // load triangle data
947 loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
949 // read the triangle elements
950 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
951 for (j = 0;j < 3;j++)
952 loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
953 // validate (note numverts is used because this is the original data)
954 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
955 // now butcher the elements according to vertonseam and tri->facesfront
956 // and then compact the vertex set to remove duplicates
957 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
958 if (!LittleLong(pintriangles[i].facesfront)) // backface
959 for (j = 0;j < 3;j++)
960 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
961 loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
963 // (this uses vertremap to count usage to save some memory)
964 for (i = 0;i < numverts*2;i++)
966 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
967 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
968 // build remapping table and compact array
969 loadmodel->surfmesh.num_vertices = 0;
970 for (i = 0;i < numverts*2;i++)
974 vertremap[i] = loadmodel->surfmesh.num_vertices;
975 vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
976 vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
977 loadmodel->surfmesh.num_vertices++;
980 vertremap[i] = -1; // not used at all
982 // remap the elements to the new vertex set
983 for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
984 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
985 // store the texture coordinates
986 loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
987 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
989 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
990 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
993 // generate ushort elements array if possible
994 if (loadmodel->surfmesh.num_vertices <= 65536)
996 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
997 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
998 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1002 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1003 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1004 loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1005 Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1006 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1007 Mod_Alias_CalculateBoundingBox();
1008 Mod_Alias_MorphMesh_CompileFrames();
1011 Mem_Free(vertremap);
1014 skinfiles = Mod_LoadSkinFiles();
1017 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1018 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1019 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1020 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1021 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1022 Mod_FreeSkinFiles(skinfiles);
1023 for (i = 0;i < loadmodel->numskins;i++)
1025 loadmodel->skinscenes[i].firstframe = i;
1026 loadmodel->skinscenes[i].framecount = 1;
1027 loadmodel->skinscenes[i].loop = true;
1028 loadmodel->skinscenes[i].framerate = 10;
1033 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1034 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1035 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1036 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1038 datapointer = startskins;
1039 for (i = 0;i < loadmodel->numskins;i++)
1041 pinskintype = (daliasskintype_t *)datapointer;
1042 datapointer += sizeof(daliasskintype_t);
1044 if (pinskintype->type == ALIAS_SKIN_SINGLE)
1051 pinskingroup = (daliasskingroup_t *)datapointer;
1052 datapointer += sizeof(daliasskingroup_t);
1054 groupskins = LittleLong (pinskingroup->numskins);
1056 pinskinintervals = (daliasskininterval_t *)datapointer;
1057 datapointer += sizeof(daliasskininterval_t) * groupskins;
1059 interval = LittleFloat(pinskinintervals[0].interval);
1060 if (interval < 0.01f)
1062 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1067 dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1068 loadmodel->skinscenes[i].firstframe = totalskins;
1069 loadmodel->skinscenes[i].framecount = groupskins;
1070 loadmodel->skinscenes[i].framerate = 1.0f / interval;
1071 loadmodel->skinscenes[i].loop = true;
1073 for (j = 0;j < groupskins;j++)
1076 dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1078 dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1079 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))
1080 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));
1081 datapointer += skinwidth * skinheight;
1085 // check for skins that don't exist in the model, but do exist as external images
1086 // (this was added because yummyluv kept pestering me about support for it)
1087 // TODO: support shaders here?
1088 while ((tempskinframe = R_SkinFrame_LoadExternal(va("%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false)))
1090 // expand the arrays to make room
1091 tempskinscenes = loadmodel->skinscenes;
1092 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1093 memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1094 Mem_Free(tempskinscenes);
1096 tempaliasskins = loadmodel->data_textures;
1097 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1098 memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1099 Mem_Free(tempaliasskins);
1101 // store the info about the new skin
1102 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
1103 strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1104 loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1105 loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1106 loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1107 loadmodel->skinscenes[loadmodel->numskins].loop = true;
1109 //increase skin counts
1110 loadmodel->numskins++;
1113 // fix up the pointers since they are pointing at the old textures array
1114 // FIXME: this is a hack!
1115 for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1116 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1120 surface = loadmodel->data_surfaces;
1121 surface->texture = loadmodel->data_textures;
1122 surface->num_firsttriangle = 0;
1123 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1124 surface->num_firstvertex = 0;
1125 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1127 loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1130 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1132 int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1133 float iskinwidth, iskinheight;
1134 unsigned char *data;
1135 msurface_t *surface;
1137 unsigned char *base, *datapointer;
1138 md2frame_t *pinframe;
1140 md2triangle_t *intri;
1141 unsigned short *inst;
1142 struct md2verthash_s
1144 struct md2verthash_s *next;
1148 *hash, **md2verthash, *md2verthashdata;
1149 skinfile_t *skinfiles;
1151 pinmodel = (md2_t *)buffer;
1152 base = (unsigned char *)buffer;
1154 version = LittleLong (pinmodel->version);
1155 if (version != MD2ALIAS_VERSION)
1156 Host_Error ("%s has wrong version number (%i should be %i)",
1157 loadmodel->name, version, MD2ALIAS_VERSION);
1159 loadmodel->modeldatatypestring = "MD2";
1161 loadmodel->type = mod_alias;
1162 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1163 loadmodel->DrawSky = NULL;
1164 loadmodel->DrawAddWaterPlanes = NULL;
1165 loadmodel->Draw = R_Q1BSP_Draw;
1166 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1167 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1168 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1169 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1170 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1171 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1172 loadmodel->PointSuperContents = NULL;
1174 if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1175 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1176 if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1177 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1178 if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1179 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1180 if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1181 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1183 end = LittleLong(pinmodel->ofs_end);
1184 if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1185 Host_Error ("%s is not a valid model", loadmodel->name);
1186 if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1187 Host_Error ("%s is not a valid model", loadmodel->name);
1188 if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1189 Host_Error ("%s is not a valid model", loadmodel->name);
1190 if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1191 Host_Error ("%s is not a valid model", loadmodel->name);
1192 if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1193 Host_Error ("%s is not a valid model", loadmodel->name);
1195 loadmodel->numskins = LittleLong(pinmodel->num_skins);
1196 numxyz = LittleLong(pinmodel->num_xyz);
1197 numst = LittleLong(pinmodel->num_st);
1198 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1199 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1200 loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1201 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1202 skinwidth = LittleLong(pinmodel->skinwidth);
1203 skinheight = LittleLong(pinmodel->skinheight);
1204 iskinwidth = 1.0f / skinwidth;
1205 iskinheight = 1.0f / skinheight;
1207 loadmodel->num_surfaces = 1;
1208 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1209 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]));
1210 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1211 loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1212 loadmodel->surfacelist[0] = 0;
1213 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1214 loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1215 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1216 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1218 loadmodel->synctype = ST_RAND;
1221 inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1222 skinfiles = Mod_LoadSkinFiles();
1225 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1226 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1227 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1228 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1229 Mod_FreeSkinFiles(skinfiles);
1231 else if (loadmodel->numskins)
1233 // skins found (most likely not a player model)
1234 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1235 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1236 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1237 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1238 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);
1242 // no skins (most likely a player model)
1243 loadmodel->numskins = 1;
1244 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1245 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1246 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1247 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL);
1250 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1251 for (i = 0;i < loadmodel->numskins;i++)
1253 loadmodel->skinscenes[i].firstframe = i;
1254 loadmodel->skinscenes[i].framecount = 1;
1255 loadmodel->skinscenes[i].loop = true;
1256 loadmodel->skinscenes[i].framerate = 10;
1259 // load the triangles and stvert data
1260 inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1261 intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1262 md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1263 md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1264 // swap the triangle list
1265 loadmodel->surfmesh.num_vertices = 0;
1266 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1268 for (j = 0;j < 3;j++)
1270 xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1271 st = (unsigned short) LittleShort (intri[i].index_st[j]);
1274 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1279 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1282 hashindex = (xyz * 256 + st) & 65535;
1283 for (hash = md2verthash[hashindex];hash;hash = hash->next)
1284 if (hash->xyz == xyz && hash->st == st)
1288 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1291 hash->next = md2verthash[hashindex];
1292 md2verthash[hashindex] = hash;
1294 loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1298 vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1299 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));
1300 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1301 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1302 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1305 hash = md2verthashdata + i;
1306 vertremap[i] = hash->xyz;
1307 sts = LittleShort(inst[hash->st*2+0]);
1308 stt = LittleShort(inst[hash->st*2+1]);
1309 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1311 Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1315 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1316 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1319 Mem_Free(md2verthash);
1320 Mem_Free(md2verthashdata);
1322 // generate ushort elements array if possible
1323 if (loadmodel->surfmesh.num_vertices <= 65536)
1325 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1326 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1327 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1331 datapointer = (base + LittleLong(pinmodel->ofs_frames));
1332 for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1337 pinframe = (md2frame_t *)datapointer;
1338 datapointer += sizeof(md2frame_t);
1339 // store the frame scale/translate into the appropriate array
1340 for (j = 0;j < 3;j++)
1342 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1343 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1345 // convert the vertices
1346 v = (trivertx_t *)datapointer;
1347 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1348 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1349 out[k] = v[vertremap[k]];
1350 datapointer += numxyz * sizeof(trivertx_t);
1352 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1353 loadmodel->animscenes[i].firstframe = i;
1354 loadmodel->animscenes[i].framecount = 1;
1355 loadmodel->animscenes[i].framerate = 10;
1356 loadmodel->animscenes[i].loop = true;
1359 Mem_Free(vertremap);
1361 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1362 Mod_Alias_CalculateBoundingBox();
1363 Mod_Alias_MorphMesh_CompileFrames();
1365 surface = loadmodel->data_surfaces;
1366 surface->texture = loadmodel->data_textures;
1367 surface->num_firsttriangle = 0;
1368 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1369 surface->num_firstvertex = 0;
1370 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1372 loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1375 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1377 int i, j, k, version, meshvertices, meshtriangles;
1378 unsigned char *data;
1379 msurface_t *surface;
1380 md3modelheader_t *pinmodel;
1381 md3frameinfo_t *pinframe;
1384 skinfile_t *skinfiles;
1386 pinmodel = (md3modelheader_t *)buffer;
1388 if (memcmp(pinmodel->identifier, "IDP3", 4))
1389 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1390 version = LittleLong (pinmodel->version);
1391 if (version != MD3VERSION)
1392 Host_Error ("%s has wrong version number (%i should be %i)",
1393 loadmodel->name, version, MD3VERSION);
1395 skinfiles = Mod_LoadSkinFiles();
1396 if (loadmodel->numskins < 1)
1397 loadmodel->numskins = 1;
1399 loadmodel->modeldatatypestring = "MD3";
1401 loadmodel->type = mod_alias;
1402 loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1403 loadmodel->DrawSky = NULL;
1404 loadmodel->DrawAddWaterPlanes = NULL;
1405 loadmodel->Draw = R_Q1BSP_Draw;
1406 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1407 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1408 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1409 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1410 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1411 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1412 loadmodel->PointSuperContents = NULL;
1413 loadmodel->synctype = ST_RAND;
1414 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1415 i = LittleLong (pinmodel->flags);
1416 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1418 // set up some global info about the model
1419 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1420 loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1422 // make skinscenes for the skins (no groups)
1423 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1424 for (i = 0;i < loadmodel->numskins;i++)
1426 loadmodel->skinscenes[i].firstframe = i;
1427 loadmodel->skinscenes[i].framecount = 1;
1428 loadmodel->skinscenes[i].loop = true;
1429 loadmodel->skinscenes[i].framerate = 10;
1433 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1434 for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1436 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1437 loadmodel->animscenes[i].firstframe = i;
1438 loadmodel->animscenes[i].framecount = 1;
1439 loadmodel->animscenes[i].framerate = 10;
1440 loadmodel->animscenes[i].loop = true;
1444 loadmodel->num_tagframes = loadmodel->numframes;
1445 loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1446 loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1447 for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1449 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1450 for (j = 0;j < 9;j++)
1451 loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1452 for (j = 0;j < 3;j++)
1453 loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1454 //Con_Printf("model \"%s\" frame #%i tag #%i \"%s\"\n", loadmodel->name, i / loadmodel->num_tags, i % loadmodel->num_tags, loadmodel->data_tags[i].name);
1460 for (i = 0, pinmesh = (md3mesh_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_meshes));i < loadmodel->num_surfaces;i++, pinmesh = (md3mesh_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_end)))
1462 if (memcmp(pinmesh->identifier, "IDP3", 4))
1463 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1464 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1465 Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1466 meshvertices += LittleLong(pinmesh->num_vertices);
1467 meshtriangles += LittleLong(pinmesh->num_triangles);
1470 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1471 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1472 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1473 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));
1474 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1475 loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1476 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1477 loadmodel->surfmesh.num_vertices = meshvertices;
1478 loadmodel->surfmesh.num_triangles = meshtriangles;
1479 loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1480 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1481 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1482 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1483 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1484 loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1485 if (meshvertices <= 65536)
1487 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1488 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1489 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1494 for (i = 0, pinmesh = (md3mesh_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_meshes));i < loadmodel->num_surfaces;i++, pinmesh = (md3mesh_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_end)))
1496 if (memcmp(pinmesh->identifier, "IDP3", 4))
1497 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1498 loadmodel->surfacelist[i] = i;
1499 surface = loadmodel->data_surfaces + i;
1500 surface->texture = loadmodel->data_textures + i;
1501 surface->num_firsttriangle = meshtriangles;
1502 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1503 surface->num_firstvertex = meshvertices;
1504 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1505 meshvertices += surface->num_vertices;
1506 meshtriangles += surface->num_triangles;
1508 for (j = 0;j < surface->num_triangles * 3;j++)
1509 loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1510 for (j = 0;j < surface->num_vertices;j++)
1512 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1513 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1515 for (j = 0;j < loadmodel->numframes;j++)
1517 const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1518 md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1519 for (k = 0;k < surface->num_vertices;k++, in++, out++)
1521 out->origin[0] = LittleShort(in->origin[0]);
1522 out->origin[1] = LittleShort(in->origin[1]);
1523 out->origin[2] = LittleShort(in->origin[2]);
1524 out->pitch = in->pitch;
1529 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1531 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1533 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1534 Mod_Alias_MorphMesh_CompileFrames();
1535 Mod_Alias_CalculateBoundingBox();
1536 Mod_FreeSkinFiles(skinfiles);
1538 loadmodel->surfmesh.isanimated = loadmodel->numframes > 1
1539 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
1542 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1544 zymtype1header_t *pinmodel, *pheader;
1545 unsigned char *pbase;
1546 int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1547 float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose;
1548 zymvertex_t *verts, *vertdata;
1552 skinfile_t *skinfiles;
1553 unsigned char *data;
1554 msurface_t *surface;
1556 pinmodel = (zymtype1header_t *)buffer;
1557 pbase = (unsigned char *)buffer;
1558 if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1559 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1560 if (BigLong(pinmodel->type) != 1)
1561 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1563 loadmodel->modeldatatypestring = "ZYM";
1565 loadmodel->type = mod_alias;
1566 loadmodel->synctype = ST_RAND;
1570 pheader->type = BigLong(pinmodel->type);
1571 pheader->filesize = BigLong(pinmodel->filesize);
1572 pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1573 pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1574 pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1575 pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1576 pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1577 pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1578 pheader->radius = BigFloat(pinmodel->radius);
1579 pheader->numverts = BigLong(pinmodel->numverts);
1580 pheader->numtris = BigLong(pinmodel->numtris);
1581 pheader->numshaders = BigLong(pinmodel->numshaders);
1582 pheader->numbones = BigLong(pinmodel->numbones);
1583 pheader->numscenes = BigLong(pinmodel->numscenes);
1584 pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1585 pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1586 pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1587 pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1588 pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1589 pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1590 pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1591 pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1592 pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1593 pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1594 pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1595 pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1596 pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1597 pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1598 pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1599 pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1600 pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1601 pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1603 if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1605 Con_Printf("%s has no geometry\n", loadmodel->name);
1608 if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1610 Con_Printf("%s has no animations\n", loadmodel->name);
1614 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1615 loadmodel->DrawSky = NULL;
1616 loadmodel->DrawAddWaterPlanes = NULL;
1617 loadmodel->Draw = R_Q1BSP_Draw;
1618 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1619 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1620 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1621 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1622 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1623 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1624 loadmodel->PointSuperContents = NULL;
1626 loadmodel->numframes = pheader->numscenes;
1627 loadmodel->num_surfaces = pheader->numshaders;
1629 skinfiles = Mod_LoadSkinFiles();
1630 if (loadmodel->numskins < 1)
1631 loadmodel->numskins = 1;
1633 // make skinscenes for the skins (no groups)
1634 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1635 for (i = 0;i < loadmodel->numskins;i++)
1637 loadmodel->skinscenes[i].firstframe = i;
1638 loadmodel->skinscenes[i].framecount = 1;
1639 loadmodel->skinscenes[i].loop = true;
1640 loadmodel->skinscenes[i].framerate = 10;
1644 modelradius = pheader->radius;
1645 for (i = 0;i < 3;i++)
1647 loadmodel->normalmins[i] = pheader->mins[i];
1648 loadmodel->normalmaxs[i] = pheader->maxs[i];
1649 loadmodel->rotatedmins[i] = -modelradius;
1650 loadmodel->rotatedmaxs[i] = modelradius;
1652 corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1653 corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1654 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1655 if (loadmodel->yawmaxs[0] > modelradius)
1656 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1657 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1658 loadmodel->yawmins[2] = loadmodel->normalmins[2];
1659 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1660 loadmodel->radius = modelradius;
1661 loadmodel->radius2 = modelradius * modelradius;
1663 // go through the lumps, swapping things
1665 //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1666 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1667 scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1668 numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1669 for (i = 0;i < pheader->numscenes;i++)
1671 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1672 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1673 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1674 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1675 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1676 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1677 Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1678 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1679 Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1680 if (loadmodel->animscenes[i].framerate < 0)
1681 Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1685 //zymlump_t lump_bones; // zymbone_t bone[numbones];
1686 loadmodel->num_bones = pheader->numbones;
1687 loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, pheader->numbones * sizeof(aliasbone_t));
1688 bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1689 for (i = 0;i < pheader->numbones;i++)
1691 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1692 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1693 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1694 if (loadmodel->data_bones[i].parent >= i)
1695 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1698 //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1699 vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1700 bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1701 for (i = 0;i < pheader->numverts;i++)
1703 vertbonecounts[i] = BigLong(bonecount[i]);
1704 if (vertbonecounts[i] != 1)
1705 Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1708 loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]);
1710 meshvertices = pheader->numverts;
1711 meshtriangles = pheader->numtris;
1713 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1714 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1715 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1716 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]));
1717 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1718 loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1719 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1720 loadmodel->surfmesh.num_vertices = meshvertices;
1721 loadmodel->surfmesh.num_triangles = meshtriangles;
1722 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1723 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1724 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1725 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1726 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1727 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1728 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1729 loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += meshvertices * sizeof(int[4]);
1730 loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += meshvertices * sizeof(float[4]);
1731 loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]);
1732 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1733 if (loadmodel->surfmesh.num_vertices <= 65536)
1735 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1736 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1737 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1740 //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1741 poses = (float *) (pheader->lump_poses.start + pbase);
1742 for (i = 0;i < pheader->lump_poses.length / 4;i++)
1743 loadmodel->data_poses[i] = BigFloat(poses[i]);
1745 //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
1746 verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
1747 vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
1748 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
1749 // (converting from weight-blending skeletal animation to
1750 // deformation-based skeletal animation)
1751 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
1752 for (i = 0;i < loadmodel->num_bones;i++)
1754 const float *m = loadmodel->data_poses + i * 12;
1755 if (loadmodel->data_bones[i].parent >= 0)
1756 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
1758 for (k = 0;k < 12;k++)
1759 bonepose[12*i+k] = m[k];
1761 for (j = 0;j < pheader->numverts;j++)
1763 // this format really should have had a per vertexweight weight value...
1764 // but since it does not, the weighting is completely ignored and
1765 // only one weight is allowed per vertex
1766 int boneindex = BigLong(vertdata[j].bonenum);
1767 const float *m = bonepose + 12 * boneindex;
1768 float relativeorigin[3];
1769 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
1770 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
1771 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
1772 // transform the vertex bone weight into the base mesh
1773 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
1774 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
1775 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
1776 // store the weight as the primary weight on this vertex
1777 loadmodel->surfmesh.data_vertexweightindex4i[j*4+0] = boneindex;
1778 loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+0] = 1;
1781 // normals and tangents are calculated after elements are loaded
1783 //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
1784 outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
1785 intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
1786 for (i = 0;i < pheader->numverts;i++)
1788 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
1789 // flip T coordinate for OpenGL
1790 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
1793 //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
1794 //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
1795 //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
1797 //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
1798 //zymlump_t lump_render; // int renderlist[rendersize]; // sorted by shader with run lengths (int count), shaders are sequentially used, each run can be used with glDrawElements (each triangle is 3 int indices)
1799 // byteswap, validate, and swap winding order of tris
1800 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
1801 if (pheader->lump_render.length != count)
1802 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
1803 renderlist = (int *) (pheader->lump_render.start + pbase);
1804 renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
1806 for (i = 0;i < loadmodel->num_surfaces;i++)
1808 int firstvertex, lastvertex;
1809 if (renderlist >= renderlistend)
1810 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
1811 count = BigLong(*renderlist);renderlist++;
1812 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
1813 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
1815 loadmodel->surfacelist[i] = i;
1816 surface = loadmodel->data_surfaces + i;
1817 surface->texture = loadmodel->data_textures + i;
1818 surface->num_firsttriangle = meshtriangles;
1819 surface->num_triangles = count;
1820 meshtriangles += surface->num_triangles;
1822 // load the elements
1823 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1824 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
1826 outelements[j*3+2] = BigLong(renderlist[0]);
1827 outelements[j*3+1] = BigLong(renderlist[1]);
1828 outelements[j*3+0] = BigLong(renderlist[2]);
1830 // validate the elements and find the used vertex range
1831 firstvertex = meshvertices;
1833 for (j = 0;j < surface->num_triangles * 3;j++)
1835 if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
1836 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
1837 firstvertex = min(firstvertex, outelements[j]);
1838 lastvertex = max(lastvertex, outelements[j]);
1840 surface->num_firstvertex = firstvertex;
1841 surface->num_vertices = lastvertex + 1 - firstvertex;
1843 // since zym models do not have named sections, reuse their shader
1844 // name as the section name
1845 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
1846 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
1848 Mod_FreeSkinFiles(skinfiles);
1849 Mem_Free(vertbonecounts);
1852 // compute all the mesh information that was not loaded from the file
1853 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
1854 Mod_BuildBaseBonePoses();
1855 Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true);
1856 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, true);
1857 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1859 loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1862 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1864 dpmheader_t *pheader;
1868 unsigned char *pbase;
1869 int i, j, k, meshvertices, meshtriangles;
1870 skinfile_t *skinfiles;
1871 unsigned char *data;
1874 pheader = (dpmheader_t *)buffer;
1875 pbase = (unsigned char *)buffer;
1876 if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
1877 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
1878 if (BigLong(pheader->type) != 2)
1879 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1881 loadmodel->modeldatatypestring = "DPM";
1883 loadmodel->type = mod_alias;
1884 loadmodel->synctype = ST_RAND;
1887 pheader->type = BigLong(pheader->type);
1888 pheader->filesize = BigLong(pheader->filesize);
1889 pheader->mins[0] = BigFloat(pheader->mins[0]);
1890 pheader->mins[1] = BigFloat(pheader->mins[1]);
1891 pheader->mins[2] = BigFloat(pheader->mins[2]);
1892 pheader->maxs[0] = BigFloat(pheader->maxs[0]);
1893 pheader->maxs[1] = BigFloat(pheader->maxs[1]);
1894 pheader->maxs[2] = BigFloat(pheader->maxs[2]);
1895 pheader->yawradius = BigFloat(pheader->yawradius);
1896 pheader->allradius = BigFloat(pheader->allradius);
1897 pheader->num_bones = BigLong(pheader->num_bones);
1898 pheader->num_meshs = BigLong(pheader->num_meshs);
1899 pheader->num_frames = BigLong(pheader->num_frames);
1900 pheader->ofs_bones = BigLong(pheader->ofs_bones);
1901 pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
1902 pheader->ofs_frames = BigLong(pheader->ofs_frames);
1904 if (pheader->num_bones < 1 || pheader->num_meshs < 1)
1906 Con_Printf("%s has no geometry\n", loadmodel->name);
1909 if (pheader->num_frames < 1)
1911 Con_Printf("%s has no frames\n", loadmodel->name);
1915 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1916 loadmodel->DrawSky = NULL;
1917 loadmodel->DrawAddWaterPlanes = NULL;
1918 loadmodel->Draw = R_Q1BSP_Draw;
1919 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1920 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1921 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1922 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1923 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1924 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1925 loadmodel->PointSuperContents = NULL;
1928 for (i = 0;i < 3;i++)
1930 loadmodel->normalmins[i] = pheader->mins[i];
1931 loadmodel->normalmaxs[i] = pheader->maxs[i];
1932 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
1933 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
1934 loadmodel->rotatedmins[i] = -pheader->allradius;
1935 loadmodel->rotatedmaxs[i] = pheader->allradius;
1937 loadmodel->radius = pheader->allradius;
1938 loadmodel->radius2 = pheader->allradius * pheader->allradius;
1940 // load external .skin files if present
1941 skinfiles = Mod_LoadSkinFiles();
1942 if (loadmodel->numskins < 1)
1943 loadmodel->numskins = 1;
1948 // gather combined statistics from the meshes
1949 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
1950 for (i = 0;i < (int)pheader->num_meshs;i++)
1952 int numverts = BigLong(dpmmesh->num_verts);
1953 meshvertices += numverts;
1954 meshtriangles += BigLong(dpmmesh->num_tris);
1958 loadmodel->numframes = pheader->num_frames;
1959 loadmodel->num_bones = pheader->num_bones;
1960 loadmodel->num_poses = loadmodel->num_bones * loadmodel->numframes;
1961 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
1962 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1963 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1964 // do most allocations as one merged chunk
1965 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));
1966 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1967 loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1968 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1969 loadmodel->surfmesh.num_vertices = meshvertices;
1970 loadmodel->surfmesh.num_triangles = meshtriangles;
1971 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1972 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1973 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1974 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1975 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1976 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1977 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1978 loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += meshvertices * sizeof(int[4]);
1979 loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += meshvertices * sizeof(float[4]);
1980 loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]);
1981 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1982 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
1983 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
1984 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1985 if (meshvertices <= 65536)
1987 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1988 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1989 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1992 for (i = 0;i < loadmodel->numskins;i++)
1994 loadmodel->skinscenes[i].firstframe = i;
1995 loadmodel->skinscenes[i].framecount = 1;
1996 loadmodel->skinscenes[i].loop = true;
1997 loadmodel->skinscenes[i].framerate = 10;
2000 // load the bone info
2001 bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2002 for (i = 0;i < loadmodel->num_bones;i++)
2004 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2005 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2006 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2007 if (loadmodel->data_bones[i].parent >= i)
2008 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2012 frame = (dpmframe_t *) (pbase + pheader->ofs_frames);
2013 for (i = 0;i < loadmodel->numframes;i++)
2016 memcpy(loadmodel->animscenes[i].name, frame->name, sizeof(frame->name));
2017 loadmodel->animscenes[i].firstframe = i;
2018 loadmodel->animscenes[i].framecount = 1;
2019 loadmodel->animscenes[i].loop = true;
2020 loadmodel->animscenes[i].framerate = 10;
2021 // load the bone poses for this frame
2022 poses = (float *) (pbase + BigLong(frame->ofs_bonepositions));
2023 for (j = 0;j < loadmodel->num_bones*12;j++)
2024 loadmodel->data_poses[i * loadmodel->num_bones*12 + j] = BigFloat(poses[j]);
2025 // stuff not processed here: mins, maxs, yawradius, allradius
2029 // load the meshes now
2030 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2033 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2034 // (converting from weight-blending skeletal animation to
2035 // deformation-based skeletal animation)
2036 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2037 for (i = 0;i < loadmodel->num_bones;i++)
2039 const float *m = loadmodel->data_poses + i * 12;
2040 if (loadmodel->data_bones[i].parent >= 0)
2041 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2043 for (k = 0;k < 12;k++)
2044 bonepose[12*i+k] = m[k];
2046 for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2048 const int *inelements;
2050 const float *intexcoord;
2051 msurface_t *surface;
2053 loadmodel->surfacelist[i] = i;
2054 surface = loadmodel->data_surfaces + i;
2055 surface->texture = loadmodel->data_textures + i;
2056 surface->num_firsttriangle = meshtriangles;
2057 surface->num_triangles = BigLong(dpmmesh->num_tris);
2058 surface->num_firstvertex = meshvertices;
2059 surface->num_vertices = BigLong(dpmmesh->num_verts);
2060 meshvertices += surface->num_vertices;
2061 meshtriangles += surface->num_triangles;
2063 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2064 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2065 for (j = 0;j < surface->num_triangles;j++)
2067 // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2068 outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2069 outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2070 outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2075 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2076 for (j = 0;j < surface->num_vertices*2;j++)
2077 loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2079 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2080 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2084 int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2085 data += sizeof(dpmvertex_t);
2086 for (k = 0;k < numweights;k++)
2088 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2089 int boneindex = BigLong(vert->bonenum);
2090 const float *m = bonepose + 12 * boneindex;
2091 float influence = BigFloat(vert->influence);
2092 float relativeorigin[3], relativenormal[3];
2093 relativeorigin[0] = BigFloat(vert->origin[0]);
2094 relativeorigin[1] = BigFloat(vert->origin[1]);
2095 relativeorigin[2] = BigFloat(vert->origin[2]);
2096 relativenormal[0] = BigFloat(vert->normal[0]);
2097 relativenormal[1] = BigFloat(vert->normal[1]);
2098 relativenormal[2] = BigFloat(vert->normal[2]);
2099 // blend the vertex bone weights into the base mesh
2100 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2101 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2102 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2103 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2104 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2105 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2108 // store the first (and often only) weight
2109 loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+0] = influence;
2110 loadmodel->surfmesh.data_vertexweightindex4i[j*4+0] = boneindex;
2114 // sort the new weight into this vertex's weight table
2115 // (which only accepts up to 4 bones per vertex)
2116 for (l = 0;l < 4;l++)
2118 if (loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] < influence)
2120 // move weaker influence weights out of the way first
2122 for (l2 = 3;l2 > l;l2--)
2124 loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l2] = loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l2-1];
2125 loadmodel->surfmesh.data_vertexweightindex4i[j*4+l2] = loadmodel->surfmesh.data_vertexweightindex4i[j*4+l2-1];
2127 // store the new weight
2128 loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] = influence;
2129 loadmodel->surfmesh.data_vertexweightindex4i[j*4+l] = boneindex;
2134 data += sizeof(dpmbonevert_t);
2137 for (l = 0;l < 4;l++)
2138 sum += loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l];
2139 if (sum && fabs(sum - 1) > (1.0f / 256.0f))
2141 float f = 1.0f / sum;
2142 for (l = 0;l < 4;l++)
2143 loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] *= f;
2147 // since dpm models do not have named sections, reuse their shader name as the section name
2148 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2150 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2153 Mod_FreeSkinFiles(skinfiles);
2155 // compute all the mesh information that was not loaded from the file
2156 Mod_BuildBaseBonePoses();
2157 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, true);
2158 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2160 loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
2163 // no idea why PSK/PSA files contain weird quaternions but they do...
2164 #define PSKQUATNEGATIONS
2165 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2167 int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2168 int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2169 fs_offset_t filesize;
2174 pskboneinfo_t *bones;
2175 pskrawweights_t *rawweights;
2176 pskboneinfo_t *animbones;
2177 pskaniminfo_t *anims;
2178 pskanimkeys_t *animkeys;
2179 void *animfilebuffer, *animbuffer, *animbufferend;
2180 unsigned char *data;
2182 skinfile_t *skinfiles;
2183 char animname[MAX_QPATH];
2186 pchunk = (pskchunk_t *)buffer;
2187 if (strcmp(pchunk->id, "ACTRHEAD"))
2188 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2190 loadmodel->modeldatatypestring = "PSK";
2192 loadmodel->type = mod_alias;
2193 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2194 loadmodel->DrawSky = NULL;
2195 loadmodel->DrawAddWaterPlanes = NULL;
2196 loadmodel->Draw = R_Q1BSP_Draw;
2197 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2198 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2199 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2200 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2201 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2202 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2203 loadmodel->PointSuperContents = NULL;
2204 loadmodel->synctype = ST_RAND;
2206 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2207 strlcat(animname, ".psa", sizeof(animname));
2208 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2209 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2210 if (animbuffer == NULL)
2211 Host_Error("%s: can't find .psa file (%s)", loadmodel->name, animname);
2230 while (buffer < bufferend)
2232 pchunk = (pskchunk_t *)buffer;
2233 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2234 version = LittleLong(pchunk->version);
2235 recordsize = LittleLong(pchunk->recordsize);
2236 numrecords = LittleLong(pchunk->numrecords);
2237 if (developer.integer >= 100)
2238 Con_Printf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2239 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2240 Con_Printf ("%s: chunk %s has unknown version %x (0x1e83b9, 0x1e9179, 0x2e, 0x12f2bc, 0x12f2f0 are currently supported), trying to load anyway!\n", loadmodel->name, pchunk->id, version);
2241 if (!strcmp(pchunk->id, "ACTRHEAD"))
2245 else if (!strcmp(pchunk->id, "PNTS0000"))
2248 if (recordsize != sizeof(*p))
2249 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2250 // byteswap in place and keep the pointer
2251 numpnts = numrecords;
2252 pnts = (pskpnts_t *)buffer;
2253 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2255 p->origin[0] = LittleFloat(p->origin[0]);
2256 p->origin[1] = LittleFloat(p->origin[1]);
2257 p->origin[2] = LittleFloat(p->origin[2]);
2261 else if (!strcmp(pchunk->id, "VTXW0000"))
2264 if (recordsize != sizeof(*p))
2265 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2266 // byteswap in place and keep the pointer
2267 numvtxw = numrecords;
2268 vtxw = (pskvtxw_t *)buffer;
2269 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2271 p->pntsindex = LittleShort(p->pntsindex);
2272 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2273 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2274 if (p->pntsindex >= numpnts)
2276 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2282 else if (!strcmp(pchunk->id, "FACE0000"))
2285 if (recordsize != sizeof(*p))
2286 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2287 // byteswap in place and keep the pointer
2288 numfaces = numrecords;
2289 faces = (pskface_t *)buffer;
2290 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2292 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2293 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2294 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2295 p->group = LittleLong(p->group);
2296 if (p->vtxwindex[0] >= numvtxw)
2298 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2299 p->vtxwindex[0] = 0;
2301 if (p->vtxwindex[1] >= numvtxw)
2303 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2304 p->vtxwindex[1] = 0;
2306 if (p->vtxwindex[2] >= numvtxw)
2308 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2309 p->vtxwindex[2] = 0;
2314 else if (!strcmp(pchunk->id, "MATT0000"))
2317 if (recordsize != sizeof(*p))
2318 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2319 // byteswap in place and keep the pointer
2320 nummatts = numrecords;
2321 matts = (pskmatt_t *)buffer;
2322 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2328 else if (!strcmp(pchunk->id, "REFSKELT"))
2331 if (recordsize != sizeof(*p))
2332 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2333 // byteswap in place and keep the pointer
2334 numbones = numrecords;
2335 bones = (pskboneinfo_t *)buffer;
2336 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2338 p->numchildren = LittleLong(p->numchildren);
2339 p->parent = LittleLong(p->parent);
2340 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2341 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2342 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2343 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2344 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2345 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2346 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2347 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2348 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2349 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2350 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2351 #ifdef PSKQUATNEGATIONS
2354 p->basepose.quat[0] *= -1;
2355 p->basepose.quat[1] *= -1;
2356 p->basepose.quat[2] *= -1;
2360 p->basepose.quat[0] *= 1;
2361 p->basepose.quat[1] *= -1;
2362 p->basepose.quat[2] *= 1;
2365 if (p->parent < 0 || p->parent >= numbones)
2367 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2373 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2376 if (recordsize != sizeof(*p))
2377 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2378 // byteswap in place and keep the pointer
2379 numrawweights = numrecords;
2380 rawweights = (pskrawweights_t *)buffer;
2381 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2383 p->weight = LittleFloat(p->weight);
2384 p->pntsindex = LittleLong(p->pntsindex);
2385 p->boneindex = LittleLong(p->boneindex);
2386 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2388 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2391 if (p->boneindex < 0 || p->boneindex >= numbones)
2393 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2401 while (animbuffer < animbufferend)
2403 pchunk = (pskchunk_t *)animbuffer;
2404 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2405 version = LittleLong(pchunk->version);
2406 recordsize = LittleLong(pchunk->recordsize);
2407 numrecords = LittleLong(pchunk->numrecords);
2408 if (developer.integer >= 100)
2409 Con_Printf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2410 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2411 Con_Printf ("%s: chunk %s has unknown version %x (0x1e83b9, 0x1e9179, 0x2e, 0x12f2bc, 0x12f2f0 are currently supported), trying to load anyway!\n", animname, pchunk->id, version);
2412 if (!strcmp(pchunk->id, "ANIMHEAD"))
2416 else if (!strcmp(pchunk->id, "BONENAMES"))
2419 if (recordsize != sizeof(*p))
2420 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2421 // byteswap in place and keep the pointer
2422 numanimbones = numrecords;
2423 animbones = (pskboneinfo_t *)animbuffer;
2424 // NOTE: supposedly psa does not need to match the psk model, the
2425 // bones missing from the psa would simply use their base
2426 // positions from the psk, but this is hard for me to implement
2427 // and people can easily make animations that match.
2428 if (numanimbones != numbones)
2429 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2430 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2432 p->numchildren = LittleLong(p->numchildren);
2433 p->parent = LittleLong(p->parent);
2434 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2435 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2436 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2437 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2438 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2439 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2440 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2441 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2442 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2443 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2444 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2445 #ifdef PSKQUATNEGATIONS
2448 p->basepose.quat[0] *= -1;
2449 p->basepose.quat[1] *= -1;
2450 p->basepose.quat[2] *= -1;
2454 p->basepose.quat[0] *= 1;
2455 p->basepose.quat[1] *= -1;
2456 p->basepose.quat[2] *= 1;
2459 if (p->parent < 0 || p->parent >= numanimbones)
2461 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2464 // check that bones are the same as in the base
2465 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2466 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2470 else if (!strcmp(pchunk->id, "ANIMINFO"))
2473 if (recordsize != sizeof(*p))
2474 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2475 // byteswap in place and keep the pointer
2476 numanims = numrecords;
2477 anims = (pskaniminfo_t *)animbuffer;
2478 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2480 p->numbones = LittleLong(p->numbones);
2481 p->playtime = LittleFloat(p->playtime);
2482 p->fps = LittleFloat(p->fps);
2483 p->firstframe = LittleLong(p->firstframe);
2484 p->numframes = LittleLong(p->numframes);
2485 if (p->numbones != numbones)
2486 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2490 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2493 if (recordsize != sizeof(*p))
2494 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2495 numanimkeys = numrecords;
2496 animkeys = (pskanimkeys_t *)animbuffer;
2497 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2499 p->origin[0] = LittleFloat(p->origin[0]);
2500 p->origin[1] = LittleFloat(p->origin[1]);
2501 p->origin[2] = LittleFloat(p->origin[2]);
2502 p->quat[0] = LittleFloat(p->quat[0]);
2503 p->quat[1] = LittleFloat(p->quat[1]);
2504 p->quat[2] = LittleFloat(p->quat[2]);
2505 p->quat[3] = LittleFloat(p->quat[3]);
2506 p->frametime = LittleFloat(p->frametime);
2507 #ifdef PSKQUATNEGATIONS
2508 if (index % numbones)
2523 // TODO: allocate bonepose stuff
2526 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2529 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights || !numanims || !anims || !numanimkeys || !animkeys)
2530 Host_Error("%s: missing required chunks", loadmodel->name);
2532 loadmodel->numframes = 0;
2533 for (index = 0;index < numanims;index++)
2534 loadmodel->numframes += anims[index].numframes;
2536 if (numanimkeys != numbones * loadmodel->numframes)
2537 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2539 meshvertices = numvtxw;
2540 meshtriangles = numfaces;
2542 // load external .skin files if present
2543 skinfiles = Mod_LoadSkinFiles();
2544 if (loadmodel->numskins < 1)
2545 loadmodel->numskins = 1;
2546 loadmodel->num_bones = numbones;
2547 loadmodel->num_poses = loadmodel->num_bones * loadmodel->numframes;
2548 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2549 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2550 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2551 loadmodel->surfmesh.num_vertices = meshvertices;
2552 loadmodel->surfmesh.num_triangles = meshtriangles;
2553 // do most allocations as one merged chunk
2554 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);
2555 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2556 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2557 loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2558 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2559 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2560 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2561 loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2562 loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2563 loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2564 loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2565 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2566 loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += loadmodel->surfmesh.num_vertices * sizeof(int[4]);
2567 loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
2568 //loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]);
2569 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2570 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2571 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2572 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2573 if (loadmodel->surfmesh.num_vertices <= 65536)
2575 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2576 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2577 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2579 loadmodel->data_poses = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->num_poses * sizeof(float[12]));
2581 for (i = 0;i < loadmodel->numskins;i++)
2583 loadmodel->skinscenes[i].firstframe = i;
2584 loadmodel->skinscenes[i].framecount = 1;
2585 loadmodel->skinscenes[i].loop = true;
2586 loadmodel->skinscenes[i].framerate = 10;
2590 for (index = 0, i = 0;index < nummatts;index++)
2592 // since psk models do not have named sections, reuse their shader name as the section name
2593 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2594 loadmodel->surfacelist[index] = index;
2595 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2596 loadmodel->data_surfaces[index].num_firstvertex = 0;
2597 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2600 // copy over the vertex locations and texcoords
2601 for (index = 0;index < numvtxw;index++)
2603 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2604 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2605 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2606 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2607 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
2610 // loading the faces is complicated because we need to sort them into surfaces by mattindex
2611 for (index = 0;index < numfaces;index++)
2612 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
2613 for (index = 0, i = 0;index < nummatts;index++)
2615 loadmodel->data_surfaces[index].num_firsttriangle = i;
2616 i += loadmodel->data_surfaces[index].num_triangles;
2617 loadmodel->data_surfaces[index].num_triangles = 0;
2619 for (index = 0;index < numfaces;index++)
2621 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
2622 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
2623 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
2624 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
2627 // copy over the bones
2628 for (index = 0;index < numbones;index++)
2630 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
2631 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
2632 if (loadmodel->data_bones[index].parent >= index)
2633 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
2636 // sort the psk point weights into the vertex weight tables
2637 // (which only accept up to 4 bones per vertex)
2638 for (index = 0;index < numvtxw;index++)
2642 for (j = 0;j < numrawweights;j++)
2644 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
2646 int boneindex = rawweights[j].boneindex;
2647 float influence = rawweights[j].weight;
2648 for (l = 0;l < 4;l++)
2650 if (loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] < influence)
2652 // move lower influence weights out of the way first
2654 for (l2 = 3;l2 > l;l2--)
2656 loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l2] = loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l2-1];
2657 loadmodel->surfmesh.data_vertexweightindex4i[index*4+l2] = loadmodel->surfmesh.data_vertexweightindex4i[index*4+l2-1];
2659 // store the new weight
2660 loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] = influence;
2661 loadmodel->surfmesh.data_vertexweightindex4i[index*4+l] = boneindex;
2668 for (l = 0;l < 4;l++)
2669 sum += loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l];
2670 if (sum && fabs(sum - 1) > (1.0f / 256.0f))
2672 float f = 1.0f / sum;
2673 for (l = 0;l < 4;l++)
2674 loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] *= f;
2678 // set up the animscenes based on the anims
2679 for (index = 0, i = 0;index < numanims;index++)
2681 for (j = 0;j < anims[index].numframes;j++, i++)
2683 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
2684 loadmodel->animscenes[i].firstframe = i;
2685 loadmodel->animscenes[i].framecount = 1;
2686 loadmodel->animscenes[i].loop = true;
2687 loadmodel->animscenes[i].framerate = 10;
2691 // load the poses from the animkeys
2692 for (index = 0;index < numanimkeys;index++)
2694 pskanimkeys_t *k = animkeys + index;
2696 Matrix4x4_FromOriginQuat(&matrix, k->origin[0], k->origin[1], k->origin[2], k->quat[0], k->quat[1], k->quat[2], k->quat[3]);
2697 Matrix4x4_ToArray12FloatD3D(&matrix, loadmodel->data_poses + index*12);
2699 Mod_FreeSkinFiles(skinfiles);
2700 Mem_Free(animfilebuffer);
2702 // compute all the mesh information that was not loaded from the file
2703 // TODO: honor smoothing groups somehow?
2704 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2705 Mod_BuildBaseBonePoses();
2706 Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true);
2707 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, true);
2708 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2709 Mod_Alias_CalculateBoundingBox();
2711 loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;