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.
24 #include "mod_skeletal_animatevertices_generic.h"
26 #include "mod_skeletal_animatevertices_sse.h"
30 static qbool r_skeletal_use_sse_defined = false;
31 cvar_t r_skeletal_use_sse = {CF_CLIENT, "r_skeletal_use_sse", "1", "use SSE for skeletal model animation"};
33 cvar_t r_skeletal_debugbone = {CF_CLIENT, "r_skeletal_debugbone", "-1", "development cvar for testing skeletal model code"};
34 cvar_t r_skeletal_debugbonecomponent = {CF_CLIENT, "r_skeletal_debugbonecomponent", "3", "development cvar for testing skeletal model code"};
35 cvar_t r_skeletal_debugbonevalue = {CF_CLIENT, "r_skeletal_debugbonevalue", "100", "development cvar for testing skeletal model code"};
36 cvar_t r_skeletal_debugtranslatex = {CF_CLIENT, "r_skeletal_debugtranslatex", "1", "development cvar for testing skeletal model code"};
37 cvar_t r_skeletal_debugtranslatey = {CF_CLIENT, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"};
38 cvar_t r_skeletal_debugtranslatez = {CF_CLIENT, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"};
39 cvar_t mod_alias_supporttagscale = {CF_CLIENT | CF_SERVER, "mod_alias_supporttagscale", "1", "support scaling factors in bone/tag attachment matrices as supported by MD3"};
40 cvar_t mod_alias_force_animated = {CF_CLIENT | CF_SERVER, "mod_alias_force_animated", "", "if set to an non-empty string, overrides the is-animated flag of any alias models (for benchmarking)"};
42 float mod_md3_sin[320];
44 static size_t Mod_Skeletal_AnimateVertices_maxbonepose = 0;
45 static void *Mod_Skeletal_AnimateVertices_bonepose = NULL;
46 void Mod_Skeletal_FreeBuffers(void)
48 if(Mod_Skeletal_AnimateVertices_bonepose)
49 Mem_Free(Mod_Skeletal_AnimateVertices_bonepose);
50 Mod_Skeletal_AnimateVertices_maxbonepose = 0;
51 Mod_Skeletal_AnimateVertices_bonepose = NULL;
53 void *Mod_Skeletal_AnimateVertices_AllocBuffers(size_t nbytes)
55 if(Mod_Skeletal_AnimateVertices_maxbonepose < nbytes)
57 if(Mod_Skeletal_AnimateVertices_bonepose)
58 Mem_Free(Mod_Skeletal_AnimateVertices_bonepose);
59 Mod_Skeletal_AnimateVertices_bonepose = Z_Malloc(nbytes);
60 Mod_Skeletal_AnimateVertices_maxbonepose = nbytes;
62 return Mod_Skeletal_AnimateVertices_bonepose;
65 void Mod_Skeletal_BuildTransforms(const model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT bonepose, float * RESTRICT boneposerelative)
71 bonepose = (float * RESTRICT) Mod_Skeletal_AnimateVertices_AllocBuffers(sizeof(float[12]) * model->num_bones);
73 if (skeleton && !skeleton->relativetransforms)
76 // interpolate matrices
79 for (i = 0;i < model->num_bones;i++)
81 Matrix4x4_ToArray12FloatD3D(&skeleton->relativetransforms[i], m);
82 if (model->data_bones[i].parent >= 0)
83 R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12);
85 memcpy(bonepose + i * 12, m, sizeof(m));
87 // create a relative deformation matrix to describe displacement
88 // from the base mesh, which is used by the actual weighting
89 R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
94 for (i = 0;i < model->num_bones;i++)
96 // blend by transform each quaternion/translation into a dual-quaternion first, then blending
97 const short * RESTRICT firstpose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i);
98 float firstlerp = frameblend[0].lerp,
99 firsttx = firstpose7s[0], firstty = firstpose7s[1], firsttz = firstpose7s[2],
100 rx = firstpose7s[3] * firstlerp,
101 ry = firstpose7s[4] * firstlerp,
102 rz = firstpose7s[5] * firstlerp,
103 rw = firstpose7s[6] * firstlerp,
104 dx = firsttx*rw + firstty*rz - firsttz*ry,
105 dy = -firsttx*rz + firstty*rw + firsttz*rx,
106 dz = firsttx*ry - firstty*rx + firsttz*rw,
107 dw = -firsttx*rx - firstty*ry - firsttz*rz,
108 scale, sx, sy, sz, sw;
109 for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
111 const short * RESTRICT blendpose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i);
112 float blendlerp = frameblend[blends].lerp,
113 blendtx = blendpose7s[0], blendty = blendpose7s[1], blendtz = blendpose7s[2],
114 qx = blendpose7s[3], qy = blendpose7s[4], qz = blendpose7s[5], qw = blendpose7s[6];
115 if(rx*qx + ry*qy + rz*qz + rw*qw < 0) blendlerp = -blendlerp;
124 dx += blendtx*qw + blendty*qz - blendtz*qy;
125 dy += -blendtx*qz + blendty*qw + blendtz*qx;
126 dz += blendtx*qy - blendty*qx + blendtz*qw;
127 dw += -blendtx*qx - blendty*qy - blendtz*qz;
129 // generate a matrix from the dual-quaternion, implicitly normalizing it in the process
130 scale = 1.0f / (rx*rx + ry*ry + rz*rz + rw*rw);
135 m[0] = sw*rw + sx*rx - sy*ry - sz*rz;
136 m[1] = 2*(sx*ry - sw*rz);
137 m[2] = 2*(sx*rz + sw*ry);
138 m[3] = model->num_posescale*(dx*sw - dy*sz + dz*sy - dw*sx);
139 m[4] = 2*(sx*ry + sw*rz);
140 m[5] = sw*rw + sy*ry - sx*rx - sz*rz;
141 m[6] = 2*(sy*rz - sw*rx);
142 m[7] = model->num_posescale*(dx*sz + dy*sw - dz*sx - dw*sy);
143 m[8] = 2*(sx*rz - sw*ry);
144 m[9] = 2*(sy*rz + sw*rx);
145 m[10] = sw*rw + sz*rz - sx*rx - sy*ry;
146 m[11] = model->num_posescale*(dy*sx + dz*sw - dx*sy - dw*sz);
147 if (i == r_skeletal_debugbone.integer)
148 m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value;
149 m[3] *= r_skeletal_debugtranslatex.value;
150 m[7] *= r_skeletal_debugtranslatey.value;
151 m[11] *= r_skeletal_debugtranslatez.value;
152 if (model->data_bones[i].parent >= 0)
153 R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12);
155 memcpy(bonepose + i * 12, m, sizeof(m));
156 // create a relative deformation matrix to describe displacement
157 // from the base mesh, which is used by the actual weighting
158 R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
163 static void Mod_Skeletal_AnimateVertices(const model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
166 if (!model->surfmesh.num_vertices)
169 if (!model->num_bones)
171 if (vertex3f) memcpy(vertex3f, model->surfmesh.data_vertex3f, model->surfmesh.num_vertices*sizeof(float[3]));
172 if (normal3f) memcpy(normal3f, model->surfmesh.data_normal3f, model->surfmesh.num_vertices*sizeof(float[3]));
173 if (svector3f) memcpy(svector3f, model->surfmesh.data_svector3f, model->surfmesh.num_vertices*sizeof(float[3]));
174 if (tvector3f) memcpy(tvector3f, model->surfmesh.data_tvector3f, model->surfmesh.num_vertices*sizeof(float[3]));
179 if(r_skeletal_use_sse_defined)
180 if(r_skeletal_use_sse.integer)
182 Mod_Skeletal_AnimateVertices_SSE(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
186 Mod_Skeletal_AnimateVertices_Generic(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
189 void Mod_AliasInit (void)
192 Cvar_RegisterVariable(&r_skeletal_debugbone);
193 Cvar_RegisterVariable(&r_skeletal_debugbonecomponent);
194 Cvar_RegisterVariable(&r_skeletal_debugbonevalue);
195 Cvar_RegisterVariable(&r_skeletal_debugtranslatex);
196 Cvar_RegisterVariable(&r_skeletal_debugtranslatey);
197 Cvar_RegisterVariable(&r_skeletal_debugtranslatez);
198 Cvar_RegisterVariable(&mod_alias_supporttagscale);
199 Cvar_RegisterVariable(&mod_alias_force_animated);
200 for (i = 0;i < 320;i++)
201 mod_md3_sin[i] = sin(i * M_PI * 2.0f / 256.0);
205 Con_Printf("Skeletal animation uses SSE code path\n");
206 r_skeletal_use_sse_defined = true;
207 Cvar_RegisterVariable(&r_skeletal_use_sse);
210 Con_Printf("Skeletal animation uses generic code path (SSE disabled or not detected)\n");
212 Con_Printf("Skeletal animation uses generic code path (SSE not compiled in)\n");
216 static int Mod_Skeletal_AddBlend(model_t *model, const blendweights_t *newweights)
219 blendweights_t *weights;
220 if(!newweights->influence[1])
221 return newweights->index[0];
222 weights = model->surfmesh.data_blendweights;
223 for (i = 0;i < model->surfmesh.num_blends;i++, weights++)
225 if (!memcmp(weights, newweights, sizeof(blendweights_t)))
226 return model->num_bones + i;
228 model->surfmesh.num_blends++;
229 memcpy(weights, newweights, sizeof(blendweights_t));
230 return model->num_bones + i;
233 static int Mod_Skeletal_CompressBlend(model_t *model, const int *newindex, const float *newinfluence)
237 blendweights_t newweights;
241 for (i = 0;i < 4;i++)
242 scale += newinfluence[i];
243 scale = 255.0f / scale;
245 for (i = 0;i < 4;i++)
247 newweights.index[i] = newindex[i];
248 newweights.influence[i] = (unsigned char)(newinfluence[i] * scale);
249 total += newweights.influence[i];
253 for (i = 0;i < 4;i++)
255 if(newweights.influence[i] > 0 && total > 255)
257 newweights.influence[i]--;
264 for (i = 0; i < 4;i++)
266 if(newweights.influence[i] < 255 && total < 255)
268 newweights.influence[i]++;
273 return Mod_Skeletal_AddBlend(model, &newweights);
276 static void Mod_MD3_AnimateVertices(const model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
279 int i, numblends, blendnum;
280 int numverts = model->surfmesh.num_vertices;
282 for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
284 //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate);
285 if (frameblend[blendnum].lerp > 0)
286 numblends = blendnum + 1;
288 // special case for the first blend because it avoids some adds and the need to memset the arrays first
289 for (blendnum = 0;blendnum < numblends;blendnum++)
291 const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].subframe;
294 float scale = frameblend[blendnum].lerp * (1.0f / 64.0f);
297 for (i = 0;i < numverts;i++)
299 vertex3f[i * 3 + 0] = verts[i].origin[0] * scale;
300 vertex3f[i * 3 + 1] = verts[i].origin[1] * scale;
301 vertex3f[i * 3 + 2] = verts[i].origin[2] * scale;
306 for (i = 0;i < numverts;i++)
308 vertex3f[i * 3 + 0] += verts[i].origin[0] * scale;
309 vertex3f[i * 3 + 1] += verts[i].origin[1] * scale;
310 vertex3f[i * 3 + 2] += verts[i].origin[2] * scale;
314 // the yaw and pitch stored in md3 models are 8bit quantized angles
315 // (0-255), and as such a lookup table is very well suited to
316 // decoding them, and since cosine is equivalent to sine with an
317 // extra 45 degree rotation, this uses one lookup table for both
318 // sine and cosine with a +64 bias to get cosine.
321 float lerp = frameblend[blendnum].lerp;
324 for (i = 0;i < numverts;i++)
326 normal3f[i * 3 + 0] = mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp;
327 normal3f[i * 3 + 1] = mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp;
328 normal3f[i * 3 + 2] = mod_md3_sin[verts[i].pitch + 64] * lerp;
333 for (i = 0;i < numverts;i++)
335 normal3f[i * 3 + 0] += mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp;
336 normal3f[i * 3 + 1] += mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp;
337 normal3f[i * 3 + 2] += mod_md3_sin[verts[i].pitch + 64] * lerp;
343 const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
344 float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
347 for (i = 0;i < numverts;i++, texvecvert++)
349 VectorScale(texvecvert->svec, f, svector3f + i*3);
350 VectorScale(texvecvert->tvec, f, tvector3f + i*3);
355 for (i = 0;i < numverts;i++, texvecvert++)
357 VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
358 VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
364 static void Mod_MDL_AnimateVertices(const model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
367 int i, numblends, blendnum;
368 int numverts = model->surfmesh.num_vertices;
370 VectorClear(translate);
372 // blend the frame translates to avoid redundantly doing so on each vertex
373 // (a bit of a brain twister but it works)
374 for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
376 if (model->surfmesh.data_morphmd2framesize6f)
377 VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6 + 3, translate);
379 VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate);
380 if (frameblend[blendnum].lerp > 0)
381 numblends = blendnum + 1;
383 // special case for the first blend because it avoids some adds and the need to memset the arrays first
384 for (blendnum = 0;blendnum < numblends;blendnum++)
386 const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].subframe;
390 if (model->surfmesh.data_morphmd2framesize6f)
391 VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6, frameblend[blendnum].lerp, scale);
393 VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale);
396 for (i = 0;i < numverts;i++)
398 vertex3f[i * 3 + 0] = translate[0] + verts[i].v[0] * scale[0];
399 vertex3f[i * 3 + 1] = translate[1] + verts[i].v[1] * scale[1];
400 vertex3f[i * 3 + 2] = translate[2] + verts[i].v[2] * scale[2];
405 for (i = 0;i < numverts;i++)
407 vertex3f[i * 3 + 0] += verts[i].v[0] * scale[0];
408 vertex3f[i * 3 + 1] += verts[i].v[1] * scale[1];
409 vertex3f[i * 3 + 2] += verts[i].v[2] * scale[2];
413 // the vertex normals in mdl models are an index into a table of
414 // 162 unique values, this very crude quantization reduces the
415 // vertex normal to only one byte, which saves a lot of space but
416 // also makes lighting pretty coarse
419 float lerp = frameblend[blendnum].lerp;
422 for (i = 0;i < numverts;i++)
424 const float *vn = m_bytenormals[verts[i].lightnormalindex];
425 VectorScale(vn, lerp, normal3f + i*3);
430 for (i = 0;i < numverts;i++)
432 const float *vn = m_bytenormals[verts[i].lightnormalindex];
433 VectorMA(normal3f + i*3, lerp, vn, normal3f + i*3);
439 const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
440 float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
443 for (i = 0;i < numverts;i++, texvecvert++)
445 VectorScale(texvecvert->svec, f, svector3f + i*3);
446 VectorScale(texvecvert->tvec, f, tvector3f + i*3);
451 for (i = 0;i < numverts;i++, texvecvert++)
453 VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
454 VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
461 int Mod_Alias_GetTagMatrix(const model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, matrix4x4_t *outmatrix)
464 matrix4x4_t parentbonematrix;
465 matrix4x4_t tempbonematrix;
466 matrix4x4_t bonematrix;
467 matrix4x4_t blendmatrix;
474 *outmatrix = identitymatrix;
475 if (skeleton && skeleton->relativetransforms)
477 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
479 *outmatrix = skeleton->relativetransforms[tagindex];
480 while ((tagindex = model->data_bones[tagindex].parent) >= 0)
483 Matrix4x4_Concat(outmatrix, &skeleton->relativetransforms[tagindex], &temp);
486 else if (model->num_bones)
488 if (tagindex < 0 || tagindex >= model->num_bones)
490 Matrix4x4_Clear(&blendmatrix);
491 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
493 lerp = frameblend[blendindex].lerp;
494 Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
495 parenttagindex = tagindex;
496 while ((parenttagindex = model->data_bones[parenttagindex].parent) >= 0)
498 Matrix4x4_FromBonePose7s(&parentbonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + parenttagindex));
499 tempbonematrix = bonematrix;
500 Matrix4x4_Concat(&bonematrix, &parentbonematrix, &tempbonematrix);
502 Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
504 *outmatrix = blendmatrix;
506 else if (model->num_tags)
508 if (tagindex < 0 || tagindex >= model->num_tags)
510 for (k = 0;k < 12;k++)
512 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
514 lerp = frameblend[blendindex].lerp;
515 input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
516 for (k = 0;k < 12;k++)
517 blendtag[k] += input[k] * lerp;
519 Matrix4x4_FromArray12FloatGL(outmatrix, blendtag);
522 if(!mod_alias_supporttagscale.integer)
523 Matrix4x4_Normalize3(outmatrix, outmatrix);
528 int Mod_Alias_GetExtendedTagInfoForIndex(const model_t *model, unsigned int skin, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
533 matrix4x4_t bonematrix;
534 matrix4x4_t blendmatrix;
538 if (skeleton && skeleton->relativetransforms)
540 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
542 *parentindex = skeleton->model->data_bones[tagindex].parent;
543 *tagname = skeleton->model->data_bones[tagindex].name;
544 *tag_localmatrix = skeleton->relativetransforms[tagindex];
547 else if (model->num_bones)
549 if (tagindex < 0 || tagindex >= model->num_bones)
551 *parentindex = model->data_bones[tagindex].parent;
552 *tagname = model->data_bones[tagindex].name;
553 Matrix4x4_Clear(&blendmatrix);
554 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
556 lerp = frameblend[blendindex].lerp;
557 Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
558 Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
560 *tag_localmatrix = blendmatrix;
563 else if (model->num_tags)
565 if (tagindex < 0 || tagindex >= model->num_tags)
568 *tagname = model->data_tags[tagindex].name;
569 for (k = 0;k < 12;k++)
571 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
573 lerp = frameblend[blendindex].lerp;
574 input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
575 for (k = 0;k < 12;k++)
576 blendtag[k] += input[k] * lerp;
578 Matrix4x4_FromArray12FloatGL(tag_localmatrix, blendtag);
585 int Mod_Alias_GetTagIndexForName(const model_t *model, unsigned int skin, const char *tagname)
588 if(skin >= (unsigned int)model->numskins)
590 if (model->num_bones)
591 for (i = 0;i < model->num_bones;i++)
592 if (!strcasecmp(tagname, model->data_bones[i].name))
595 for (i = 0;i < model->num_tags;i++)
596 if (!strcasecmp(tagname, model->data_tags[i].name))
601 static void Mod_BuildBaseBonePoses(void)
604 matrix4x4_t *basebonepose;
605 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
606 matrix4x4_t bonematrix;
607 matrix4x4_t tempbonematrix;
608 if (!loadmodel->num_bones)
610 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
611 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
613 Matrix4x4_FromBonePose7s(&bonematrix, loadmodel->num_posescale, loadmodel->data_poses7s + 7 * boneindex);
614 if (loadmodel->data_bones[boneindex].parent >= 0)
616 tempbonematrix = bonematrix;
617 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
619 basebonepose[boneindex] = bonematrix;
620 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
621 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
623 Mem_Free(basebonepose);
626 static qbool Mod_Alias_CalculateBoundingBox(void)
629 qbool firstvertex = true;
630 float dist, yawradius, radius;
632 qbool isanimated = false;
633 VectorClear(loadmodel->normalmins);
634 VectorClear(loadmodel->normalmaxs);
637 if (loadmodel->AnimateVertices)
639 float *vertex3f, *refvertex3f;
640 frameblend_t frameblend[MAX_FRAMEBLENDS];
641 memset(frameblend, 0, sizeof(frameblend));
642 frameblend[0].lerp = 1;
643 vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]) * 2);
645 for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
647 loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL);
650 // make a copy of the first frame for comparing all others
651 refvertex3f = vertex3f + loadmodel->surfmesh.num_vertices * 3;
652 memcpy(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
656 if (!isanimated && memcmp(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3])))
659 for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
664 VectorCopy(v, loadmodel->normalmins);
665 VectorCopy(v, loadmodel->normalmaxs);
669 if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
670 if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
671 if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
672 if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
673 if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
674 if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
676 dist = v[0] * v[0] + v[1] * v[1];
677 if (yawradius < dist)
689 for (vnum = 0, v = loadmodel->surfmesh.data_vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
694 VectorCopy(v, loadmodel->normalmins);
695 VectorCopy(v, loadmodel->normalmaxs);
699 if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
700 if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
701 if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
702 if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
703 if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
704 if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
706 dist = v[0] * v[0] + v[1] * v[1];
707 if (yawradius < dist)
714 radius = sqrt(radius);
715 yawradius = sqrt(yawradius);
716 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
717 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius;
718 loadmodel->yawmins[2] = loadmodel->normalmins[2];
719 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
720 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
721 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
722 loadmodel->radius = radius;
723 loadmodel->radius2 = radius * radius;
727 static void Mod_Alias_MorphMesh_CompileFrames(void)
730 frameblend_t frameblend[MAX_FRAMEBLENDS];
731 unsigned char *datapointer;
732 memset(frameblend, 0, sizeof(frameblend));
733 frameblend[0].lerp = 1;
734 datapointer = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * (sizeof(float[3]) * 4 + loadmodel->surfmesh.num_morphframes * sizeof(texvecvertex_t)));
735 loadmodel->surfmesh.data_vertex3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
736 loadmodel->surfmesh.data_svector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
737 loadmodel->surfmesh.data_tvector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
738 loadmodel->surfmesh.data_normal3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
739 loadmodel->surfmesh.data_morphtexvecvertex = (texvecvertex_t *)datapointer;datapointer += loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices * sizeof(texvecvertex_t);
740 // 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)
741 for (i = loadmodel->surfmesh.num_morphframes-1;i >= 0;i--)
743 frameblend[0].subframe = i;
744 loadmodel->AnimateVertices(loadmodel, frameblend, NULL, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL);
745 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
746 // encode the svector and tvector in 3 byte format for permanent storage
747 for (j = 0;j < loadmodel->surfmesh.num_vertices;j++)
749 VectorScaleCast(loadmodel->surfmesh.data_svector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].svec);
750 VectorScaleCast(loadmodel->surfmesh.data_tvector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].tvec);
755 static void Mod_MDLMD2MD3_TraceLine(model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
758 float segmentmins[3], segmentmaxs[3];
760 float vertex3fbuf[1024 * 3];
761 float *vertex3f = vertex3fbuf;
762 float *freevertex3f = NULL;
763 // for static cases we can just call CollisionBIH which is much faster
764 if ((frameblend == NULL || (frameblend[0].subframe == 0 && frameblend[1].lerp == 0)) && (skeleton == NULL || skeleton->relativetransforms == NULL))
766 Mod_CollisionBIH_TraceLine(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
769 memset(trace, 0, sizeof(*trace));
771 trace->hitsupercontentsmask = hitsupercontentsmask;
772 trace->skipsupercontentsmask = skipsupercontentsmask;
773 trace->skipmaterialflagsmask = skipmaterialflagsmask;
774 segmentmins[0] = min(start[0], end[0]) - 1;
775 segmentmins[1] = min(start[1], end[1]) - 1;
776 segmentmins[2] = min(start[2], end[2]) - 1;
777 segmentmaxs[0] = max(start[0], end[0]) + 1;
778 segmentmaxs[1] = max(start[1], end[1]) + 1;
779 segmentmaxs[2] = max(start[2], end[2]) + 1;
780 if (frameblend == NULL || frameblend[0].subframe != 0 || frameblend[0].lerp != 0 || skeleton != NULL)
782 if (model->surfmesh.num_vertices > 1024)
783 vertex3f = freevertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
784 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
787 vertex3f = model->surfmesh.data_vertex3f;
788 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
789 Collision_TraceLineTriangleMeshFloat(trace, start, end, surface->num_triangles, model->surfmesh.data_element3i + 3 * surface->num_firsttriangle, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
791 Mem_Free(freevertex3f);
794 static void Mod_MDLMD2MD3_TraceBox(model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
797 vec3_t shiftstart, shiftend;
798 float segmentmins[3], segmentmaxs[3];
800 float vertex3fbuf[1024*3];
801 float *vertex3f = vertex3fbuf;
802 colboxbrushf_t thisbrush_start, thisbrush_end;
803 vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
805 if (VectorCompare(boxmins, boxmaxs))
807 VectorAdd(start, boxmins, shiftstart);
808 VectorAdd(end, boxmins, shiftend);
809 Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
810 VectorSubtract(trace->endpos, boxmins, trace->endpos);
814 // for static cases we can just call CollisionBIH which is much faster
815 if ((frameblend == NULL || (frameblend[0].subframe == 0 && frameblend[1].lerp == 0)) && (skeleton == NULL || skeleton->relativetransforms == NULL))
817 Mod_CollisionBIH_TraceBox(model, frameblend, skeleton, trace, start, boxmins, boxmaxs, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
821 // box trace, performed as brush trace
822 memset(trace, 0, sizeof(*trace));
824 trace->hitsupercontentsmask = hitsupercontentsmask;
825 trace->skipsupercontentsmask = skipsupercontentsmask;
826 trace->skipmaterialflagsmask = skipmaterialflagsmask;
827 if (model->surfmesh.num_vertices > 1024)
828 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
829 segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
830 segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
831 segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
832 segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
833 segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
834 segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
835 VectorAdd(start, boxmins, boxstartmins);
836 VectorAdd(start, boxmaxs, boxstartmaxs);
837 VectorAdd(end, boxmins, boxendmins);
838 VectorAdd(end, boxmaxs, boxendmaxs);
839 Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL);
840 Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL);
841 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
842 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
843 Collision_TraceBrushTriangleMeshFloat(trace, &thisbrush_start.brush, &thisbrush_end.brush, surface->num_triangles, model->surfmesh.data_element3i + 3 * surface->num_firsttriangle, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
844 if (vertex3f != vertex3fbuf)
848 static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
851 for (i = 0;i < inverts;i++)
853 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
855 j = vertremap[i]; // not onseam
858 j = vertremap[i+inverts]; // onseam
864 static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
866 int i, f, pose, groupframes;
868 daliasframetype_t *pframetype;
869 daliasframe_t *pinframe;
870 daliasgroup_t *group;
871 daliasinterval_t *intervals;
874 scene = loadmodel->animscenes;
875 for (f = 0;f < loadmodel->numframes;f++)
877 pframetype = (daliasframetype_t *)datapointer;
878 datapointer += sizeof(daliasframetype_t);
879 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
881 // a single frame is still treated as a group
888 group = (daliasgroup_t *)datapointer;
889 datapointer += sizeof(daliasgroup_t);
890 groupframes = LittleLong (group->numframes);
892 // intervals (time per frame)
893 intervals = (daliasinterval_t *)datapointer;
894 datapointer += sizeof(daliasinterval_t) * groupframes;
896 interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
897 if (interval < 0.01f)
899 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
904 // get scene name from first frame
905 pinframe = (daliasframe_t *)datapointer;
907 strlcpy(scene->name, pinframe->name, sizeof(scene->name));
908 scene->firstframe = pose;
909 scene->framecount = groupframes;
910 scene->framerate = 1.0f / interval;
915 for (i = 0;i < groupframes;i++)
917 datapointer += sizeof(daliasframe_t);
918 Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
919 datapointer += sizeof(trivertx_t) * inverts;
925 void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
928 char stripbuf[MAX_QPATH];
929 skinfileitem_t *skinfileitem;
930 if(developer_extra.integer)
931 Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername);
934 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
935 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
937 memset(skin, 0, sizeof(*skin));
939 for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
941 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
942 if (!strcmp(skinfileitem->name, meshname))
944 Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
945 if(developer_extra.integer)
946 Con_DPrintf("--> got %s from skin file\n", stripbuf);
947 Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
953 // don't render unmentioned meshes
954 Mod_LoadCustomMaterial(loadmodel->mempool, skin, meshname, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
955 if(developer_extra.integer)
956 Con_DPrintf("--> skipping\n");
957 skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
963 if(developer_extra.integer)
964 Con_DPrintf("--> using default\n");
965 Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
966 Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
969 extern cvar_t r_nolerp_list;
970 #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);
971 #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);
972 void Mod_IDP0_Load(model_t *mod, void *buffer, void *bufferend)
974 int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
975 float scales, scalet, interval;
979 stvert_t *pinstverts;
980 dtriangle_t *pintriangles;
981 daliasskintype_t *pinskintype;
982 daliasskingroup_t *pinskingroup;
983 daliasskininterval_t *pinskinintervals;
984 daliasframetype_t *pinframetype;
985 daliasgroup_t *pinframegroup;
986 unsigned char *datapointer, *startframes, *startskins;
987 char name[MAX_QPATH];
988 skinframe_t *tempskinframe;
989 animscene_t *tempskinscenes;
990 texture_t *tempaliasskins;
992 int *vertonseam, *vertremap;
993 skinfile_t *skinfiles;
995 datapointer = (unsigned char *)buffer;
996 pinmodel = (mdl_t *)datapointer;
997 datapointer += sizeof(mdl_t);
999 version = LittleLong (pinmodel->version);
1000 if (version != ALIAS_VERSION)
1001 Host_Error ("%s has wrong version number (%i should be %i)",
1002 loadmodel->name, version, ALIAS_VERSION);
1004 loadmodel->modeldatatypestring = "MDL";
1006 loadmodel->type = mod_alias;
1007 loadmodel->Draw = R_Mod_Draw;
1008 loadmodel->DrawDepth = R_Mod_DrawDepth;
1009 loadmodel->DrawDebug = R_Mod_DrawDebug;
1010 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1011 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1012 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1013 loadmodel->DrawLight = R_Mod_DrawLight;
1014 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1015 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1016 // FIXME add TraceBrush!
1017 loadmodel->PointSuperContents = NULL;
1018 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1020 loadmodel->num_surfaces = 1;
1021 loadmodel->submodelsurfaces_start = 0;
1022 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1023 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1024 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1025 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1026 loadmodel->modelsurfaces_sorted[0] = 0;
1028 loadmodel->numskins = LittleLong(pinmodel->numskins);
1029 BOUNDI(loadmodel->numskins,0,65536);
1030 skinwidth = LittleLong (pinmodel->skinwidth);
1031 BOUNDI(skinwidth,0,65536);
1032 skinheight = LittleLong (pinmodel->skinheight);
1033 BOUNDI(skinheight,0,65536);
1034 numverts = LittleLong(pinmodel->numverts);
1035 BOUNDI(numverts,0,65536);
1036 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1037 BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1038 loadmodel->numframes = LittleLong(pinmodel->numframes);
1039 BOUNDI(loadmodel->numframes,0,65536);
1040 loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1041 BOUNDI((int)loadmodel->synctype,0,2);
1042 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1043 i = LittleLong (pinmodel->flags);
1044 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1046 if (strstr(r_nolerp_list.string, loadmodel->name))
1047 loadmodel->nolerp = true;
1049 for (i = 0;i < 3;i++)
1051 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1052 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1055 startskins = datapointer;
1057 for (i = 0;i < loadmodel->numskins;i++)
1059 pinskintype = (daliasskintype_t *)datapointer;
1060 datapointer += sizeof(daliasskintype_t);
1061 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1065 pinskingroup = (daliasskingroup_t *)datapointer;
1066 datapointer += sizeof(daliasskingroup_t);
1067 groupskins = LittleLong(pinskingroup->numskins);
1068 datapointer += sizeof(daliasskininterval_t) * groupskins;
1071 for (j = 0;j < groupskins;j++)
1073 datapointer += skinwidth * skinheight;
1078 pinstverts = (stvert_t *)datapointer;
1079 datapointer += sizeof(stvert_t) * numverts;
1081 pintriangles = (dtriangle_t *)datapointer;
1082 datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1084 startframes = datapointer;
1085 loadmodel->surfmesh.num_morphframes = 0;
1086 for (i = 0;i < loadmodel->numframes;i++)
1088 pinframetype = (daliasframetype_t *)datapointer;
1089 datapointer += sizeof(daliasframetype_t);
1090 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1094 pinframegroup = (daliasgroup_t *)datapointer;
1095 datapointer += sizeof(daliasgroup_t);
1096 groupframes = LittleLong(pinframegroup->numframes);
1097 datapointer += sizeof(daliasinterval_t) * groupframes;
1100 for (j = 0;j < groupframes;j++)
1102 datapointer += sizeof(daliasframe_t);
1103 datapointer += sizeof(trivertx_t) * numverts;
1104 loadmodel->surfmesh.num_morphframes++;
1107 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1109 // store texture coordinates into temporary array, they will be stored
1110 // after usage is determined (triangle data)
1111 vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1112 vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1113 vertonseam = vertremap + numverts * 2;
1115 scales = 1.0 / skinwidth;
1116 scalet = 1.0 / skinheight;
1117 for (i = 0;i < numverts;i++)
1119 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1120 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1121 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1122 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1123 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1126 // load triangle data
1127 loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1129 // read the triangle elements
1130 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1131 for (j = 0;j < 3;j++)
1132 loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1133 // validate (note numverts is used because this is the original data)
1134 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, NULL, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1135 // now butcher the elements according to vertonseam and tri->facesfront
1136 // and then compact the vertex set to remove duplicates
1137 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1138 if (!LittleLong(pintriangles[i].facesfront)) // backface
1139 for (j = 0;j < 3;j++)
1140 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1141 loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1143 // (this uses vertremap to count usage to save some memory)
1144 for (i = 0;i < numverts*2;i++)
1146 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1147 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1148 // build remapping table and compact array
1149 loadmodel->surfmesh.num_vertices = 0;
1150 for (i = 0;i < numverts*2;i++)
1154 vertremap[i] = loadmodel->surfmesh.num_vertices;
1155 vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1156 vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1157 loadmodel->surfmesh.num_vertices++;
1160 vertremap[i] = -1; // not used at all
1162 // remap the elements to the new vertex set
1163 for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1164 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1165 // store the texture coordinates
1166 loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1167 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1169 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1170 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1173 // generate ushort elements array if possible
1174 if (loadmodel->surfmesh.num_vertices <= 65536)
1175 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1176 if (loadmodel->surfmesh.data_element3s)
1177 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1178 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1181 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1182 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1183 Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1184 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1185 Mod_Alias_MorphMesh_CompileFrames();
1188 Mem_Free(vertremap);
1191 skinfiles = Mod_LoadSkinFiles();
1194 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1195 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1196 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1197 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1198 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1199 Mod_FreeSkinFiles(skinfiles);
1200 for (i = 0;i < loadmodel->numskins;i++)
1202 loadmodel->skinscenes[i].firstframe = i;
1203 loadmodel->skinscenes[i].framecount = 1;
1204 loadmodel->skinscenes[i].loop = true;
1205 loadmodel->skinscenes[i].framerate = 10;
1210 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1211 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1212 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1213 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1215 datapointer = startskins;
1216 for (i = 0;i < loadmodel->numskins;i++)
1218 pinskintype = (daliasskintype_t *)datapointer;
1219 datapointer += sizeof(daliasskintype_t);
1221 if (pinskintype->type == ALIAS_SKIN_SINGLE)
1228 pinskingroup = (daliasskingroup_t *)datapointer;
1229 datapointer += sizeof(daliasskingroup_t);
1231 groupskins = LittleLong (pinskingroup->numskins);
1233 pinskinintervals = (daliasskininterval_t *)datapointer;
1234 datapointer += sizeof(daliasskininterval_t) * groupskins;
1236 interval = LittleFloat(pinskinintervals[0].interval);
1237 if (interval < 0.01f)
1239 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1244 dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1245 loadmodel->skinscenes[i].firstframe = totalskins;
1246 loadmodel->skinscenes[i].framecount = groupskins;
1247 loadmodel->skinscenes[i].framerate = 1.0f / interval;
1248 loadmodel->skinscenes[i].loop = true;
1250 for (j = 0;j < groupskins;j++)
1253 dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1255 dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1256 if (!Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, false, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL))
1257 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight));
1258 datapointer += skinwidth * skinheight;
1262 // check for skins that don't exist in the model, but do exist as external images
1263 // (this was added because yummyluv kept pestering me about support for it)
1264 // TODO: support shaders here?
1267 dpsnprintf(name, sizeof(name), "%s_%i", loadmodel->name, loadmodel->numskins);
1268 tempskinframe = R_SkinFrame_LoadExternal(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false, false);
1271 // expand the arrays to make room
1272 tempskinscenes = loadmodel->skinscenes;
1273 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1274 memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1275 Mem_Free(tempskinscenes);
1277 tempaliasskins = loadmodel->data_textures;
1278 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1279 memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1280 Mem_Free(tempaliasskins);
1282 // store the info about the new skin
1283 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, tempskinframe);
1284 strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1285 loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1286 loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1287 loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1288 loadmodel->skinscenes[loadmodel->numskins].loop = true;
1290 //increase skin counts
1291 loadmodel->num_textures++;
1292 loadmodel->numskins++;
1295 // fix up the pointers since they are pointing at the old textures array
1296 // FIXME: this is a hack!
1297 for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1298 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1302 surface = loadmodel->data_surfaces;
1303 surface->texture = loadmodel->data_textures;
1304 surface->num_firsttriangle = 0;
1305 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1306 surface->num_firstvertex = 0;
1307 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1309 if(mod_alias_force_animated.string[0])
1310 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1312 // Always make a BIH for the first frame, we can use it where possible.
1313 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1314 if (!loadmodel->surfmesh.isanimated)
1316 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1317 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1318 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1319 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1320 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1324 void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend)
1326 int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1327 float iskinwidth, iskinheight;
1328 unsigned char *data;
1329 msurface_t *surface;
1331 unsigned char *base, *datapointer;
1332 md2frame_t *pinframe;
1334 md2triangle_t *intri;
1335 unsigned short *inst;
1336 struct md2verthash_s
1338 struct md2verthash_s *next;
1342 *hash, **md2verthash, *md2verthashdata;
1343 skinfile_t *skinfiles;
1345 pinmodel = (md2_t *)buffer;
1346 base = (unsigned char *)buffer;
1348 version = LittleLong (pinmodel->version);
1349 if (version != MD2ALIAS_VERSION)
1350 Host_Error ("%s has wrong version number (%i should be %i)",
1351 loadmodel->name, version, MD2ALIAS_VERSION);
1353 loadmodel->modeldatatypestring = "MD2";
1355 loadmodel->type = mod_alias;
1356 loadmodel->Draw = R_Mod_Draw;
1357 loadmodel->DrawDepth = R_Mod_DrawDepth;
1358 loadmodel->DrawDebug = R_Mod_DrawDebug;
1359 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1360 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1361 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1362 loadmodel->DrawLight = R_Mod_DrawLight;
1363 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1364 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1365 loadmodel->PointSuperContents = NULL;
1366 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1368 if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1369 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1370 if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1371 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1372 if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1373 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1374 if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1375 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1377 end = LittleLong(pinmodel->ofs_end);
1378 if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1379 Host_Error ("%s is not a valid model", loadmodel->name);
1380 if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1381 Host_Error ("%s is not a valid model", loadmodel->name);
1382 if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1383 Host_Error ("%s is not a valid model", loadmodel->name);
1384 if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1385 Host_Error ("%s is not a valid model", loadmodel->name);
1386 if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1387 Host_Error ("%s is not a valid model", loadmodel->name);
1389 loadmodel->numskins = LittleLong(pinmodel->num_skins);
1390 numxyz = LittleLong(pinmodel->num_xyz);
1391 numst = LittleLong(pinmodel->num_st);
1392 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1393 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1394 loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1395 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1396 skinwidth = LittleLong(pinmodel->skinwidth);
1397 skinheight = LittleLong(pinmodel->skinheight);
1398 iskinwidth = 1.0f / skinwidth;
1399 iskinheight = 1.0f / skinheight;
1401 loadmodel->num_surfaces = 1;
1402 loadmodel->submodelsurfaces_start = 0;
1403 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1404 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]));
1405 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1406 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1407 loadmodel->modelsurfaces_sorted[0] = 0;
1408 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1409 loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1410 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1412 loadmodel->synctype = ST_RAND;
1415 inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1416 skinfiles = Mod_LoadSkinFiles();
1419 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1420 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1421 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1422 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1423 Mod_FreeSkinFiles(skinfiles);
1425 else if (loadmodel->numskins)
1427 // skins found (most likely not a player model)
1428 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1429 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1430 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1431 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1432 Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
1436 // no skins (most likely a player model)
1437 loadmodel->numskins = 1;
1438 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1439 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1440 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1441 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures, loadmodel->name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
1444 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1445 for (i = 0;i < loadmodel->numskins;i++)
1447 loadmodel->skinscenes[i].firstframe = i;
1448 loadmodel->skinscenes[i].framecount = 1;
1449 loadmodel->skinscenes[i].loop = true;
1450 loadmodel->skinscenes[i].framerate = 10;
1453 // load the triangles and stvert data
1454 inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1455 intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1456 md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1457 md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1458 // swap the triangle list
1459 loadmodel->surfmesh.num_vertices = 0;
1460 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1462 for (j = 0;j < 3;j++)
1464 xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1465 st = (unsigned short) LittleShort (intri[i].index_st[j]);
1468 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1473 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1476 hashindex = (xyz * 256 + st) & 65535;
1477 for (hash = md2verthash[hashindex];hash;hash = hash->next)
1478 if (hash->xyz == xyz && hash->st == st)
1482 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1485 hash->next = md2verthash[hashindex];
1486 md2verthash[hashindex] = hash;
1488 loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1492 vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1493 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));
1494 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1495 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1496 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1499 hash = md2verthashdata + i;
1500 vertremap[i] = hash->xyz;
1501 sts = LittleShort(inst[hash->st*2+0]);
1502 stt = LittleShort(inst[hash->st*2+1]);
1503 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1505 Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1509 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1510 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1513 Mem_Free(md2verthash);
1514 Mem_Free(md2verthashdata);
1516 // generate ushort elements array if possible
1517 if (loadmodel->surfmesh.num_vertices <= 65536)
1518 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1519 if (loadmodel->surfmesh.data_element3s)
1520 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1521 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1524 datapointer = (base + LittleLong(pinmodel->ofs_frames));
1525 for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1530 pinframe = (md2frame_t *)datapointer;
1531 datapointer += sizeof(md2frame_t);
1532 // store the frame scale/translate into the appropriate array
1533 for (j = 0;j < 3;j++)
1535 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1536 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1538 // convert the vertices
1539 v = (trivertx_t *)datapointer;
1540 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1541 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1542 out[k] = v[vertremap[k]];
1543 datapointer += numxyz * sizeof(trivertx_t);
1545 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1546 loadmodel->animscenes[i].firstframe = i;
1547 loadmodel->animscenes[i].framecount = 1;
1548 loadmodel->animscenes[i].framerate = 10;
1549 loadmodel->animscenes[i].loop = true;
1552 Mem_Free(vertremap);
1554 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1555 Mod_Alias_MorphMesh_CompileFrames();
1556 if(mod_alias_force_animated.string[0])
1557 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1559 surface = loadmodel->data_surfaces;
1560 surface->texture = loadmodel->data_textures;
1561 surface->num_firsttriangle = 0;
1562 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1563 surface->num_firstvertex = 0;
1564 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1566 // Always make a BIH for the first frame, we can use it where possible.
1567 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1568 if (!loadmodel->surfmesh.isanimated)
1570 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1571 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1572 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1573 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1574 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1578 void Mod_IDP3_Load(model_t *mod, void *buffer, void *bufferend)
1580 int i, j, k, version, meshvertices, meshtriangles;
1581 unsigned char *data;
1582 msurface_t *surface;
1583 md3modelheader_t *pinmodel;
1584 md3frameinfo_t *pinframe;
1587 skinfile_t *skinfiles;
1589 pinmodel = (md3modelheader_t *)buffer;
1591 if (memcmp(pinmodel->identifier, "IDP3", 4))
1592 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1593 version = LittleLong (pinmodel->version);
1594 if (version != MD3VERSION)
1595 Host_Error ("%s has wrong version number (%i should be %i)",
1596 loadmodel->name, version, MD3VERSION);
1598 skinfiles = Mod_LoadSkinFiles();
1599 if (loadmodel->numskins < 1)
1600 loadmodel->numskins = 1;
1602 loadmodel->modeldatatypestring = "MD3";
1604 loadmodel->type = mod_alias;
1605 loadmodel->Draw = R_Mod_Draw;
1606 loadmodel->DrawDepth = R_Mod_DrawDepth;
1607 loadmodel->DrawDebug = R_Mod_DrawDebug;
1608 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1609 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1610 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1611 loadmodel->DrawLight = R_Mod_DrawLight;
1612 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1613 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1614 loadmodel->PointSuperContents = NULL;
1615 loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1616 loadmodel->synctype = ST_RAND;
1617 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1618 i = LittleLong (pinmodel->flags);
1619 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1621 // set up some global info about the model
1622 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1623 loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1625 // make skinscenes for the skins (no groups)
1626 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1627 for (i = 0;i < loadmodel->numskins;i++)
1629 loadmodel->skinscenes[i].firstframe = i;
1630 loadmodel->skinscenes[i].framecount = 1;
1631 loadmodel->skinscenes[i].loop = true;
1632 loadmodel->skinscenes[i].framerate = 10;
1636 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1637 for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1639 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1640 loadmodel->animscenes[i].firstframe = i;
1641 loadmodel->animscenes[i].framecount = 1;
1642 loadmodel->animscenes[i].framerate = 10;
1643 loadmodel->animscenes[i].loop = true;
1647 loadmodel->num_tagframes = loadmodel->numframes;
1648 loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1649 loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1650 for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1652 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1653 for (j = 0;j < 9;j++)
1654 loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1655 for (j = 0;j < 3;j++)
1656 loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1657 //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);
1663 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)))
1665 if (memcmp(pinmesh->identifier, "IDP3", 4))
1666 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1667 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1668 Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1669 meshvertices += LittleLong(pinmesh->num_vertices);
1670 meshtriangles += LittleLong(pinmesh->num_triangles);
1673 loadmodel->submodelsurfaces_start = 0;
1674 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1675 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1676 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1677 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) + meshvertices * sizeof(float[2]) + meshvertices * loadmodel->numframes * sizeof(md3vertex_t));
1678 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1679 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1680 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1681 loadmodel->surfmesh.num_vertices = meshvertices;
1682 loadmodel->surfmesh.num_triangles = meshtriangles;
1683 loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1684 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1685 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1686 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1687 loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1688 if (meshvertices <= 65536)
1690 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1695 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)))
1697 if (memcmp(pinmesh->identifier, "IDP3", 4))
1698 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1699 loadmodel->modelsurfaces_sorted[i] = i;
1700 surface = loadmodel->data_surfaces + i;
1701 surface->texture = loadmodel->data_textures + i;
1702 surface->num_firsttriangle = meshtriangles;
1703 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1704 surface->num_firstvertex = meshvertices;
1705 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1706 meshvertices += surface->num_vertices;
1707 meshtriangles += surface->num_triangles;
1709 for (j = 0;j < surface->num_triangles * 3;j++)
1711 int e = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1712 loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = e;
1713 if (loadmodel->surfmesh.data_element3s)
1714 loadmodel->surfmesh.data_element3s[j + surface->num_firsttriangle * 3] = e;
1716 for (j = 0;j < surface->num_vertices;j++)
1718 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1719 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1721 for (j = 0;j < loadmodel->numframes;j++)
1723 const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1724 md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1725 for (k = 0;k < surface->num_vertices;k++, in++, out++)
1727 out->origin[0] = LittleShort(in->origin[0]);
1728 out->origin[1] = LittleShort(in->origin[1]);
1729 out->origin[2] = LittleShort(in->origin[2]);
1730 out->pitch = in->pitch;
1735 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1737 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1739 Mod_Alias_MorphMesh_CompileFrames();
1740 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1741 Mod_FreeSkinFiles(skinfiles);
1742 Mod_MakeSortedSurfaces(loadmodel);
1743 if(mod_alias_force_animated.string[0])
1744 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1746 // Always make a BIH for the first frame, we can use it where possible.
1747 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1748 if (!loadmodel->surfmesh.isanimated)
1750 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1751 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1752 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1753 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1754 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1758 void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend)
1760 zymtype1header_t *pinmodel, *pheader;
1761 unsigned char *pbase;
1762 int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1763 float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1764 zymvertex_t *verts, *vertdata;
1768 skinfile_t *skinfiles;
1769 unsigned char *data;
1770 msurface_t *surface;
1772 pinmodel = (zymtype1header_t *)buffer;
1773 pbase = (unsigned char *)buffer;
1774 if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1775 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1776 if (BigLong(pinmodel->type) != 1)
1777 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1779 loadmodel->modeldatatypestring = "ZYM";
1781 loadmodel->type = mod_alias;
1782 loadmodel->synctype = ST_RAND;
1786 pheader->type = BigLong(pinmodel->type);
1787 pheader->filesize = BigLong(pinmodel->filesize);
1788 pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1789 pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1790 pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1791 pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1792 pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1793 pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1794 pheader->radius = BigFloat(pinmodel->radius);
1795 pheader->numverts = BigLong(pinmodel->numverts);
1796 pheader->numtris = BigLong(pinmodel->numtris);
1797 pheader->numshaders = BigLong(pinmodel->numshaders);
1798 pheader->numbones = BigLong(pinmodel->numbones);
1799 pheader->numscenes = BigLong(pinmodel->numscenes);
1800 pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1801 pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1802 pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1803 pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1804 pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1805 pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1806 pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1807 pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1808 pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1809 pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1810 pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1811 pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1812 pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1813 pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1814 pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1815 pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1816 pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1817 pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1819 if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1821 Con_Printf("%s has no geometry\n", loadmodel->name);
1824 if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1826 Con_Printf("%s has no animations\n", loadmodel->name);
1830 loadmodel->Draw = R_Mod_Draw;
1831 loadmodel->DrawDepth = R_Mod_DrawDepth;
1832 loadmodel->DrawDebug = R_Mod_DrawDebug;
1833 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1834 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1835 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1836 loadmodel->DrawLight = R_Mod_DrawLight;
1837 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1838 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1839 loadmodel->PointSuperContents = NULL;
1840 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1842 loadmodel->numframes = pheader->numscenes;
1843 loadmodel->num_surfaces = pheader->numshaders;
1845 skinfiles = Mod_LoadSkinFiles();
1846 if (loadmodel->numskins < 1)
1847 loadmodel->numskins = 1;
1849 // make skinscenes for the skins (no groups)
1850 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1851 for (i = 0;i < loadmodel->numskins;i++)
1853 loadmodel->skinscenes[i].firstframe = i;
1854 loadmodel->skinscenes[i].framecount = 1;
1855 loadmodel->skinscenes[i].loop = true;
1856 loadmodel->skinscenes[i].framerate = 10;
1860 // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1861 modelradius = pheader->radius;
1862 for (i = 0;i < 3;i++)
1864 loadmodel->normalmins[i] = pheader->mins[i];
1865 loadmodel->normalmaxs[i] = pheader->maxs[i];
1866 loadmodel->rotatedmins[i] = -modelradius;
1867 loadmodel->rotatedmaxs[i] = modelradius;
1869 corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1870 corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1871 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1872 if (loadmodel->yawmaxs[0] > modelradius)
1873 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1874 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1875 loadmodel->yawmins[2] = loadmodel->normalmins[2];
1876 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1877 loadmodel->radius = modelradius;
1878 loadmodel->radius2 = modelradius * modelradius;
1880 // go through the lumps, swapping things
1882 //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1883 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1884 scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1885 numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1886 for (i = 0;i < pheader->numscenes;i++)
1888 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1889 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1890 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1891 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1892 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1893 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1894 Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1895 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1896 Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1897 if (loadmodel->animscenes[i].framerate < 0)
1898 Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1902 //zymlump_t lump_bones; // zymbone_t bone[numbones];
1903 loadmodel->num_bones = pheader->numbones;
1904 loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1905 bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1906 for (i = 0;i < pheader->numbones;i++)
1908 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1909 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1910 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1911 if (loadmodel->data_bones[i].parent >= i)
1912 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1915 //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1916 vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1917 bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1918 for (i = 0;i < pheader->numverts;i++)
1920 vertbonecounts[i] = BigLong(bonecount[i]);
1921 if (vertbonecounts[i] != 1)
1922 Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1925 loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1927 meshvertices = pheader->numverts;
1928 meshtriangles = pheader->numtris;
1930 loadmodel->submodelsurfaces_start = 0;
1931 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1932 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1933 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1934 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) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4])) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]));
1935 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1936 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1937 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1938 loadmodel->surfmesh.num_vertices = meshvertices;
1939 loadmodel->surfmesh.num_triangles = meshtriangles;
1940 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1941 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1942 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1943 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1944 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1945 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1946 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1947 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1948 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1949 loadmodel->surfmesh.num_blends = 0;
1950 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
1951 if (loadmodel->surfmesh.num_vertices <= 65536)
1953 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1955 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
1956 loadmodel->surfmesh.data_blendweights = NULL;
1958 //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1959 poses = (float *) (pheader->lump_poses.start + pbase);
1960 // figure out scale of model from root bone, for compatibility with old zmodel versions
1961 tempvec[0] = BigFloat(poses[0]);
1962 tempvec[1] = BigFloat(poses[1]);
1963 tempvec[2] = BigFloat(poses[2]);
1964 modelscale = VectorLength(tempvec);
1966 for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
1968 f = fabs(BigFloat(poses[i]));
1969 biggestorigin = max(biggestorigin, f);
1971 loadmodel->num_posescale = biggestorigin / 32767.0f;
1972 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
1973 for (i = 0;i < numposes;i++)
1975 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
1976 for (j = 0;j < loadmodel->num_bones;j++)
1979 matrix4x4_t posematrix;
1980 for (k = 0;k < 12;k++)
1981 pose[k] = BigFloat(frameposes[j*12+k]);
1982 //if (j < loadmodel->num_bones)
1983 // Con_Printf("%s: bone %i = %f %f %f %f : %f %f %f %f : %f %f %f %f : scale = %f\n", loadmodel->name, j, pose[0], pose[1], pose[2], pose[3], pose[4], pose[5], pose[6], pose[7], pose[8], pose[9], pose[10], pose[11], VectorLength(pose));
1984 // scale child bones to match the root scale
1985 if (loadmodel->data_bones[j].parent >= 0)
1987 pose[3] *= modelscale;
1988 pose[7] *= modelscale;
1989 pose[11] *= modelscale;
1991 // normalize rotation matrix
1992 VectorNormalize(pose + 0);
1993 VectorNormalize(pose + 4);
1994 VectorNormalize(pose + 8);
1995 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
1996 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2000 //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2001 verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2002 vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2003 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2004 // (converting from weight-blending skeletal animation to
2005 // deformation-based skeletal animation)
2006 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2007 for (i = 0;i < loadmodel->num_bones;i++)
2010 for (k = 0;k < 12;k++)
2011 m[k] = BigFloat(poses[i*12+k]);
2012 if (loadmodel->data_bones[i].parent >= 0)
2013 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2015 for (k = 0;k < 12;k++)
2016 bonepose[12*i+k] = m[k];
2018 for (j = 0;j < pheader->numverts;j++)
2020 // this format really should have had a per vertexweight weight value...
2021 // but since it does not, the weighting is completely ignored and
2022 // only one weight is allowed per vertex
2023 int boneindex = BigLong(vertdata[j].bonenum);
2024 const float *m = bonepose + 12 * boneindex;
2025 float relativeorigin[3];
2026 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2027 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2028 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2029 // transform the vertex bone weight into the base mesh
2030 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2031 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2032 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2033 // store the weight as the primary weight on this vertex
2034 loadmodel->surfmesh.blends[j] = boneindex;
2035 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = boneindex;
2036 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2037 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2038 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2039 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = 255;
2040 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2041 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2042 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2045 // normals and tangents are calculated after elements are loaded
2047 //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2048 outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2049 intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2050 for (i = 0;i < pheader->numverts;i++)
2052 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2053 // flip T coordinate for OpenGL
2054 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2057 //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2058 //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2059 //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2061 //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2062 //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)
2063 // byteswap, validate, and swap winding order of tris
2064 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2065 if (pheader->lump_render.length != count)
2066 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2067 renderlist = (int *) (pheader->lump_render.start + pbase);
2068 renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2070 for (i = 0;i < loadmodel->num_surfaces;i++)
2072 int firstvertex, lastvertex;
2073 if (renderlist >= renderlistend)
2074 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2075 count = BigLong(*renderlist);renderlist++;
2076 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2077 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2079 loadmodel->modelsurfaces_sorted[i] = i;
2080 surface = loadmodel->data_surfaces + i;
2081 surface->texture = loadmodel->data_textures + i;
2082 surface->num_firsttriangle = meshtriangles;
2083 surface->num_triangles = count;
2084 meshtriangles += surface->num_triangles;
2086 // load the elements
2087 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2088 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2090 outelements[j*3+2] = BigLong(renderlist[0]);
2091 outelements[j*3+1] = BigLong(renderlist[1]);
2092 outelements[j*3+0] = BigLong(renderlist[2]);
2094 // validate the elements and find the used vertex range
2095 firstvertex = meshvertices;
2097 for (j = 0;j < surface->num_triangles * 3;j++)
2099 if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2100 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2101 firstvertex = min(firstvertex, outelements[j]);
2102 lastvertex = max(lastvertex, outelements[j]);
2104 surface->num_firstvertex = firstvertex;
2105 surface->num_vertices = lastvertex + 1 - firstvertex;
2107 // since zym models do not have named sections, reuse their shader
2108 // name as the section name
2109 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2110 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2112 Mod_FreeSkinFiles(skinfiles);
2113 Mem_Free(vertbonecounts);
2115 Mod_MakeSortedSurfaces(loadmodel);
2117 // compute all the mesh information that was not loaded from the file
2118 if (loadmodel->surfmesh.data_element3s)
2119 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2120 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2121 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2122 Mod_BuildBaseBonePoses();
2123 Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, r_smoothnormals_areaweighting.integer != 0);
2124 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
2125 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2126 if(mod_alias_force_animated.string[0])
2127 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2129 // Always make a BIH for the first frame, we can use it where possible.
2130 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2131 if (!loadmodel->surfmesh.isanimated)
2133 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2134 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2135 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2136 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2137 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2141 void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend)
2143 dpmheader_t *pheader;
2147 unsigned char *pbase;
2148 int i, j, k, meshvertices, meshtriangles;
2149 skinfile_t *skinfiles;
2150 unsigned char *data;
2152 float biggestorigin, tempvec[3], modelscale;
2156 pheader = (dpmheader_t *)buffer;
2157 pbase = (unsigned char *)buffer;
2158 if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2159 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2160 if (BigLong(pheader->type) != 2)
2161 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2163 loadmodel->modeldatatypestring = "DPM";
2165 loadmodel->type = mod_alias;
2166 loadmodel->synctype = ST_RAND;
2169 pheader->type = BigLong(pheader->type);
2170 pheader->filesize = BigLong(pheader->filesize);
2171 pheader->mins[0] = BigFloat(pheader->mins[0]);
2172 pheader->mins[1] = BigFloat(pheader->mins[1]);
2173 pheader->mins[2] = BigFloat(pheader->mins[2]);
2174 pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2175 pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2176 pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2177 pheader->yawradius = BigFloat(pheader->yawradius);
2178 pheader->allradius = BigFloat(pheader->allradius);
2179 pheader->num_bones = BigLong(pheader->num_bones);
2180 pheader->num_meshs = BigLong(pheader->num_meshs);
2181 pheader->num_frames = BigLong(pheader->num_frames);
2182 pheader->ofs_bones = BigLong(pheader->ofs_bones);
2183 pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2184 pheader->ofs_frames = BigLong(pheader->ofs_frames);
2186 if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2188 Con_Printf("%s has no geometry\n", loadmodel->name);
2191 if (pheader->num_frames < 1)
2193 Con_Printf("%s has no frames\n", loadmodel->name);
2197 loadmodel->Draw = R_Mod_Draw;
2198 loadmodel->DrawDepth = R_Mod_DrawDepth;
2199 loadmodel->DrawDebug = R_Mod_DrawDebug;
2200 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2201 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2202 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2203 loadmodel->DrawLight = R_Mod_DrawLight;
2204 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2205 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2206 loadmodel->PointSuperContents = NULL;
2207 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2210 // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2211 for (i = 0;i < 3;i++)
2213 loadmodel->normalmins[i] = pheader->mins[i];
2214 loadmodel->normalmaxs[i] = pheader->maxs[i];
2215 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2216 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2217 loadmodel->rotatedmins[i] = -pheader->allradius;
2218 loadmodel->rotatedmaxs[i] = pheader->allradius;
2220 loadmodel->radius = pheader->allradius;
2221 loadmodel->radius2 = pheader->allradius * pheader->allradius;
2223 // load external .skin files if present
2224 skinfiles = Mod_LoadSkinFiles();
2225 if (loadmodel->numskins < 1)
2226 loadmodel->numskins = 1;
2231 // gather combined statistics from the meshes
2232 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2233 for (i = 0;i < (int)pheader->num_meshs;i++)
2235 int numverts = BigLong(dpmmesh->num_verts);
2236 meshvertices += numverts;
2237 meshtriangles += BigLong(dpmmesh->num_tris);
2241 loadmodel->numframes = pheader->num_frames;
2242 loadmodel->num_bones = pheader->num_bones;
2243 loadmodel->num_poses = loadmodel->numframes;
2244 loadmodel->submodelsurfaces_start = 0;
2245 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = pheader->num_meshs;
2246 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2247 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2248 // do most allocations as one merged chunk
2249 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) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4])) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t));
2250 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2251 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2252 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2253 loadmodel->surfmesh.num_vertices = meshvertices;
2254 loadmodel->surfmesh.num_triangles = meshtriangles;
2255 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2256 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2257 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2258 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2259 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2260 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2261 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2262 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2263 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2264 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2265 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2266 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2267 loadmodel->surfmesh.num_blends = 0;
2268 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2269 if (meshvertices <= 65536)
2271 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2273 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2274 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2276 for (i = 0;i < loadmodel->numskins;i++)
2278 loadmodel->skinscenes[i].firstframe = i;
2279 loadmodel->skinscenes[i].framecount = 1;
2280 loadmodel->skinscenes[i].loop = true;
2281 loadmodel->skinscenes[i].framerate = 10;
2284 // load the bone info
2285 bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2286 for (i = 0;i < loadmodel->num_bones;i++)
2288 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2289 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2290 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2291 if (loadmodel->data_bones[i].parent >= i)
2292 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2296 frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2297 // figure out scale of model from root bone, for compatibility with old dpmodel versions
2298 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2299 tempvec[0] = BigFloat(poses[0]);
2300 tempvec[1] = BigFloat(poses[1]);
2301 tempvec[2] = BigFloat(poses[2]);
2302 modelscale = VectorLength(tempvec);
2304 for (i = 0;i < loadmodel->numframes;i++)
2306 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2307 loadmodel->animscenes[i].firstframe = i;
2308 loadmodel->animscenes[i].framecount = 1;
2309 loadmodel->animscenes[i].loop = true;
2310 loadmodel->animscenes[i].framerate = 10;
2311 // load the bone poses for this frame
2312 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2313 for (j = 0;j < loadmodel->num_bones*12;j++)
2315 f = fabs(BigFloat(poses[j]));
2316 biggestorigin = max(biggestorigin, f);
2318 // stuff not processed here: mins, maxs, yawradius, allradius
2320 loadmodel->num_posescale = biggestorigin / 32767.0f;
2321 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2322 for (i = 0;i < loadmodel->numframes;i++)
2324 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2325 for (j = 0;j < loadmodel->num_bones;j++)
2328 matrix4x4_t posematrix;
2329 for (k = 0;k < 12;k++)
2330 pose[k] = BigFloat(frameposes[j*12+k]);
2331 // scale child bones to match the root scale
2332 if (loadmodel->data_bones[j].parent >= 0)
2334 pose[3] *= modelscale;
2335 pose[7] *= modelscale;
2336 pose[11] *= modelscale;
2338 // normalize rotation matrix
2339 VectorNormalize(pose + 0);
2340 VectorNormalize(pose + 4);
2341 VectorNormalize(pose + 8);
2342 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2343 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2347 // load the meshes now
2348 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2351 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2352 // (converting from weight-blending skeletal animation to
2353 // deformation-based skeletal animation)
2354 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2355 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2356 for (i = 0;i < loadmodel->num_bones;i++)
2359 for (k = 0;k < 12;k++)
2360 m[k] = BigFloat(poses[i*12+k]);
2361 if (loadmodel->data_bones[i].parent >= 0)
2362 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2364 for (k = 0;k < 12;k++)
2365 bonepose[12*i+k] = m[k];
2367 for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2369 const int *inelements;
2371 unsigned short *outelement3s;
2372 const float *intexcoord;
2373 msurface_t *surface;
2375 loadmodel->modelsurfaces_sorted[i] = i;
2376 surface = loadmodel->data_surfaces + i;
2377 surface->texture = loadmodel->data_textures + i;
2378 surface->num_firsttriangle = meshtriangles;
2379 surface->num_triangles = BigLong(dpmmesh->num_tris);
2380 surface->num_firstvertex = meshvertices;
2381 surface->num_vertices = BigLong(dpmmesh->num_verts);
2382 meshvertices += surface->num_vertices;
2383 meshtriangles += surface->num_triangles;
2385 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2386 outelement3i = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2387 outelement3s = loadmodel->surfmesh.data_element3s ? loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3 : NULL;
2388 for (j = 0;j < surface->num_triangles;j++)
2390 // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2391 outelement3i[j * 3 + 0] = surface->num_firstvertex + BigLong(inelements[j * 3 + 2]);
2392 outelement3i[j * 3 + 1] = surface->num_firstvertex + BigLong(inelements[j * 3 + 1]);
2393 outelement3i[j * 3 + 2] = surface->num_firstvertex + BigLong(inelements[j * 3 + 0]);
2396 outelement3s[j * 3 + 0] = outelement3i[j * 3 + 0];
2397 outelement3s[j * 3 + 1] = outelement3i[j * 3 + 1];
2398 outelement3s[j * 3 + 2] = outelement3i[j * 3 + 2];
2402 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2403 for (j = 0;j < surface->num_vertices*2;j++)
2404 loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2406 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2407 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2409 int weightindex[4] = { 0, 0, 0, 0 };
2410 float weightinfluence[4] = { 0, 0, 0, 0 };
2412 int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2413 data += sizeof(dpmvertex_t);
2414 for (k = 0;k < numweights;k++)
2416 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2417 int boneindex = BigLong(vert->bonenum);
2418 const float *m = bonepose + 12 * boneindex;
2419 float influence = BigFloat(vert->influence);
2420 float relativeorigin[3], relativenormal[3];
2421 relativeorigin[0] = BigFloat(vert->origin[0]);
2422 relativeorigin[1] = BigFloat(vert->origin[1]);
2423 relativeorigin[2] = BigFloat(vert->origin[2]);
2424 relativenormal[0] = BigFloat(vert->normal[0]);
2425 relativenormal[1] = BigFloat(vert->normal[1]);
2426 relativenormal[2] = BigFloat(vert->normal[2]);
2427 // blend the vertex bone weights into the base mesh
2428 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2429 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2430 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2431 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2432 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2433 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2436 // store the first (and often only) weight
2437 weightinfluence[0] = influence;
2438 weightindex[0] = boneindex;
2442 // sort the new weight into this vertex's weight table
2443 // (which only accepts up to 4 bones per vertex)
2444 for (l = 0;l < 4;l++)
2446 if (weightinfluence[l] < influence)
2448 // move weaker influence weights out of the way first
2450 for (l2 = 3;l2 > l;l2--)
2452 weightinfluence[l2] = weightinfluence[l2-1];
2453 weightindex[l2] = weightindex[l2-1];
2455 // store the new weight
2456 weightinfluence[l] = influence;
2457 weightindex[l] = boneindex;
2462 data += sizeof(dpmbonevert_t);
2464 loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2465 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = weightindex[0];
2466 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2467 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2468 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2469 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
2470 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2471 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2472 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2475 // since dpm models do not have named sections, reuse their shader name as the section name
2476 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2478 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2480 if (loadmodel->surfmesh.num_blends < meshvertices)
2481 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2483 Mod_FreeSkinFiles(skinfiles);
2484 Mod_MakeSortedSurfaces(loadmodel);
2486 // compute all the mesh information that was not loaded from the file
2487 Mod_BuildBaseBonePoses();
2488 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
2489 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2490 if(mod_alias_force_animated.string[0])
2491 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2493 // Always make a BIH for the first frame, we can use it where possible.
2494 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2495 if (!loadmodel->surfmesh.isanimated)
2497 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2498 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2499 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2500 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2501 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2505 // no idea why PSK/PSA files contain weird quaternions but they do...
2506 #define PSKQUATNEGATIONS
2507 void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
2509 int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2510 int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2511 fs_offset_t filesize;
2516 pskboneinfo_t *bones;
2517 pskrawweights_t *rawweights;
2518 //pskboneinfo_t *animbones;
2519 pskaniminfo_t *anims;
2520 pskanimkeys_t *animkeys;
2521 void *animfilebuffer, *animbuffer, *animbufferend;
2522 unsigned char *data;
2524 skinfile_t *skinfiles;
2525 char animname[MAX_QPATH];
2527 float biggestorigin;
2529 pchunk = (pskchunk_t *)buffer;
2530 if (strcmp(pchunk->id, "ACTRHEAD"))
2531 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2533 loadmodel->modeldatatypestring = "PSK";
2535 loadmodel->type = mod_alias;
2536 loadmodel->Draw = R_Mod_Draw;
2537 loadmodel->DrawDepth = R_Mod_DrawDepth;
2538 loadmodel->DrawDebug = R_Mod_DrawDebug;
2539 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2540 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2541 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2542 loadmodel->DrawLight = R_Mod_DrawLight;
2543 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2544 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2545 loadmodel->PointSuperContents = NULL;
2546 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2547 loadmodel->synctype = ST_RAND;
2549 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2550 strlcat(animname, ".psa", sizeof(animname));
2551 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2552 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2554 animbufferend = animbuffer;
2573 while (buffer < bufferend)
2575 pchunk = (pskchunk_t *)buffer;
2576 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2577 version = LittleLong(pchunk->version);
2578 recordsize = LittleLong(pchunk->recordsize);
2579 numrecords = LittleLong(pchunk->numrecords);
2580 if (developer_extra.integer)
2581 Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2582 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2583 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);
2584 if (!strcmp(pchunk->id, "ACTRHEAD"))
2588 else if (!strcmp(pchunk->id, "PNTS0000"))
2591 if (recordsize != sizeof(*p))
2592 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2593 // byteswap in place and keep the pointer
2594 numpnts = numrecords;
2595 pnts = (pskpnts_t *)buffer;
2596 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2598 p->origin[0] = LittleFloat(p->origin[0]);
2599 p->origin[1] = LittleFloat(p->origin[1]);
2600 p->origin[2] = LittleFloat(p->origin[2]);
2604 else if (!strcmp(pchunk->id, "VTXW0000"))
2607 if (recordsize != sizeof(*p))
2608 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2609 // byteswap in place and keep the pointer
2610 numvtxw = numrecords;
2611 vtxw = (pskvtxw_t *)buffer;
2612 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2614 p->pntsindex = LittleShort(p->pntsindex);
2615 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2616 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2617 if (p->pntsindex >= numpnts)
2619 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2625 else if (!strcmp(pchunk->id, "FACE0000"))
2628 if (recordsize != sizeof(*p))
2629 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2630 // byteswap in place and keep the pointer
2631 numfaces = numrecords;
2632 faces = (pskface_t *)buffer;
2633 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2635 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2636 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2637 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2638 p->group = LittleLong(p->group);
2639 if (p->vtxwindex[0] >= numvtxw)
2641 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2642 p->vtxwindex[0] = 0;
2644 if (p->vtxwindex[1] >= numvtxw)
2646 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2647 p->vtxwindex[1] = 0;
2649 if (p->vtxwindex[2] >= numvtxw)
2651 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2652 p->vtxwindex[2] = 0;
2657 else if (!strcmp(pchunk->id, "MATT0000"))
2660 if (recordsize != sizeof(*p))
2661 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2662 // byteswap in place and keep the pointer
2663 nummatts = numrecords;
2664 matts = (pskmatt_t *)buffer;
2665 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2671 else if (!strcmp(pchunk->id, "REFSKELT"))
2674 if (recordsize != sizeof(*p))
2675 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2676 // byteswap in place and keep the pointer
2677 numbones = numrecords;
2678 bones = (pskboneinfo_t *)buffer;
2679 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2681 p->numchildren = LittleLong(p->numchildren);
2682 p->parent = LittleLong(p->parent);
2683 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2684 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2685 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2686 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2687 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2688 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2689 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2690 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2691 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2692 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2693 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2694 #ifdef PSKQUATNEGATIONS
2697 p->basepose.quat[0] *= -1;
2698 p->basepose.quat[1] *= -1;
2699 p->basepose.quat[2] *= -1;
2703 p->basepose.quat[0] *= 1;
2704 p->basepose.quat[1] *= -1;
2705 p->basepose.quat[2] *= 1;
2708 if (p->parent < 0 || p->parent >= numbones)
2710 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2716 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2719 if (recordsize != sizeof(*p))
2720 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2721 // byteswap in place and keep the pointer
2722 numrawweights = numrecords;
2723 rawweights = (pskrawweights_t *)buffer;
2724 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2726 p->weight = LittleFloat(p->weight);
2727 p->pntsindex = LittleLong(p->pntsindex);
2728 p->boneindex = LittleLong(p->boneindex);
2729 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2731 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2734 if (p->boneindex < 0 || p->boneindex >= numbones)
2736 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2744 while (animbuffer < animbufferend)
2746 pchunk = (pskchunk_t *)animbuffer;
2747 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2748 version = LittleLong(pchunk->version);
2749 recordsize = LittleLong(pchunk->recordsize);
2750 numrecords = LittleLong(pchunk->numrecords);
2751 if (developer_extra.integer)
2752 Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2753 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2754 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);
2755 if (!strcmp(pchunk->id, "ANIMHEAD"))
2759 else if (!strcmp(pchunk->id, "BONENAMES"))
2762 if (recordsize != sizeof(*p))
2763 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2764 // byteswap in place and keep the pointer
2765 numanimbones = numrecords;
2766 //animbones = (pskboneinfo_t *)animbuffer;
2767 // NOTE: supposedly psa does not need to match the psk model, the
2768 // bones missing from the psa would simply use their base
2769 // positions from the psk, but this is hard for me to implement
2770 // and people can easily make animations that match.
2771 if (numanimbones != numbones)
2772 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2773 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2775 p->numchildren = LittleLong(p->numchildren);
2776 p->parent = LittleLong(p->parent);
2777 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2778 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2779 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2780 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2781 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2782 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2783 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2784 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2785 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2786 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2787 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2788 #ifdef PSKQUATNEGATIONS
2791 p->basepose.quat[0] *= -1;
2792 p->basepose.quat[1] *= -1;
2793 p->basepose.quat[2] *= -1;
2797 p->basepose.quat[0] *= 1;
2798 p->basepose.quat[1] *= -1;
2799 p->basepose.quat[2] *= 1;
2802 if (p->parent < 0 || p->parent >= numanimbones)
2804 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2807 // check that bones are the same as in the base
2808 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2809 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2813 else if (!strcmp(pchunk->id, "ANIMINFO"))
2816 if (recordsize != sizeof(*p))
2817 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2818 // byteswap in place and keep the pointer
2819 numanims = numrecords;
2820 anims = (pskaniminfo_t *)animbuffer;
2821 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2823 p->numbones = LittleLong(p->numbones);
2824 p->playtime = LittleFloat(p->playtime);
2825 p->fps = LittleFloat(p->fps);
2826 p->firstframe = LittleLong(p->firstframe);
2827 p->numframes = LittleLong(p->numframes);
2828 if (p->numbones != numbones)
2829 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2833 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2836 if (recordsize != sizeof(*p))
2837 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2838 numanimkeys = numrecords;
2839 animkeys = (pskanimkeys_t *)animbuffer;
2840 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2842 p->origin[0] = LittleFloat(p->origin[0]);
2843 p->origin[1] = LittleFloat(p->origin[1]);
2844 p->origin[2] = LittleFloat(p->origin[2]);
2845 p->quat[0] = LittleFloat(p->quat[0]);
2846 p->quat[1] = LittleFloat(p->quat[1]);
2847 p->quat[2] = LittleFloat(p->quat[2]);
2848 p->quat[3] = LittleFloat(p->quat[3]);
2849 p->frametime = LittleFloat(p->frametime);
2850 #ifdef PSKQUATNEGATIONS
2851 if (index % numbones)
2866 // TODO: allocate bonepose stuff
2869 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2872 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2873 Host_Error("%s: missing required chunks", loadmodel->name);
2877 loadmodel->numframes = 0;
2878 for (index = 0;index < numanims;index++)
2879 loadmodel->numframes += anims[index].numframes;
2880 if (numanimkeys != numbones * loadmodel->numframes)
2881 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2884 loadmodel->numframes = loadmodel->num_poses = 1;
2886 meshvertices = numvtxw;
2887 meshtriangles = numfaces;
2889 // load external .skin files if present
2890 skinfiles = Mod_LoadSkinFiles();
2891 if (loadmodel->numskins < 1)
2892 loadmodel->numskins = 1;
2893 loadmodel->num_bones = numbones;
2894 loadmodel->num_poses = loadmodel->numframes;
2895 loadmodel->submodelsurfaces_start = 0;
2896 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = nummatts;
2897 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2898 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2899 loadmodel->surfmesh.num_vertices = meshvertices;
2900 loadmodel->surfmesh.num_triangles = meshtriangles;
2901 // do most allocations as one merged chunk
2902 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_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned short) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t) + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0);
2903 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2904 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2905 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2906 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2907 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2908 loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2909 loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2910 loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2911 loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2912 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2913 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2914 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2915 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2916 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2917 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2918 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2919 loadmodel->surfmesh.num_blends = 0;
2920 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2921 if (loadmodel->surfmesh.num_vertices <= 65536)
2923 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2925 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2926 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2928 for (i = 0;i < loadmodel->numskins;i++)
2930 loadmodel->skinscenes[i].firstframe = i;
2931 loadmodel->skinscenes[i].framecount = 1;
2932 loadmodel->skinscenes[i].loop = true;
2933 loadmodel->skinscenes[i].framerate = 10;
2937 for (index = 0, i = 0;index < nummatts;index++)
2939 // since psk models do not have named sections, reuse their shader name as the section name
2940 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2941 loadmodel->modelsurfaces_sorted[index] = index;
2942 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2943 loadmodel->data_surfaces[index].num_firstvertex = 0;
2944 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2947 // copy over the vertex locations and texcoords
2948 for (index = 0;index < numvtxw;index++)
2950 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2951 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2952 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2953 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2954 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
2957 // loading the faces is complicated because we need to sort them into surfaces by mattindex
2958 for (index = 0;index < numfaces;index++)
2959 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
2960 for (index = 0, i = 0;index < nummatts;index++)
2962 loadmodel->data_surfaces[index].num_firsttriangle = i;
2963 i += loadmodel->data_surfaces[index].num_triangles;
2964 loadmodel->data_surfaces[index].num_triangles = 0;
2966 for (index = 0;index < numfaces;index++)
2968 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
2969 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
2970 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
2971 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
2974 // copy over the bones
2975 for (index = 0;index < numbones;index++)
2977 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
2978 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
2979 if (loadmodel->data_bones[index].parent >= index)
2980 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
2983 // convert the basepose data
2984 if (loadmodel->num_bones)
2987 matrix4x4_t *basebonepose;
2988 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
2989 matrix4x4_t bonematrix;
2990 matrix4x4_t tempbonematrix;
2991 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
2992 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
2994 Matrix4x4_FromOriginQuat(&bonematrix, bones[boneindex].basepose.origin[0], bones[boneindex].basepose.origin[1], bones[boneindex].basepose.origin[2], bones[boneindex].basepose.quat[0], bones[boneindex].basepose.quat[1], bones[boneindex].basepose.quat[2], bones[boneindex].basepose.quat[3]);
2995 if (loadmodel->data_bones[boneindex].parent >= 0)
2997 tempbonematrix = bonematrix;
2998 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3000 basebonepose[boneindex] = bonematrix;
3001 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3002 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3004 Mem_Free(basebonepose);
3007 // sort the psk point weights into the vertex weight tables
3008 // (which only accept up to 4 bones per vertex)
3009 for (index = 0;index < numvtxw;index++)
3011 int weightindex[4] = { 0, 0, 0, 0 };
3012 float weightinfluence[4] = { 0, 0, 0, 0 };
3014 for (j = 0;j < numrawweights;j++)
3016 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3018 int boneindex = rawweights[j].boneindex;
3019 float influence = rawweights[j].weight;
3020 for (l = 0;l < 4;l++)
3022 if (weightinfluence[l] < influence)
3024 // move lower influence weights out of the way first
3026 for (l2 = 3;l2 > l;l2--)
3028 weightinfluence[l2] = weightinfluence[l2-1];
3029 weightindex[l2] = weightindex[l2-1];
3031 // store the new weight
3032 weightinfluence[l] = influence;
3033 weightindex[l] = boneindex;
3039 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3040 loadmodel->surfmesh.data_skeletalindex4ub[index*4 ] = weightindex[0];
3041 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3042 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3043 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3044 loadmodel->surfmesh.data_skeletalweight4ub[index*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
3045 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3046 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3047 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3049 if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3050 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3052 // set up the animscenes based on the anims
3055 for (index = 0, i = 0;index < numanims;index++)
3057 for (j = 0;j < anims[index].numframes;j++, i++)
3059 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3060 loadmodel->animscenes[i].firstframe = i;
3061 loadmodel->animscenes[i].framecount = 1;
3062 loadmodel->animscenes[i].loop = true;
3063 loadmodel->animscenes[i].framerate = anims[index].fps;
3066 // calculate the scaling value for bone origins so they can be compressed to short
3068 for (index = 0;index < numanimkeys;index++)
3070 pskanimkeys_t *k = animkeys + index;
3071 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3072 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3073 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3075 loadmodel->num_posescale = biggestorigin / 32767.0f;
3076 if (loadmodel->num_posescale == 0) // don't divide by zero
3077 loadmodel->num_posescale = 1.0;
3078 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3080 // load the poses from the animkeys
3081 for (index = 0;index < numanimkeys;index++)
3083 pskanimkeys_t *k = animkeys + index;
3085 Vector4Copy(k->quat, quat);
3087 Vector4Negate(quat, quat);
3088 Vector4Normalize2(quat, quat);
3089 // compress poses to the short[7] format for longterm storage
3090 loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3091 loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3092 loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3093 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3094 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3095 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3096 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3101 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3102 loadmodel->animscenes[0].firstframe = 0;
3103 loadmodel->animscenes[0].framecount = 1;
3104 loadmodel->animscenes[0].loop = true;
3105 loadmodel->animscenes[0].framerate = 10;
3107 // calculate the scaling value for bone origins so they can be compressed to short
3109 for (index = 0;index < numbones;index++)
3111 pskboneinfo_t *p = bones + index;
3112 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3113 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3114 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3116 loadmodel->num_posescale = biggestorigin / 32767.0f;
3117 if (loadmodel->num_posescale == 0) // don't divide by zero
3118 loadmodel->num_posescale = 1.0;
3119 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3121 // load the basepose as a frame
3122 for (index = 0;index < numbones;index++)
3124 pskboneinfo_t *p = bones + index;
3126 Vector4Copy(p->basepose.quat, quat);
3128 Vector4Negate(quat, quat);
3129 Vector4Normalize2(quat, quat);
3130 // compress poses to the short[7] format for longterm storage
3131 loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3132 loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3133 loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3134 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3135 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3136 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3137 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3141 Mod_FreeSkinFiles(skinfiles);
3143 Mem_Free(animfilebuffer);
3144 Mod_MakeSortedSurfaces(loadmodel);
3146 // compute all the mesh information that was not loaded from the file
3147 // TODO: honor smoothing groups somehow?
3148 if (loadmodel->surfmesh.data_element3s)
3149 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3150 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3151 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3152 Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, r_smoothnormals_areaweighting.integer != 0);
3153 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
3154 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3155 if(mod_alias_force_animated.string[0])
3156 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3158 // Always make a BIH for the first frame, we can use it where possible.
3159 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3160 if (!loadmodel->surfmesh.isanimated)
3162 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3163 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3164 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3165 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3166 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3170 void Mod_INTERQUAKEMODEL_Load(model_t *mod, void *buffer, void *bufferend)
3172 unsigned char *data;
3174 const unsigned char *pbase, *pend;
3176 skinfile_t *skinfiles;
3177 int i, j, k, meshvertices, meshtriangles;
3178 float biggestorigin;
3179 const unsigned int *inelements;
3181 float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3182 // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3183 const float *vnormal = NULL;
3184 const float *vposition = NULL;
3185 const float *vtangent = NULL;
3186 const float *vtexcoord = NULL;
3187 const float *vcolor4f = NULL;
3188 const unsigned char *vblendindexes = NULL;
3189 const unsigned char *vblendweights = NULL;
3190 const unsigned char *vcolor4ub = NULL;
3191 const unsigned short *framedata = NULL;
3192 // temporary memory allocations (because the data in the file may be misaligned)
3193 iqmanim_t *anims = NULL;
3194 iqmbounds_t *bounds = NULL;
3195 iqmjoint1_t *joint1 = NULL;
3196 iqmjoint_t *joint = NULL;
3197 iqmmesh_t *meshes = NULL;
3198 iqmpose1_t *pose1 = NULL;
3199 iqmpose_t *pose = NULL;
3200 iqmvertexarray_t *vas = NULL;
3202 pbase = (unsigned char *)buffer;
3203 pend = (unsigned char *)bufferend;
3205 if (pbase + sizeof(iqmheader_t) > pend)
3206 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3208 // copy struct (otherwise it may be misaligned)
3209 // LadyHavoc: okay it's definitely not misaligned here, but for consistency...
3210 memcpy(&header, pbase, sizeof(iqmheader_t));
3212 if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3213 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3214 if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3215 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3217 loadmodel->modeldatatypestring = "IQM";
3219 loadmodel->type = mod_alias;
3220 loadmodel->synctype = ST_RAND;
3223 header.version = LittleLong(header.version);
3224 header.filesize = LittleLong(header.filesize);
3225 header.flags = LittleLong(header.flags);
3226 header.num_text = LittleLong(header.num_text);
3227 header.ofs_text = LittleLong(header.ofs_text);
3228 header.num_meshes = LittleLong(header.num_meshes);
3229 header.ofs_meshes = LittleLong(header.ofs_meshes);
3230 header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3231 header.num_vertexes = LittleLong(header.num_vertexes);
3232 header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3233 header.num_triangles = LittleLong(header.num_triangles);
3234 header.ofs_triangles = LittleLong(header.ofs_triangles);
3235 header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3236 header.num_joints = LittleLong(header.num_joints);
3237 header.ofs_joints = LittleLong(header.ofs_joints);
3238 header.num_poses = LittleLong(header.num_poses);
3239 header.ofs_poses = LittleLong(header.ofs_poses);
3240 header.num_anims = LittleLong(header.num_anims);
3241 header.ofs_anims = LittleLong(header.ofs_anims);
3242 header.num_frames = LittleLong(header.num_frames);
3243 header.num_framechannels = LittleLong(header.num_framechannels);
3244 header.ofs_frames = LittleLong(header.ofs_frames);
3245 header.ofs_bounds = LittleLong(header.ofs_bounds);
3246 header.num_comment = LittleLong(header.num_comment);
3247 header.ofs_comment = LittleLong(header.ofs_comment);
3248 header.num_extensions = LittleLong(header.num_extensions);
3249 header.ofs_extensions = LittleLong(header.ofs_extensions);
3251 if (header.version == 1)
3253 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3254 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3256 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3262 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3263 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3265 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3269 if (pbase + header.ofs_text + header.num_text > pend ||
3270 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3271 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3272 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3273 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3274 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3275 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3276 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3277 pbase + header.ofs_comment + header.num_comment > pend)
3279 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3283 // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3284 if (header.num_vertexarrays)
3285 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3286 if (header.num_anims)
3287 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3288 if (header.ofs_bounds)
3289 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3290 if (header.num_meshes)
3291 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3293 for (i = 0;i < (int)header.num_vertexarrays;i++)
3295 iqmvertexarray_t va;
3297 va.type = LittleLong(vas[i].type);
3298 va.flags = LittleLong(vas[i].flags);
3299 va.format = LittleLong(vas[i].format);
3300 va.size = LittleLong(vas[i].size);
3301 va.offset = LittleLong(vas[i].offset);
3302 vsize = header.num_vertexes*va.size;
3305 case IQM_FLOAT: vsize *= sizeof(float); break;
3306 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3309 if (pbase + va.offset + vsize > pend)
3311 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3315 if (va.format == IQM_FLOAT && va.size == 3)
3316 vposition = (const float *)(pbase + va.offset);
3319 if (va.format == IQM_FLOAT && va.size == 2)
3320 vtexcoord = (const float *)(pbase + va.offset);
3323 if (va.format == IQM_FLOAT && va.size == 3)
3324 vnormal = (const float *)(pbase + va.offset);
3327 if (va.format == IQM_FLOAT && va.size == 4)
3328 vtangent = (const float *)(pbase + va.offset);
3330 case IQM_BLENDINDEXES:
3331 if (va.format == IQM_UBYTE && va.size == 4)
3332 vblendindexes = (const unsigned char *)(pbase + va.offset);
3334 case IQM_BLENDWEIGHTS:
3335 if (va.format == IQM_UBYTE && va.size == 4)
3336 vblendweights = (const unsigned char *)(pbase + va.offset);
3339 if (va.format == IQM_FLOAT && va.size == 4)
3340 vcolor4f = (const float *)(pbase + va.offset);
3341 if (va.format == IQM_UBYTE && va.size == 4)
3342 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3346 if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3348 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3352 text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3354 loadmodel->Draw = R_Mod_Draw;
3355 loadmodel->DrawDepth = R_Mod_DrawDepth;
3356 loadmodel->DrawDebug = R_Mod_DrawDebug;
3357 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
3358 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
3359 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
3360 loadmodel->DrawLight = R_Mod_DrawLight;
3361 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3362 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3363 loadmodel->PointSuperContents = NULL;
3364 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3366 // load external .skin files if present
3367 skinfiles = Mod_LoadSkinFiles();
3368 if (loadmodel->numskins < 1)
3369 loadmodel->numskins = 1;
3371 loadmodel->numframes = max(header.num_anims, 1);
3372 loadmodel->num_bones = header.num_joints;
3373 loadmodel->num_poses = max(header.num_frames, 1);
3374 loadmodel->submodelsurfaces_start = 0;
3375 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = header.num_meshes;
3376 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3377 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3379 meshvertices = header.num_vertexes;
3380 meshtriangles = header.num_triangles;
3382 // do most allocations as one merged chunk
3383 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) + meshvertices * (sizeof(float[14]) + (vcolor4f || vcolor4ub ? sizeof(float[4]) : 0)) + (vblendindexes && vblendweights ? meshvertices * (sizeof(unsigned short) + sizeof(unsigned char[2][4])) : 0) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t));
3384 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3385 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3386 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3387 loadmodel->surfmesh.num_vertices = meshvertices;
3388 loadmodel->surfmesh.num_triangles = meshtriangles;
3389 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3390 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3391 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3392 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3393 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3394 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3395 if (vcolor4f || vcolor4ub)
3397 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3399 if (vblendindexes && vblendweights)
3401 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3402 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3404 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3405 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3406 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3407 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3408 if (vblendindexes && vblendweights)
3410 loadmodel->surfmesh.num_blends = 0;
3411 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3413 if (meshvertices <= 65536)
3415 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3417 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3418 if (vblendindexes && vblendweights)
3419 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3421 for (i = 0;i < loadmodel->numskins;i++)
3423 loadmodel->skinscenes[i].firstframe = i;
3424 loadmodel->skinscenes[i].framecount = 1;
3425 loadmodel->skinscenes[i].loop = true;
3426 loadmodel->skinscenes[i].framerate = 10;
3429 // load the bone info
3430 if (header.version == 1)
3432 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3433 if (loadmodel->num_bones)
3434 joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3435 for (i = 0;i < loadmodel->num_bones;i++)
3437 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3438 joint1[i].name = LittleLong(injoint1[i].name);
3439 joint1[i].parent = LittleLong(injoint1[i].parent);
3440 for (j = 0;j < 3;j++)
3442 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3443 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3444 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3446 strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3447 loadmodel->data_bones[i].parent = joint1[i].parent;
3448 if (loadmodel->data_bones[i].parent >= i)
3449 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3450 Matrix4x4_FromDoom3Joint(&relbase, joint1[i].origin[0], joint1[i].origin[1], joint1[i].origin[2], joint1[i].rotation[0], joint1[i].rotation[1], joint1[i].rotation[2]);
3451 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3452 if (loadmodel->data_bones[i].parent >= 0)
3454 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3455 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3456 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3458 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3463 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3464 if (header.num_joints)
3465 joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3466 for (i = 0;i < loadmodel->num_bones;i++)
3468 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3469 joint[i].name = LittleLong(injoint[i].name);
3470 joint[i].parent = LittleLong(injoint[i].parent);
3471 for (j = 0;j < 3;j++)
3473 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3474 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3475 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3477 joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3478 strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3479 loadmodel->data_bones[i].parent = joint[i].parent;
3480 if (loadmodel->data_bones[i].parent >= i)
3481 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3482 if (joint[i].rotation[3] > 0)
3483 Vector4Negate(joint[i].rotation, joint[i].rotation);
3484 Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3485 Matrix4x4_FromDoom3Joint(&relbase, joint[i].origin[0], joint[i].origin[1], joint[i].origin[2], joint[i].rotation[0], joint[i].rotation[1], joint[i].rotation[2]);
3486 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3487 if (loadmodel->data_bones[i].parent >= 0)
3489 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3490 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3491 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3493 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3497 // set up the animscenes based on the anims
3498 for (i = 0;i < (int)header.num_anims;i++)
3501 anim.name = LittleLong(anims[i].name);
3502 anim.first_frame = LittleLong(anims[i].first_frame);
3503 anim.num_frames = LittleLong(anims[i].num_frames);
3504 anim.framerate = LittleFloat(anims[i].framerate);
3505 anim.flags = LittleLong(anims[i].flags);
3506 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3507 loadmodel->animscenes[i].firstframe = anim.first_frame;
3508 loadmodel->animscenes[i].framecount = anim.num_frames;
3509 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3510 loadmodel->animscenes[i].framerate = anim.framerate;
3512 if (header.num_anims <= 0)
3514 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3515 loadmodel->animscenes[0].firstframe = 0;
3516 loadmodel->animscenes[0].framecount = 1;
3517 loadmodel->animscenes[0].loop = true;
3518 loadmodel->animscenes[0].framerate = 10;
3521 loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3522 if(mod_alias_force_animated.string[0])
3523 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3526 if (header.version == 1)
3528 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3529 if (header.num_poses)
3530 pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3531 for (i = 0;i < (int)header.num_poses;i++)
3534 pose1[i].parent = LittleLong(inpose1[i].parent);
3535 pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3536 for (j = 0;j < 9;j++)
3538 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3539 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3541 f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3542 f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3543 f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3544 f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3545 f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3546 f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3548 if (header.num_frames <= 0)
3550 for (i = 0;i < loadmodel->num_bones;i++)
3553 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3554 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3555 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3561 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3562 if (header.num_poses)
3563 pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3564 for (i = 0;i < (int)header.num_poses;i++)
3567 pose[i].parent = LittleLong(inpose[i].parent);
3568 pose[i].channelmask = LittleLong(inpose[i].channelmask);
3569 for (j = 0;j < 10;j++)
3571 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3572 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3574 f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3575 f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3576 f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3577 f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3578 f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3579 f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3581 if (header.num_frames <= 0)
3583 for (i = 0;i < loadmodel->num_bones;i++)
3586 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3587 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3588 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3592 loadmodel->num_posescale = biggestorigin / 32767.0f;
3593 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3595 // load the pose data
3596 // this unaligned memory access is safe (LittleShort reads as bytes)
3597 framedata = (const unsigned short *)(pbase + header.ofs_frames);
3598 if (header.version == 1)
3600 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3602 for (j = 0;j < (int)header.num_poses;j++, k++)
3604 float qx, qy, qz, qw;
3605 loadmodel->data_poses7s[k*7 + 0] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[0] + (pose1[j].channelmask&1 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[0] : 0));
3606 loadmodel->data_poses7s[k*7 + 1] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[1] + (pose1[j].channelmask&2 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[1] : 0));
3607 loadmodel->data_poses7s[k*7 + 2] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[2] + (pose1[j].channelmask&4 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[2] : 0));
3608 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3609 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3610 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3611 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3612 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3613 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3614 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3615 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3616 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3617 // skip scale data for now
3618 if(pose1[j].channelmask&64) framedata++;
3619 if(pose1[j].channelmask&128) framedata++;
3620 if(pose1[j].channelmask&256) framedata++;
3623 if (header.num_frames <= 0)
3625 for (i = 0;i < loadmodel->num_bones;i++)
3627 float qx, qy, qz, qw;
3628 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3629 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3630 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3631 qx = joint1[i].rotation[0];
3632 qy = joint1[i].rotation[1];
3633 qz = joint1[i].rotation[2];
3634 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3635 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3636 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3637 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3638 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3639 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3645 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3647 for (j = 0;j < (int)header.num_poses;j++, k++)
3650 loadmodel->data_poses7s[k*7 + 0] = loadmodel->num_poseinvscale * (pose[j].channeloffset[0] + (pose[j].channelmask&1 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[0] : 0));
3651 loadmodel->data_poses7s[k*7 + 1] = loadmodel->num_poseinvscale * (pose[j].channeloffset[1] + (pose[j].channelmask&2 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[1] : 0));
3652 loadmodel->data_poses7s[k*7 + 2] = loadmodel->num_poseinvscale * (pose[j].channeloffset[2] + (pose[j].channelmask&4 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[2] : 0));
3653 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3654 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3655 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3656 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3658 Vector4Negate(rot, rot);
3659 Vector4Normalize2(rot, rot);
3660 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3661 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3662 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3663 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3664 // skip scale data for now
3665 if(pose[j].channelmask&128) framedata++;
3666 if(pose[j].channelmask&256) framedata++;
3667 if(pose[j].channelmask&512) framedata++;
3670 if (header.num_frames <= 0)
3672 for (i = 0;i < loadmodel->num_bones;i++)
3674 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3675 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3676 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3677 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3678 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3679 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3680 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3685 // load bounding box data
3686 if (header.ofs_bounds)
3688 float xyradius = 0, radius = 0;
3689 VectorClear(loadmodel->normalmins);
3690 VectorClear(loadmodel->normalmaxs);
3691 for (i = 0; i < (int)header.num_frames;i++)
3694 bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3695 bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3696 bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3697 bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);
3698 bound.maxs[1] = LittleFloat(bounds[i].maxs[1]);
3699 bound.maxs[2] = LittleFloat(bounds[i].maxs[2]);
3700 bound.xyradius = LittleFloat(bounds[i].xyradius);
3701 bound.radius = LittleFloat(bounds[i].radius);
3704 VectorCopy(bound.mins, loadmodel->normalmins);
3705 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3709 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3710 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3711 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3712 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3713 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3714 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3716 if (bound.xyradius > xyradius)
3717 xyradius = bound.xyradius;
3718 if (bound.radius > radius)
3719 radius = bound.radius;
3721 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3722 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3723 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3724 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3725 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3726 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3727 loadmodel->radius = radius;
3728 loadmodel->radius2 = radius * radius;
3731 // load triangle data
3732 // this unaligned memory access is safe (LittleLong reads as bytes)
3733 inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3734 outelements = loadmodel->surfmesh.data_element3i;
3735 for (i = 0;i < (int)header.num_triangles;i++)
3737 outelements[0] = LittleLong(inelements[0]);
3738 outelements[1] = LittleLong(inelements[1]);
3739 outelements[2] = LittleLong(inelements[2]);
3743 if (loadmodel->surfmesh.data_element3s)
3744 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3745 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3746 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3749 // this unaligned memory access is safe (LittleFloat reads as bytes)
3750 outvertex = loadmodel->surfmesh.data_vertex3f;
3751 for (i = 0;i < (int)header.num_vertexes;i++)
3753 outvertex[0] = LittleFloat(vposition[0]);
3754 outvertex[1] = LittleFloat(vposition[1]);
3755 outvertex[2] = LittleFloat(vposition[2]);
3760 outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3761 // this unaligned memory access is safe (LittleFloat reads as bytes)
3762 for (i = 0;i < (int)header.num_vertexes;i++)
3764 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3765 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3770 // this unaligned memory access is safe (LittleFloat reads as bytes)
3773 outnormal = loadmodel->surfmesh.data_normal3f;
3774 for (i = 0;i < (int)header.num_vertexes;i++)
3776 outnormal[0] = LittleFloat(vnormal[0]);
3777 outnormal[1] = LittleFloat(vnormal[1]);
3778 outnormal[2] = LittleFloat(vnormal[2]);
3784 // this unaligned memory access is safe (LittleFloat reads as bytes)
3785 if(vnormal && vtangent)
3787 outnormal = loadmodel->surfmesh.data_normal3f;
3788 outsvector = loadmodel->surfmesh.data_svector3f;
3789 outtvector = loadmodel->surfmesh.data_tvector3f;
3790 for (i = 0;i < (int)header.num_vertexes;i++)
3792 outsvector[0] = LittleFloat(vtangent[0]);
3793 outsvector[1] = LittleFloat(vtangent[1]);
3794 outsvector[2] = LittleFloat(vtangent[2]);
3795 if(LittleFloat(vtangent[3]) < 0)
3796 CrossProduct(outsvector, outnormal, outtvector);
3798 CrossProduct(outnormal, outsvector, outtvector);
3806 // this unaligned memory access is safe (all bytes)
3807 if (vblendindexes && vblendweights)
3809 for (i = 0; i < (int)header.num_vertexes;i++)
3811 blendweights_t weights;
3812 memcpy(weights.index, vblendindexes + i*4, 4);
3813 memcpy(weights.influence, vblendweights + i*4, 4);
3814 loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3815 loadmodel->surfmesh.data_skeletalindex4ub[i*4 ] = weights.index[0];
3816 loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3817 loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3818 loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3819 loadmodel->surfmesh.data_skeletalweight4ub[i*4 ] = weights.influence[0];
3820 loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3821 loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3822 loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3828 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3829 // this unaligned memory access is safe (LittleFloat reads as bytes)
3830 for (i = 0;i < (int)header.num_vertexes;i++)
3832 outcolor[0] = LittleFloat(vcolor4f[0]);
3833 outcolor[1] = LittleFloat(vcolor4f[1]);
3834 outcolor[2] = LittleFloat(vcolor4f[2]);
3835 outcolor[3] = LittleFloat(vcolor4f[3]);
3842 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3843 // this unaligned memory access is safe (all bytes)
3844 for (i = 0;i < (int)header.num_vertexes;i++)
3846 outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3847 outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3848 outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3849 outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3856 for (i = 0;i < (int)header.num_meshes;i++)
3859 msurface_t *surface;
3861 mesh.name = LittleLong(meshes[i].name);
3862 mesh.material = LittleLong(meshes[i].material);
3863 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3864 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3865 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3866 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3868 loadmodel->modelsurfaces_sorted[i] = i;
3869 surface = loadmodel->data_surfaces + i;
3870 surface->texture = loadmodel->data_textures + i;
3871 surface->num_firsttriangle = mesh.first_triangle;
3872 surface->num_triangles = mesh.num_triangles;
3873 surface->num_firstvertex = mesh.first_vertex;
3874 surface->num_vertices = mesh.num_vertexes;
3876 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3879 Mod_FreeSkinFiles(skinfiles);
3880 Mod_MakeSortedSurfaces(loadmodel);
3882 // compute all the mesh information that was not loaded from the file
3884 Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, r_smoothnormals_areaweighting.integer != 0);
3885 if (!vnormal || !vtangent)
3886 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
3887 if (!header.ofs_bounds)
3888 Mod_Alias_CalculateBoundingBox();
3890 // Always make a BIH for the first frame, we can use it where possible.
3891 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3892 if (!loadmodel->surfmesh.isanimated)
3894 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3895 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3896 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3897 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3898 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3901 if (joint) { Mem_Free(joint); joint = NULL; }
3902 if (joint1) { Mem_Free(joint1); joint1 = NULL; }
3903 if (pose) { Mem_Free(pose); pose = NULL; }
3904 if (pose1) { Mem_Free(pose1); pose1 = NULL; }