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 qboolean r_skeletal_use_sse_defined = false;
31 cvar_t r_skeletal_use_sse = {CVAR_CLIENT, "r_skeletal_use_sse", "1", "use SSE for skeletal model animation"};
33 cvar_t r_skeletal_debugbone = {CVAR_CLIENT, "r_skeletal_debugbone", "-1", "development cvar for testing skeletal model code"};
34 cvar_t r_skeletal_debugbonecomponent = {CVAR_CLIENT, "r_skeletal_debugbonecomponent", "3", "development cvar for testing skeletal model code"};
35 cvar_t r_skeletal_debugbonevalue = {CVAR_CLIENT, "r_skeletal_debugbonevalue", "100", "development cvar for testing skeletal model code"};
36 cvar_t r_skeletal_debugtranslatex = {CVAR_CLIENT, "r_skeletal_debugtranslatex", "1", "development cvar for testing skeletal model code"};
37 cvar_t r_skeletal_debugtranslatey = {CVAR_CLIENT, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"};
38 cvar_t r_skeletal_debugtranslatez = {CVAR_CLIENT, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"};
39 cvar_t mod_alias_supporttagscale = {CVAR_CLIENT | CVAR_SERVER, "mod_alias_supporttagscale", "1", "support scaling factors in bone/tag attachment matrices as supported by MD3"};
40 cvar_t mod_alias_force_animated = {CVAR_CLIENT | CVAR_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 dp_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 dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
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(dp_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(dp_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 dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
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 dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
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 dp_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 dp_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 dp_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 qboolean Mod_Alias_CalculateBoundingBox(void)
629 qboolean firstvertex = true;
630 float dist, yawradius, radius;
632 qboolean 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(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
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(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
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(dp_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->DrawSky = NULL;
1008 loadmodel->DrawAddWaterPlanes = NULL;
1009 loadmodel->Draw = R_Q1BSP_Draw;
1010 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1011 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1012 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1013 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1014 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1015 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1016 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1017 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1018 // FIXME add TraceBrush!
1019 loadmodel->PointSuperContents = NULL;
1020 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1022 loadmodel->num_surfaces = 1;
1023 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1024 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1025 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1026 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1027 loadmodel->sortedmodelsurfaces[0] = 0;
1029 loadmodel->numskins = LittleLong(pinmodel->numskins);
1030 BOUNDI(loadmodel->numskins,0,65536);
1031 skinwidth = LittleLong (pinmodel->skinwidth);
1032 BOUNDI(skinwidth,0,65536);
1033 skinheight = LittleLong (pinmodel->skinheight);
1034 BOUNDI(skinheight,0,65536);
1035 numverts = LittleLong(pinmodel->numverts);
1036 BOUNDI(numverts,0,65536);
1037 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1038 BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1039 loadmodel->numframes = LittleLong(pinmodel->numframes);
1040 BOUNDI(loadmodel->numframes,0,65536);
1041 loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1042 BOUNDI((int)loadmodel->synctype,0,2);
1043 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1044 i = LittleLong (pinmodel->flags);
1045 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1047 if (strstr(r_nolerp_list.string, loadmodel->name))
1048 loadmodel->nolerp = true;
1050 for (i = 0;i < 3;i++)
1052 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1053 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1056 startskins = datapointer;
1058 for (i = 0;i < loadmodel->numskins;i++)
1060 pinskintype = (daliasskintype_t *)datapointer;
1061 datapointer += sizeof(daliasskintype_t);
1062 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1066 pinskingroup = (daliasskingroup_t *)datapointer;
1067 datapointer += sizeof(daliasskingroup_t);
1068 groupskins = LittleLong(pinskingroup->numskins);
1069 datapointer += sizeof(daliasskininterval_t) * groupskins;
1072 for (j = 0;j < groupskins;j++)
1074 datapointer += skinwidth * skinheight;
1079 pinstverts = (stvert_t *)datapointer;
1080 datapointer += sizeof(stvert_t) * numverts;
1082 pintriangles = (dtriangle_t *)datapointer;
1083 datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1085 startframes = datapointer;
1086 loadmodel->surfmesh.num_morphframes = 0;
1087 for (i = 0;i < loadmodel->numframes;i++)
1089 pinframetype = (daliasframetype_t *)datapointer;
1090 datapointer += sizeof(daliasframetype_t);
1091 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1095 pinframegroup = (daliasgroup_t *)datapointer;
1096 datapointer += sizeof(daliasgroup_t);
1097 groupframes = LittleLong(pinframegroup->numframes);
1098 datapointer += sizeof(daliasinterval_t) * groupframes;
1101 for (j = 0;j < groupframes;j++)
1103 datapointer += sizeof(daliasframe_t);
1104 datapointer += sizeof(trivertx_t) * numverts;
1105 loadmodel->surfmesh.num_morphframes++;
1108 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1110 // store texture coordinates into temporary array, they will be stored
1111 // after usage is determined (triangle data)
1112 vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1113 vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1114 vertonseam = vertremap + numverts * 2;
1116 scales = 1.0 / skinwidth;
1117 scalet = 1.0 / skinheight;
1118 for (i = 0;i < numverts;i++)
1120 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1121 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1122 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1123 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1124 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1127 // load triangle data
1128 loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1130 // read the triangle elements
1131 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1132 for (j = 0;j < 3;j++)
1133 loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1134 // validate (note numverts is used because this is the original data)
1135 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, NULL, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1136 // now butcher the elements according to vertonseam and tri->facesfront
1137 // and then compact the vertex set to remove duplicates
1138 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1139 if (!LittleLong(pintriangles[i].facesfront)) // backface
1140 for (j = 0;j < 3;j++)
1141 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1142 loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1144 // (this uses vertremap to count usage to save some memory)
1145 for (i = 0;i < numverts*2;i++)
1147 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1148 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1149 // build remapping table and compact array
1150 loadmodel->surfmesh.num_vertices = 0;
1151 for (i = 0;i < numverts*2;i++)
1155 vertremap[i] = loadmodel->surfmesh.num_vertices;
1156 vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1157 vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1158 loadmodel->surfmesh.num_vertices++;
1161 vertremap[i] = -1; // not used at all
1163 // remap the elements to the new vertex set
1164 for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1165 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1166 // store the texture coordinates
1167 loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1168 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1170 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1171 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1174 // generate ushort elements array if possible
1175 if (loadmodel->surfmesh.num_vertices <= 65536)
1176 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1177 if (loadmodel->surfmesh.data_element3s)
1178 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1179 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1182 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1183 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1184 Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1185 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1186 Mod_Alias_MorphMesh_CompileFrames();
1189 Mem_Free(vertremap);
1192 skinfiles = Mod_LoadSkinFiles();
1195 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1196 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1197 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1198 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1199 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1200 Mod_FreeSkinFiles(skinfiles);
1201 for (i = 0;i < loadmodel->numskins;i++)
1203 loadmodel->skinscenes[i].firstframe = i;
1204 loadmodel->skinscenes[i].framecount = 1;
1205 loadmodel->skinscenes[i].loop = true;
1206 loadmodel->skinscenes[i].framerate = 10;
1211 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1212 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1213 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1214 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1216 datapointer = startskins;
1217 for (i = 0;i < loadmodel->numskins;i++)
1219 pinskintype = (daliasskintype_t *)datapointer;
1220 datapointer += sizeof(daliasskintype_t);
1222 if (pinskintype->type == ALIAS_SKIN_SINGLE)
1229 pinskingroup = (daliasskingroup_t *)datapointer;
1230 datapointer += sizeof(daliasskingroup_t);
1232 groupskins = LittleLong (pinskingroup->numskins);
1234 pinskinintervals = (daliasskininterval_t *)datapointer;
1235 datapointer += sizeof(daliasskininterval_t) * groupskins;
1237 interval = LittleFloat(pinskinintervals[0].interval);
1238 if (interval < 0.01f)
1240 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1245 dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1246 loadmodel->skinscenes[i].firstframe = totalskins;
1247 loadmodel->skinscenes[i].framecount = groupskins;
1248 loadmodel->skinscenes[i].framerate = 1.0f / interval;
1249 loadmodel->skinscenes[i].loop = true;
1251 for (j = 0;j < groupskins;j++)
1254 dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1256 dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1257 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))
1258 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));
1259 datapointer += skinwidth * skinheight;
1263 // check for skins that don't exist in the model, but do exist as external images
1264 // (this was added because yummyluv kept pestering me about support for it)
1265 // TODO: support shaders here?
1268 dpsnprintf(name, sizeof(name), "%s_%i", loadmodel->name, loadmodel->numskins);
1269 tempskinframe = R_SkinFrame_LoadExternal(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false, false);
1272 // expand the arrays to make room
1273 tempskinscenes = loadmodel->skinscenes;
1274 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1275 memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1276 Mem_Free(tempskinscenes);
1278 tempaliasskins = loadmodel->data_textures;
1279 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1280 memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1281 Mem_Free(tempaliasskins);
1283 // store the info about the new skin
1284 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, tempskinframe);
1285 strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1286 loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1287 loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1288 loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1289 loadmodel->skinscenes[loadmodel->numskins].loop = true;
1291 //increase skin counts
1292 loadmodel->num_textures++;
1293 loadmodel->numskins++;
1296 // fix up the pointers since they are pointing at the old textures array
1297 // FIXME: this is a hack!
1298 for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1299 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1303 surface = loadmodel->data_surfaces;
1304 surface->texture = loadmodel->data_textures;
1305 surface->num_firsttriangle = 0;
1306 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1307 surface->num_firstvertex = 0;
1308 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1310 if(mod_alias_force_animated.string[0])
1311 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1313 // Always make a BIH for the first frame, we can use it where possible.
1314 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1315 if (!loadmodel->surfmesh.isanimated)
1317 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1318 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1319 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1320 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1321 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1324 // because shaders can do somewhat unexpected things, check for unusual features now
1325 for (i = 0;i < loadmodel->num_textures;i++)
1327 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1328 mod->DrawSky = R_Q1BSP_DrawSky;
1329 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1330 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1334 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1336 int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1337 float iskinwidth, iskinheight;
1338 unsigned char *data;
1339 msurface_t *surface;
1341 unsigned char *base, *datapointer;
1342 md2frame_t *pinframe;
1344 md2triangle_t *intri;
1345 unsigned short *inst;
1346 struct md2verthash_s
1348 struct md2verthash_s *next;
1352 *hash, **md2verthash, *md2verthashdata;
1353 skinfile_t *skinfiles;
1355 pinmodel = (md2_t *)buffer;
1356 base = (unsigned char *)buffer;
1358 version = LittleLong (pinmodel->version);
1359 if (version != MD2ALIAS_VERSION)
1360 Host_Error ("%s has wrong version number (%i should be %i)",
1361 loadmodel->name, version, MD2ALIAS_VERSION);
1363 loadmodel->modeldatatypestring = "MD2";
1365 loadmodel->type = mod_alias;
1366 loadmodel->DrawSky = NULL;
1367 loadmodel->DrawAddWaterPlanes = NULL;
1368 loadmodel->Draw = R_Q1BSP_Draw;
1369 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1370 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1371 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1372 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1373 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1374 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1375 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1376 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1377 loadmodel->PointSuperContents = NULL;
1378 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1380 if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1381 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1382 if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1383 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1384 if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1385 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1386 if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1387 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1389 end = LittleLong(pinmodel->ofs_end);
1390 if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1391 Host_Error ("%s is not a valid model", loadmodel->name);
1392 if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1393 Host_Error ("%s is not a valid model", loadmodel->name);
1394 if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1395 Host_Error ("%s is not a valid model", loadmodel->name);
1396 if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1397 Host_Error ("%s is not a valid model", loadmodel->name);
1398 if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1399 Host_Error ("%s is not a valid model", loadmodel->name);
1401 loadmodel->numskins = LittleLong(pinmodel->num_skins);
1402 numxyz = LittleLong(pinmodel->num_xyz);
1403 numst = LittleLong(pinmodel->num_st);
1404 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1405 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1406 loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1407 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1408 skinwidth = LittleLong(pinmodel->skinwidth);
1409 skinheight = LittleLong(pinmodel->skinheight);
1410 iskinwidth = 1.0f / skinwidth;
1411 iskinheight = 1.0f / skinheight;
1413 loadmodel->num_surfaces = 1;
1414 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1415 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]));
1416 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1417 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1418 loadmodel->sortedmodelsurfaces[0] = 0;
1419 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1420 loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1421 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1423 loadmodel->synctype = ST_RAND;
1426 inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1427 skinfiles = Mod_LoadSkinFiles();
1430 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1431 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1432 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1433 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1434 Mod_FreeSkinFiles(skinfiles);
1436 else if (loadmodel->numskins)
1438 // skins found (most likely not a player model)
1439 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1440 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1441 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1442 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1443 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);
1447 // no skins (most likely a player model)
1448 loadmodel->numskins = 1;
1449 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1450 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1451 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1452 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures, loadmodel->name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
1455 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1456 for (i = 0;i < loadmodel->numskins;i++)
1458 loadmodel->skinscenes[i].firstframe = i;
1459 loadmodel->skinscenes[i].framecount = 1;
1460 loadmodel->skinscenes[i].loop = true;
1461 loadmodel->skinscenes[i].framerate = 10;
1464 // load the triangles and stvert data
1465 inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1466 intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1467 md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1468 md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1469 // swap the triangle list
1470 loadmodel->surfmesh.num_vertices = 0;
1471 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1473 for (j = 0;j < 3;j++)
1475 xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1476 st = (unsigned short) LittleShort (intri[i].index_st[j]);
1479 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1484 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1487 hashindex = (xyz * 256 + st) & 65535;
1488 for (hash = md2verthash[hashindex];hash;hash = hash->next)
1489 if (hash->xyz == xyz && hash->st == st)
1493 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1496 hash->next = md2verthash[hashindex];
1497 md2verthash[hashindex] = hash;
1499 loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1503 vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1504 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));
1505 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1506 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1507 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1510 hash = md2verthashdata + i;
1511 vertremap[i] = hash->xyz;
1512 sts = LittleShort(inst[hash->st*2+0]);
1513 stt = LittleShort(inst[hash->st*2+1]);
1514 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1516 Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1520 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1521 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1524 Mem_Free(md2verthash);
1525 Mem_Free(md2verthashdata);
1527 // generate ushort elements array if possible
1528 if (loadmodel->surfmesh.num_vertices <= 65536)
1529 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1530 if (loadmodel->surfmesh.data_element3s)
1531 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1532 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1535 datapointer = (base + LittleLong(pinmodel->ofs_frames));
1536 for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1541 pinframe = (md2frame_t *)datapointer;
1542 datapointer += sizeof(md2frame_t);
1543 // store the frame scale/translate into the appropriate array
1544 for (j = 0;j < 3;j++)
1546 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1547 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1549 // convert the vertices
1550 v = (trivertx_t *)datapointer;
1551 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1552 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1553 out[k] = v[vertremap[k]];
1554 datapointer += numxyz * sizeof(trivertx_t);
1556 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1557 loadmodel->animscenes[i].firstframe = i;
1558 loadmodel->animscenes[i].framecount = 1;
1559 loadmodel->animscenes[i].framerate = 10;
1560 loadmodel->animscenes[i].loop = true;
1563 Mem_Free(vertremap);
1565 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1566 Mod_Alias_MorphMesh_CompileFrames();
1567 if(mod_alias_force_animated.string[0])
1568 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1570 surface = loadmodel->data_surfaces;
1571 surface->texture = loadmodel->data_textures;
1572 surface->num_firsttriangle = 0;
1573 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1574 surface->num_firstvertex = 0;
1575 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1577 // Always make a BIH for the first frame, we can use it where possible.
1578 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1579 if (!loadmodel->surfmesh.isanimated)
1581 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1582 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1583 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1584 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1585 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1588 // because shaders can do somewhat unexpected things, check for unusual features now
1589 for (i = 0;i < loadmodel->num_textures;i++)
1591 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1592 mod->DrawSky = R_Q1BSP_DrawSky;
1593 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1594 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1598 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1600 int i, j, k, version, meshvertices, meshtriangles;
1601 unsigned char *data;
1602 msurface_t *surface;
1603 md3modelheader_t *pinmodel;
1604 md3frameinfo_t *pinframe;
1607 skinfile_t *skinfiles;
1609 pinmodel = (md3modelheader_t *)buffer;
1611 if (memcmp(pinmodel->identifier, "IDP3", 4))
1612 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1613 version = LittleLong (pinmodel->version);
1614 if (version != MD3VERSION)
1615 Host_Error ("%s has wrong version number (%i should be %i)",
1616 loadmodel->name, version, MD3VERSION);
1618 skinfiles = Mod_LoadSkinFiles();
1619 if (loadmodel->numskins < 1)
1620 loadmodel->numskins = 1;
1622 loadmodel->modeldatatypestring = "MD3";
1624 loadmodel->type = mod_alias;
1625 loadmodel->DrawSky = NULL;
1626 loadmodel->DrawAddWaterPlanes = NULL;
1627 loadmodel->Draw = R_Q1BSP_Draw;
1628 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1629 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1630 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1631 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1632 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1633 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1634 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1635 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1636 loadmodel->PointSuperContents = NULL;
1637 loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1638 loadmodel->synctype = ST_RAND;
1639 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1640 i = LittleLong (pinmodel->flags);
1641 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1643 // set up some global info about the model
1644 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1645 loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1647 // make skinscenes for the skins (no groups)
1648 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1649 for (i = 0;i < loadmodel->numskins;i++)
1651 loadmodel->skinscenes[i].firstframe = i;
1652 loadmodel->skinscenes[i].framecount = 1;
1653 loadmodel->skinscenes[i].loop = true;
1654 loadmodel->skinscenes[i].framerate = 10;
1658 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1659 for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1661 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1662 loadmodel->animscenes[i].firstframe = i;
1663 loadmodel->animscenes[i].framecount = 1;
1664 loadmodel->animscenes[i].framerate = 10;
1665 loadmodel->animscenes[i].loop = true;
1669 loadmodel->num_tagframes = loadmodel->numframes;
1670 loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1671 loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1672 for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1674 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1675 for (j = 0;j < 9;j++)
1676 loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1677 for (j = 0;j < 3;j++)
1678 loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1679 //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);
1685 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)))
1687 if (memcmp(pinmesh->identifier, "IDP3", 4))
1688 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1689 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1690 Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1691 meshvertices += LittleLong(pinmesh->num_vertices);
1692 meshtriangles += LittleLong(pinmesh->num_triangles);
1695 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1696 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1697 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1698 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));
1699 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1700 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1701 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1702 loadmodel->surfmesh.num_vertices = meshvertices;
1703 loadmodel->surfmesh.num_triangles = meshtriangles;
1704 loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1705 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1706 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1707 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1708 loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1709 if (meshvertices <= 65536)
1711 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1716 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)))
1718 if (memcmp(pinmesh->identifier, "IDP3", 4))
1719 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1720 loadmodel->sortedmodelsurfaces[i] = i;
1721 surface = loadmodel->data_surfaces + i;
1722 surface->texture = loadmodel->data_textures + i;
1723 surface->num_firsttriangle = meshtriangles;
1724 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1725 surface->num_firstvertex = meshvertices;
1726 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1727 meshvertices += surface->num_vertices;
1728 meshtriangles += surface->num_triangles;
1730 for (j = 0;j < surface->num_triangles * 3;j++)
1732 int e = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1733 loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = e;
1734 if (loadmodel->surfmesh.data_element3s)
1735 loadmodel->surfmesh.data_element3s[j + surface->num_firsttriangle * 3] = e;
1737 for (j = 0;j < surface->num_vertices;j++)
1739 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1740 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1742 for (j = 0;j < loadmodel->numframes;j++)
1744 const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1745 md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1746 for (k = 0;k < surface->num_vertices;k++, in++, out++)
1748 out->origin[0] = LittleShort(in->origin[0]);
1749 out->origin[1] = LittleShort(in->origin[1]);
1750 out->origin[2] = LittleShort(in->origin[2]);
1751 out->pitch = in->pitch;
1756 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1758 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__);
1760 Mod_Alias_MorphMesh_CompileFrames();
1761 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1762 Mod_FreeSkinFiles(skinfiles);
1763 Mod_MakeSortedSurfaces(loadmodel);
1764 if(mod_alias_force_animated.string[0])
1765 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1767 // Always make a BIH for the first frame, we can use it where possible.
1768 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1769 if (!loadmodel->surfmesh.isanimated)
1771 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1772 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1773 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1774 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1775 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1778 // because shaders can do somewhat unexpected things, check for unusual features now
1779 for (i = 0;i < loadmodel->num_textures;i++)
1781 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1782 mod->DrawSky = R_Q1BSP_DrawSky;
1783 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1784 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1788 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1790 zymtype1header_t *pinmodel, *pheader;
1791 unsigned char *pbase;
1792 int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1793 float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1794 zymvertex_t *verts, *vertdata;
1798 skinfile_t *skinfiles;
1799 unsigned char *data;
1800 msurface_t *surface;
1802 pinmodel = (zymtype1header_t *)buffer;
1803 pbase = (unsigned char *)buffer;
1804 if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1805 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1806 if (BigLong(pinmodel->type) != 1)
1807 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1809 loadmodel->modeldatatypestring = "ZYM";
1811 loadmodel->type = mod_alias;
1812 loadmodel->synctype = ST_RAND;
1816 pheader->type = BigLong(pinmodel->type);
1817 pheader->filesize = BigLong(pinmodel->filesize);
1818 pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1819 pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1820 pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1821 pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1822 pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1823 pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1824 pheader->radius = BigFloat(pinmodel->radius);
1825 pheader->numverts = BigLong(pinmodel->numverts);
1826 pheader->numtris = BigLong(pinmodel->numtris);
1827 pheader->numshaders = BigLong(pinmodel->numshaders);
1828 pheader->numbones = BigLong(pinmodel->numbones);
1829 pheader->numscenes = BigLong(pinmodel->numscenes);
1830 pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1831 pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1832 pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1833 pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1834 pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1835 pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1836 pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1837 pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1838 pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1839 pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1840 pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1841 pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1842 pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1843 pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1844 pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1845 pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1846 pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1847 pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1849 if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1851 Con_Printf("%s has no geometry\n", loadmodel->name);
1854 if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1856 Con_Printf("%s has no animations\n", loadmodel->name);
1860 loadmodel->DrawSky = NULL;
1861 loadmodel->DrawAddWaterPlanes = NULL;
1862 loadmodel->Draw = R_Q1BSP_Draw;
1863 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1864 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1865 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1866 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1867 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1868 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1869 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1870 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1871 loadmodel->PointSuperContents = NULL;
1872 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1874 loadmodel->numframes = pheader->numscenes;
1875 loadmodel->num_surfaces = pheader->numshaders;
1877 skinfiles = Mod_LoadSkinFiles();
1878 if (loadmodel->numskins < 1)
1879 loadmodel->numskins = 1;
1881 // make skinscenes for the skins (no groups)
1882 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1883 for (i = 0;i < loadmodel->numskins;i++)
1885 loadmodel->skinscenes[i].firstframe = i;
1886 loadmodel->skinscenes[i].framecount = 1;
1887 loadmodel->skinscenes[i].loop = true;
1888 loadmodel->skinscenes[i].framerate = 10;
1892 // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1893 modelradius = pheader->radius;
1894 for (i = 0;i < 3;i++)
1896 loadmodel->normalmins[i] = pheader->mins[i];
1897 loadmodel->normalmaxs[i] = pheader->maxs[i];
1898 loadmodel->rotatedmins[i] = -modelradius;
1899 loadmodel->rotatedmaxs[i] = modelradius;
1901 corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1902 corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1903 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1904 if (loadmodel->yawmaxs[0] > modelradius)
1905 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1906 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1907 loadmodel->yawmins[2] = loadmodel->normalmins[2];
1908 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1909 loadmodel->radius = modelradius;
1910 loadmodel->radius2 = modelradius * modelradius;
1912 // go through the lumps, swapping things
1914 //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1915 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1916 scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1917 numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1918 for (i = 0;i < pheader->numscenes;i++)
1920 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1921 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1922 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1923 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1924 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1925 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1926 Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1927 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1928 Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1929 if (loadmodel->animscenes[i].framerate < 0)
1930 Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1934 //zymlump_t lump_bones; // zymbone_t bone[numbones];
1935 loadmodel->num_bones = pheader->numbones;
1936 loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1937 bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1938 for (i = 0;i < pheader->numbones;i++)
1940 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1941 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1942 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1943 if (loadmodel->data_bones[i].parent >= i)
1944 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1947 //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1948 vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1949 bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1950 for (i = 0;i < pheader->numverts;i++)
1952 vertbonecounts[i] = BigLong(bonecount[i]);
1953 if (vertbonecounts[i] != 1)
1954 Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1957 loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1959 meshvertices = pheader->numverts;
1960 meshtriangles = pheader->numtris;
1962 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1963 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1964 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1965 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + 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]));
1966 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1967 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1968 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1969 loadmodel->surfmesh.num_vertices = meshvertices;
1970 loadmodel->surfmesh.num_triangles = meshtriangles;
1971 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1972 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1973 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1974 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1975 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1976 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1977 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1978 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1979 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1980 loadmodel->surfmesh.num_blends = 0;
1981 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
1982 if (loadmodel->surfmesh.num_vertices <= 65536)
1984 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1986 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
1987 loadmodel->surfmesh.data_blendweights = NULL;
1989 //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1990 poses = (float *) (pheader->lump_poses.start + pbase);
1991 // figure out scale of model from root bone, for compatibility with old zmodel versions
1992 tempvec[0] = BigFloat(poses[0]);
1993 tempvec[1] = BigFloat(poses[1]);
1994 tempvec[2] = BigFloat(poses[2]);
1995 modelscale = VectorLength(tempvec);
1997 for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
1999 f = fabs(BigFloat(poses[i]));
2000 biggestorigin = max(biggestorigin, f);
2002 loadmodel->num_posescale = biggestorigin / 32767.0f;
2003 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2004 for (i = 0;i < numposes;i++)
2006 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
2007 for (j = 0;j < loadmodel->num_bones;j++)
2010 matrix4x4_t posematrix;
2011 for (k = 0;k < 12;k++)
2012 pose[k] = BigFloat(frameposes[j*12+k]);
2013 //if (j < loadmodel->num_bones)
2014 // 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));
2015 // scale child bones to match the root scale
2016 if (loadmodel->data_bones[j].parent >= 0)
2018 pose[3] *= modelscale;
2019 pose[7] *= modelscale;
2020 pose[11] *= modelscale;
2022 // normalize rotation matrix
2023 VectorNormalize(pose + 0);
2024 VectorNormalize(pose + 4);
2025 VectorNormalize(pose + 8);
2026 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2027 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2031 //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2032 verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2033 vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2034 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2035 // (converting from weight-blending skeletal animation to
2036 // deformation-based skeletal animation)
2037 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2038 for (i = 0;i < loadmodel->num_bones;i++)
2041 for (k = 0;k < 12;k++)
2042 m[k] = BigFloat(poses[i*12+k]);
2043 if (loadmodel->data_bones[i].parent >= 0)
2044 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2046 for (k = 0;k < 12;k++)
2047 bonepose[12*i+k] = m[k];
2049 for (j = 0;j < pheader->numverts;j++)
2051 // this format really should have had a per vertexweight weight value...
2052 // but since it does not, the weighting is completely ignored and
2053 // only one weight is allowed per vertex
2054 int boneindex = BigLong(vertdata[j].bonenum);
2055 const float *m = bonepose + 12 * boneindex;
2056 float relativeorigin[3];
2057 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2058 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2059 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2060 // transform the vertex bone weight into the base mesh
2061 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2062 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2063 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2064 // store the weight as the primary weight on this vertex
2065 loadmodel->surfmesh.blends[j] = boneindex;
2066 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = boneindex;
2067 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2068 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2069 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2070 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = 255;
2071 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2072 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2073 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2076 // normals and tangents are calculated after elements are loaded
2078 //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2079 outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2080 intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2081 for (i = 0;i < pheader->numverts;i++)
2083 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2084 // flip T coordinate for OpenGL
2085 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2088 //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2089 //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2090 //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2092 //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2093 //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)
2094 // byteswap, validate, and swap winding order of tris
2095 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2096 if (pheader->lump_render.length != count)
2097 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2098 renderlist = (int *) (pheader->lump_render.start + pbase);
2099 renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2101 for (i = 0;i < loadmodel->num_surfaces;i++)
2103 int firstvertex, lastvertex;
2104 if (renderlist >= renderlistend)
2105 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2106 count = BigLong(*renderlist);renderlist++;
2107 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2108 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2110 loadmodel->sortedmodelsurfaces[i] = i;
2111 surface = loadmodel->data_surfaces + i;
2112 surface->texture = loadmodel->data_textures + i;
2113 surface->num_firsttriangle = meshtriangles;
2114 surface->num_triangles = count;
2115 meshtriangles += surface->num_triangles;
2117 // load the elements
2118 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2119 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2121 outelements[j*3+2] = BigLong(renderlist[0]);
2122 outelements[j*3+1] = BigLong(renderlist[1]);
2123 outelements[j*3+0] = BigLong(renderlist[2]);
2125 // validate the elements and find the used vertex range
2126 firstvertex = meshvertices;
2128 for (j = 0;j < surface->num_triangles * 3;j++)
2130 if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2131 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2132 firstvertex = min(firstvertex, outelements[j]);
2133 lastvertex = max(lastvertex, outelements[j]);
2135 surface->num_firstvertex = firstvertex;
2136 surface->num_vertices = lastvertex + 1 - firstvertex;
2138 // since zym models do not have named sections, reuse their shader
2139 // name as the section name
2140 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2141 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2143 Mod_FreeSkinFiles(skinfiles);
2144 Mem_Free(vertbonecounts);
2146 Mod_MakeSortedSurfaces(loadmodel);
2148 // compute all the mesh information that was not loaded from the file
2149 if (loadmodel->surfmesh.data_element3s)
2150 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2151 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2152 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2153 Mod_BuildBaseBonePoses();
2154 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);
2155 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);
2156 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2157 if(mod_alias_force_animated.string[0])
2158 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2160 // Always make a BIH for the first frame, we can use it where possible.
2161 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2162 if (!loadmodel->surfmesh.isanimated)
2164 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2165 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2166 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2167 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2168 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2171 // because shaders can do somewhat unexpected things, check for unusual features now
2172 for (i = 0;i < loadmodel->num_textures;i++)
2174 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2175 mod->DrawSky = R_Q1BSP_DrawSky;
2176 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2177 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2181 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2183 dpmheader_t *pheader;
2187 unsigned char *pbase;
2188 int i, j, k, meshvertices, meshtriangles;
2189 skinfile_t *skinfiles;
2190 unsigned char *data;
2192 float biggestorigin, tempvec[3], modelscale;
2196 pheader = (dpmheader_t *)buffer;
2197 pbase = (unsigned char *)buffer;
2198 if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2199 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2200 if (BigLong(pheader->type) != 2)
2201 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2203 loadmodel->modeldatatypestring = "DPM";
2205 loadmodel->type = mod_alias;
2206 loadmodel->synctype = ST_RAND;
2209 pheader->type = BigLong(pheader->type);
2210 pheader->filesize = BigLong(pheader->filesize);
2211 pheader->mins[0] = BigFloat(pheader->mins[0]);
2212 pheader->mins[1] = BigFloat(pheader->mins[1]);
2213 pheader->mins[2] = BigFloat(pheader->mins[2]);
2214 pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2215 pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2216 pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2217 pheader->yawradius = BigFloat(pheader->yawradius);
2218 pheader->allradius = BigFloat(pheader->allradius);
2219 pheader->num_bones = BigLong(pheader->num_bones);
2220 pheader->num_meshs = BigLong(pheader->num_meshs);
2221 pheader->num_frames = BigLong(pheader->num_frames);
2222 pheader->ofs_bones = BigLong(pheader->ofs_bones);
2223 pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2224 pheader->ofs_frames = BigLong(pheader->ofs_frames);
2226 if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2228 Con_Printf("%s has no geometry\n", loadmodel->name);
2231 if (pheader->num_frames < 1)
2233 Con_Printf("%s has no frames\n", loadmodel->name);
2237 loadmodel->DrawSky = NULL;
2238 loadmodel->DrawAddWaterPlanes = NULL;
2239 loadmodel->Draw = R_Q1BSP_Draw;
2240 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2241 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2242 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2243 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2244 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2245 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2246 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2247 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2248 loadmodel->PointSuperContents = NULL;
2249 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2252 // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2253 for (i = 0;i < 3;i++)
2255 loadmodel->normalmins[i] = pheader->mins[i];
2256 loadmodel->normalmaxs[i] = pheader->maxs[i];
2257 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2258 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2259 loadmodel->rotatedmins[i] = -pheader->allradius;
2260 loadmodel->rotatedmaxs[i] = pheader->allradius;
2262 loadmodel->radius = pheader->allradius;
2263 loadmodel->radius2 = pheader->allradius * pheader->allradius;
2265 // load external .skin files if present
2266 skinfiles = Mod_LoadSkinFiles();
2267 if (loadmodel->numskins < 1)
2268 loadmodel->numskins = 1;
2273 // gather combined statistics from the meshes
2274 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2275 for (i = 0;i < (int)pheader->num_meshs;i++)
2277 int numverts = BigLong(dpmmesh->num_verts);
2278 meshvertices += numverts;
2279 meshtriangles += BigLong(dpmmesh->num_tris);
2283 loadmodel->numframes = pheader->num_frames;
2284 loadmodel->num_bones = pheader->num_bones;
2285 loadmodel->num_poses = loadmodel->numframes;
2286 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2287 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2288 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2289 // do most allocations as one merged chunk
2290 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));
2291 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2292 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2293 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2294 loadmodel->surfmesh.num_vertices = meshvertices;
2295 loadmodel->surfmesh.num_triangles = meshtriangles;
2296 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2297 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2298 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2299 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2300 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2301 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2302 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2303 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2304 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2305 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2306 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2307 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2308 loadmodel->surfmesh.num_blends = 0;
2309 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2310 if (meshvertices <= 65536)
2312 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2314 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2315 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2317 for (i = 0;i < loadmodel->numskins;i++)
2319 loadmodel->skinscenes[i].firstframe = i;
2320 loadmodel->skinscenes[i].framecount = 1;
2321 loadmodel->skinscenes[i].loop = true;
2322 loadmodel->skinscenes[i].framerate = 10;
2325 // load the bone info
2326 bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2327 for (i = 0;i < loadmodel->num_bones;i++)
2329 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2330 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2331 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2332 if (loadmodel->data_bones[i].parent >= i)
2333 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2337 frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2338 // figure out scale of model from root bone, for compatibility with old dpmodel versions
2339 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2340 tempvec[0] = BigFloat(poses[0]);
2341 tempvec[1] = BigFloat(poses[1]);
2342 tempvec[2] = BigFloat(poses[2]);
2343 modelscale = VectorLength(tempvec);
2345 for (i = 0;i < loadmodel->numframes;i++)
2347 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2348 loadmodel->animscenes[i].firstframe = i;
2349 loadmodel->animscenes[i].framecount = 1;
2350 loadmodel->animscenes[i].loop = true;
2351 loadmodel->animscenes[i].framerate = 10;
2352 // load the bone poses for this frame
2353 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2354 for (j = 0;j < loadmodel->num_bones*12;j++)
2356 f = fabs(BigFloat(poses[j]));
2357 biggestorigin = max(biggestorigin, f);
2359 // stuff not processed here: mins, maxs, yawradius, allradius
2361 loadmodel->num_posescale = biggestorigin / 32767.0f;
2362 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2363 for (i = 0;i < loadmodel->numframes;i++)
2365 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2366 for (j = 0;j < loadmodel->num_bones;j++)
2369 matrix4x4_t posematrix;
2370 for (k = 0;k < 12;k++)
2371 pose[k] = BigFloat(frameposes[j*12+k]);
2372 // scale child bones to match the root scale
2373 if (loadmodel->data_bones[j].parent >= 0)
2375 pose[3] *= modelscale;
2376 pose[7] *= modelscale;
2377 pose[11] *= modelscale;
2379 // normalize rotation matrix
2380 VectorNormalize(pose + 0);
2381 VectorNormalize(pose + 4);
2382 VectorNormalize(pose + 8);
2383 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2384 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2388 // load the meshes now
2389 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2392 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2393 // (converting from weight-blending skeletal animation to
2394 // deformation-based skeletal animation)
2395 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2396 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2397 for (i = 0;i < loadmodel->num_bones;i++)
2400 for (k = 0;k < 12;k++)
2401 m[k] = BigFloat(poses[i*12+k]);
2402 if (loadmodel->data_bones[i].parent >= 0)
2403 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2405 for (k = 0;k < 12;k++)
2406 bonepose[12*i+k] = m[k];
2408 for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2410 const int *inelements;
2412 unsigned short *outelement3s;
2413 const float *intexcoord;
2414 msurface_t *surface;
2416 loadmodel->sortedmodelsurfaces[i] = i;
2417 surface = loadmodel->data_surfaces + i;
2418 surface->texture = loadmodel->data_textures + i;
2419 surface->num_firsttriangle = meshtriangles;
2420 surface->num_triangles = BigLong(dpmmesh->num_tris);
2421 surface->num_firstvertex = meshvertices;
2422 surface->num_vertices = BigLong(dpmmesh->num_verts);
2423 meshvertices += surface->num_vertices;
2424 meshtriangles += surface->num_triangles;
2426 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2427 outelement3i = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2428 outelement3s = loadmodel->surfmesh.data_element3s ? loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3 : NULL;
2429 for (j = 0;j < surface->num_triangles;j++)
2431 // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2432 outelement3i[j * 3 + 0] = surface->num_firstvertex + BigLong(inelements[j * 3 + 2]);
2433 outelement3i[j * 3 + 1] = surface->num_firstvertex + BigLong(inelements[j * 3 + 1]);
2434 outelement3i[j * 3 + 2] = surface->num_firstvertex + BigLong(inelements[j * 3 + 0]);
2437 outelement3s[j * 3 + 0] = outelement3i[j * 3 + 0];
2438 outelement3s[j * 3 + 1] = outelement3i[j * 3 + 1];
2439 outelement3s[j * 3 + 2] = outelement3i[j * 3 + 2];
2443 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2444 for (j = 0;j < surface->num_vertices*2;j++)
2445 loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2447 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2448 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2450 int weightindex[4] = { 0, 0, 0, 0 };
2451 float weightinfluence[4] = { 0, 0, 0, 0 };
2453 int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2454 data += sizeof(dpmvertex_t);
2455 for (k = 0;k < numweights;k++)
2457 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2458 int boneindex = BigLong(vert->bonenum);
2459 const float *m = bonepose + 12 * boneindex;
2460 float influence = BigFloat(vert->influence);
2461 float relativeorigin[3], relativenormal[3];
2462 relativeorigin[0] = BigFloat(vert->origin[0]);
2463 relativeorigin[1] = BigFloat(vert->origin[1]);
2464 relativeorigin[2] = BigFloat(vert->origin[2]);
2465 relativenormal[0] = BigFloat(vert->normal[0]);
2466 relativenormal[1] = BigFloat(vert->normal[1]);
2467 relativenormal[2] = BigFloat(vert->normal[2]);
2468 // blend the vertex bone weights into the base mesh
2469 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2470 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2471 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2472 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2473 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2474 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2477 // store the first (and often only) weight
2478 weightinfluence[0] = influence;
2479 weightindex[0] = boneindex;
2483 // sort the new weight into this vertex's weight table
2484 // (which only accepts up to 4 bones per vertex)
2485 for (l = 0;l < 4;l++)
2487 if (weightinfluence[l] < influence)
2489 // move weaker influence weights out of the way first
2491 for (l2 = 3;l2 > l;l2--)
2493 weightinfluence[l2] = weightinfluence[l2-1];
2494 weightindex[l2] = weightindex[l2-1];
2496 // store the new weight
2497 weightinfluence[l] = influence;
2498 weightindex[l] = boneindex;
2503 data += sizeof(dpmbonevert_t);
2505 loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2506 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = weightindex[0];
2507 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2508 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2509 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2510 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
2511 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2512 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2513 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2516 // since dpm models do not have named sections, reuse their shader name as the section name
2517 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2519 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__);
2521 if (loadmodel->surfmesh.num_blends < meshvertices)
2522 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2524 Mod_FreeSkinFiles(skinfiles);
2525 Mod_MakeSortedSurfaces(loadmodel);
2527 // compute all the mesh information that was not loaded from the file
2528 Mod_BuildBaseBonePoses();
2529 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);
2530 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2531 if(mod_alias_force_animated.string[0])
2532 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2534 // Always make a BIH for the first frame, we can use it where possible.
2535 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2536 if (!loadmodel->surfmesh.isanimated)
2538 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2539 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2540 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2541 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2542 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2545 // because shaders can do somewhat unexpected things, check for unusual features now
2546 for (i = 0;i < loadmodel->num_textures;i++)
2548 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2549 mod->DrawSky = R_Q1BSP_DrawSky;
2550 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2551 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2555 // no idea why PSK/PSA files contain weird quaternions but they do...
2556 #define PSKQUATNEGATIONS
2557 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2559 int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2560 int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2561 fs_offset_t filesize;
2566 pskboneinfo_t *bones;
2567 pskrawweights_t *rawweights;
2568 //pskboneinfo_t *animbones;
2569 pskaniminfo_t *anims;
2570 pskanimkeys_t *animkeys;
2571 void *animfilebuffer, *animbuffer, *animbufferend;
2572 unsigned char *data;
2574 skinfile_t *skinfiles;
2575 char animname[MAX_QPATH];
2577 float biggestorigin;
2579 pchunk = (pskchunk_t *)buffer;
2580 if (strcmp(pchunk->id, "ACTRHEAD"))
2581 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2583 loadmodel->modeldatatypestring = "PSK";
2585 loadmodel->type = mod_alias;
2586 loadmodel->DrawSky = NULL;
2587 loadmodel->DrawAddWaterPlanes = NULL;
2588 loadmodel->Draw = R_Q1BSP_Draw;
2589 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2590 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2591 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2592 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2593 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2594 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2595 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2596 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2597 loadmodel->PointSuperContents = NULL;
2598 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2599 loadmodel->synctype = ST_RAND;
2601 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2602 strlcat(animname, ".psa", sizeof(animname));
2603 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2604 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2606 animbufferend = animbuffer;
2625 while (buffer < bufferend)
2627 pchunk = (pskchunk_t *)buffer;
2628 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2629 version = LittleLong(pchunk->version);
2630 recordsize = LittleLong(pchunk->recordsize);
2631 numrecords = LittleLong(pchunk->numrecords);
2632 if (developer_extra.integer)
2633 Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2634 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2635 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);
2636 if (!strcmp(pchunk->id, "ACTRHEAD"))
2640 else if (!strcmp(pchunk->id, "PNTS0000"))
2643 if (recordsize != sizeof(*p))
2644 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2645 // byteswap in place and keep the pointer
2646 numpnts = numrecords;
2647 pnts = (pskpnts_t *)buffer;
2648 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2650 p->origin[0] = LittleFloat(p->origin[0]);
2651 p->origin[1] = LittleFloat(p->origin[1]);
2652 p->origin[2] = LittleFloat(p->origin[2]);
2656 else if (!strcmp(pchunk->id, "VTXW0000"))
2659 if (recordsize != sizeof(*p))
2660 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2661 // byteswap in place and keep the pointer
2662 numvtxw = numrecords;
2663 vtxw = (pskvtxw_t *)buffer;
2664 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2666 p->pntsindex = LittleShort(p->pntsindex);
2667 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2668 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2669 if (p->pntsindex >= numpnts)
2671 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2677 else if (!strcmp(pchunk->id, "FACE0000"))
2680 if (recordsize != sizeof(*p))
2681 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2682 // byteswap in place and keep the pointer
2683 numfaces = numrecords;
2684 faces = (pskface_t *)buffer;
2685 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2687 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2688 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2689 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2690 p->group = LittleLong(p->group);
2691 if (p->vtxwindex[0] >= numvtxw)
2693 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2694 p->vtxwindex[0] = 0;
2696 if (p->vtxwindex[1] >= numvtxw)
2698 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2699 p->vtxwindex[1] = 0;
2701 if (p->vtxwindex[2] >= numvtxw)
2703 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2704 p->vtxwindex[2] = 0;
2709 else if (!strcmp(pchunk->id, "MATT0000"))
2712 if (recordsize != sizeof(*p))
2713 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2714 // byteswap in place and keep the pointer
2715 nummatts = numrecords;
2716 matts = (pskmatt_t *)buffer;
2717 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2723 else if (!strcmp(pchunk->id, "REFSKELT"))
2726 if (recordsize != sizeof(*p))
2727 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2728 // byteswap in place and keep the pointer
2729 numbones = numrecords;
2730 bones = (pskboneinfo_t *)buffer;
2731 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2733 p->numchildren = LittleLong(p->numchildren);
2734 p->parent = LittleLong(p->parent);
2735 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2736 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2737 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2738 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2739 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2740 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2741 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2742 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2743 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2744 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2745 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2746 #ifdef PSKQUATNEGATIONS
2749 p->basepose.quat[0] *= -1;
2750 p->basepose.quat[1] *= -1;
2751 p->basepose.quat[2] *= -1;
2755 p->basepose.quat[0] *= 1;
2756 p->basepose.quat[1] *= -1;
2757 p->basepose.quat[2] *= 1;
2760 if (p->parent < 0 || p->parent >= numbones)
2762 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2768 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2771 if (recordsize != sizeof(*p))
2772 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2773 // byteswap in place and keep the pointer
2774 numrawweights = numrecords;
2775 rawweights = (pskrawweights_t *)buffer;
2776 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2778 p->weight = LittleFloat(p->weight);
2779 p->pntsindex = LittleLong(p->pntsindex);
2780 p->boneindex = LittleLong(p->boneindex);
2781 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2783 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2786 if (p->boneindex < 0 || p->boneindex >= numbones)
2788 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2796 while (animbuffer < animbufferend)
2798 pchunk = (pskchunk_t *)animbuffer;
2799 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2800 version = LittleLong(pchunk->version);
2801 recordsize = LittleLong(pchunk->recordsize);
2802 numrecords = LittleLong(pchunk->numrecords);
2803 if (developer_extra.integer)
2804 Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2805 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2806 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);
2807 if (!strcmp(pchunk->id, "ANIMHEAD"))
2811 else if (!strcmp(pchunk->id, "BONENAMES"))
2814 if (recordsize != sizeof(*p))
2815 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2816 // byteswap in place and keep the pointer
2817 numanimbones = numrecords;
2818 //animbones = (pskboneinfo_t *)animbuffer;
2819 // NOTE: supposedly psa does not need to match the psk model, the
2820 // bones missing from the psa would simply use their base
2821 // positions from the psk, but this is hard for me to implement
2822 // and people can easily make animations that match.
2823 if (numanimbones != numbones)
2824 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2825 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2827 p->numchildren = LittleLong(p->numchildren);
2828 p->parent = LittleLong(p->parent);
2829 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2830 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2831 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2832 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2833 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2834 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2835 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2836 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2837 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2838 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2839 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2840 #ifdef PSKQUATNEGATIONS
2843 p->basepose.quat[0] *= -1;
2844 p->basepose.quat[1] *= -1;
2845 p->basepose.quat[2] *= -1;
2849 p->basepose.quat[0] *= 1;
2850 p->basepose.quat[1] *= -1;
2851 p->basepose.quat[2] *= 1;
2854 if (p->parent < 0 || p->parent >= numanimbones)
2856 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2859 // check that bones are the same as in the base
2860 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2861 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2865 else if (!strcmp(pchunk->id, "ANIMINFO"))
2868 if (recordsize != sizeof(*p))
2869 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2870 // byteswap in place and keep the pointer
2871 numanims = numrecords;
2872 anims = (pskaniminfo_t *)animbuffer;
2873 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2875 p->numbones = LittleLong(p->numbones);
2876 p->playtime = LittleFloat(p->playtime);
2877 p->fps = LittleFloat(p->fps);
2878 p->firstframe = LittleLong(p->firstframe);
2879 p->numframes = LittleLong(p->numframes);
2880 if (p->numbones != numbones)
2881 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2885 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2888 if (recordsize != sizeof(*p))
2889 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2890 numanimkeys = numrecords;
2891 animkeys = (pskanimkeys_t *)animbuffer;
2892 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2894 p->origin[0] = LittleFloat(p->origin[0]);
2895 p->origin[1] = LittleFloat(p->origin[1]);
2896 p->origin[2] = LittleFloat(p->origin[2]);
2897 p->quat[0] = LittleFloat(p->quat[0]);
2898 p->quat[1] = LittleFloat(p->quat[1]);
2899 p->quat[2] = LittleFloat(p->quat[2]);
2900 p->quat[3] = LittleFloat(p->quat[3]);
2901 p->frametime = LittleFloat(p->frametime);
2902 #ifdef PSKQUATNEGATIONS
2903 if (index % numbones)
2918 // TODO: allocate bonepose stuff
2921 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2924 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2925 Host_Error("%s: missing required chunks", loadmodel->name);
2929 loadmodel->numframes = 0;
2930 for (index = 0;index < numanims;index++)
2931 loadmodel->numframes += anims[index].numframes;
2932 if (numanimkeys != numbones * loadmodel->numframes)
2933 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2936 loadmodel->numframes = loadmodel->num_poses = 1;
2938 meshvertices = numvtxw;
2939 meshtriangles = numfaces;
2941 // load external .skin files if present
2942 skinfiles = Mod_LoadSkinFiles();
2943 if (loadmodel->numskins < 1)
2944 loadmodel->numskins = 1;
2945 loadmodel->num_bones = numbones;
2946 loadmodel->num_poses = loadmodel->numframes;
2947 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2948 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2949 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2950 loadmodel->surfmesh.num_vertices = meshvertices;
2951 loadmodel->surfmesh.num_triangles = meshtriangles;
2952 // do most allocations as one merged chunk
2953 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);
2954 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2955 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2956 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2957 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2958 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2959 loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2960 loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2961 loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2962 loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2963 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2964 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2965 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2966 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2967 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2968 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2969 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2970 loadmodel->surfmesh.num_blends = 0;
2971 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2972 if (loadmodel->surfmesh.num_vertices <= 65536)
2974 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2976 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2977 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2979 for (i = 0;i < loadmodel->numskins;i++)
2981 loadmodel->skinscenes[i].firstframe = i;
2982 loadmodel->skinscenes[i].framecount = 1;
2983 loadmodel->skinscenes[i].loop = true;
2984 loadmodel->skinscenes[i].framerate = 10;
2988 for (index = 0, i = 0;index < nummatts;index++)
2990 // since psk models do not have named sections, reuse their shader name as the section name
2991 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2992 loadmodel->sortedmodelsurfaces[index] = index;
2993 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2994 loadmodel->data_surfaces[index].num_firstvertex = 0;
2995 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2998 // copy over the vertex locations and texcoords
2999 for (index = 0;index < numvtxw;index++)
3001 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
3002 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
3003 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
3004 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
3005 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
3008 // loading the faces is complicated because we need to sort them into surfaces by mattindex
3009 for (index = 0;index < numfaces;index++)
3010 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
3011 for (index = 0, i = 0;index < nummatts;index++)
3013 loadmodel->data_surfaces[index].num_firsttriangle = i;
3014 i += loadmodel->data_surfaces[index].num_triangles;
3015 loadmodel->data_surfaces[index].num_triangles = 0;
3017 for (index = 0;index < numfaces;index++)
3019 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3020 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3021 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3022 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3025 // copy over the bones
3026 for (index = 0;index < numbones;index++)
3028 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3029 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3030 if (loadmodel->data_bones[index].parent >= index)
3031 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3034 // convert the basepose data
3035 if (loadmodel->num_bones)
3038 matrix4x4_t *basebonepose;
3039 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3040 matrix4x4_t bonematrix;
3041 matrix4x4_t tempbonematrix;
3042 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3043 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3045 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]);
3046 if (loadmodel->data_bones[boneindex].parent >= 0)
3048 tempbonematrix = bonematrix;
3049 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3051 basebonepose[boneindex] = bonematrix;
3052 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3053 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3055 Mem_Free(basebonepose);
3058 // sort the psk point weights into the vertex weight tables
3059 // (which only accept up to 4 bones per vertex)
3060 for (index = 0;index < numvtxw;index++)
3062 int weightindex[4] = { 0, 0, 0, 0 };
3063 float weightinfluence[4] = { 0, 0, 0, 0 };
3065 for (j = 0;j < numrawweights;j++)
3067 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3069 int boneindex = rawweights[j].boneindex;
3070 float influence = rawweights[j].weight;
3071 for (l = 0;l < 4;l++)
3073 if (weightinfluence[l] < influence)
3075 // move lower influence weights out of the way first
3077 for (l2 = 3;l2 > l;l2--)
3079 weightinfluence[l2] = weightinfluence[l2-1];
3080 weightindex[l2] = weightindex[l2-1];
3082 // store the new weight
3083 weightinfluence[l] = influence;
3084 weightindex[l] = boneindex;
3090 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3091 loadmodel->surfmesh.data_skeletalindex4ub[index*4 ] = weightindex[0];
3092 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3093 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3094 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3095 loadmodel->surfmesh.data_skeletalweight4ub[index*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
3096 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3097 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3098 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3100 if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3101 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3103 // set up the animscenes based on the anims
3106 for (index = 0, i = 0;index < numanims;index++)
3108 for (j = 0;j < anims[index].numframes;j++, i++)
3110 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3111 loadmodel->animscenes[i].firstframe = i;
3112 loadmodel->animscenes[i].framecount = 1;
3113 loadmodel->animscenes[i].loop = true;
3114 loadmodel->animscenes[i].framerate = anims[index].fps;
3117 // calculate the scaling value for bone origins so they can be compressed to short
3119 for (index = 0;index < numanimkeys;index++)
3121 pskanimkeys_t *k = animkeys + index;
3122 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3123 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3124 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3126 loadmodel->num_posescale = biggestorigin / 32767.0f;
3127 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3129 // load the poses from the animkeys
3130 for (index = 0;index < numanimkeys;index++)
3132 pskanimkeys_t *k = animkeys + index;
3134 Vector4Copy(k->quat, quat);
3136 Vector4Negate(quat, quat);
3137 Vector4Normalize2(quat, quat);
3138 // compress poses to the short[7] format for longterm storage
3139 loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3140 loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3141 loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3142 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3143 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3144 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3145 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3150 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3151 loadmodel->animscenes[0].firstframe = 0;
3152 loadmodel->animscenes[0].framecount = 1;
3153 loadmodel->animscenes[0].loop = true;
3154 loadmodel->animscenes[0].framerate = 10;
3156 // calculate the scaling value for bone origins so they can be compressed to short
3158 for (index = 0;index < numbones;index++)
3160 pskboneinfo_t *p = bones + index;
3161 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3162 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3163 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3165 loadmodel->num_posescale = biggestorigin / 32767.0f;
3166 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3168 // load the basepose as a frame
3169 for (index = 0;index < numbones;index++)
3171 pskboneinfo_t *p = bones + index;
3173 Vector4Copy(p->basepose.quat, quat);
3175 Vector4Negate(quat, quat);
3176 Vector4Normalize2(quat, quat);
3177 // compress poses to the short[7] format for longterm storage
3178 loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3179 loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3180 loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3181 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3182 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3183 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3184 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3188 Mod_FreeSkinFiles(skinfiles);
3190 Mem_Free(animfilebuffer);
3191 Mod_MakeSortedSurfaces(loadmodel);
3193 // compute all the mesh information that was not loaded from the file
3194 // TODO: honor smoothing groups somehow?
3195 if (loadmodel->surfmesh.data_element3s)
3196 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3197 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3198 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3199 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);
3200 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);
3201 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3202 if(mod_alias_force_animated.string[0])
3203 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3205 // Always make a BIH for the first frame, we can use it where possible.
3206 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3207 if (!loadmodel->surfmesh.isanimated)
3209 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3210 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3211 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3212 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3213 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3216 // because shaders can do somewhat unexpected things, check for unusual features now
3217 for (i = 0;i < loadmodel->num_textures;i++)
3219 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3220 mod->DrawSky = R_Q1BSP_DrawSky;
3221 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3222 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3226 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
3228 unsigned char *data;
3230 const unsigned char *pbase, *pend;
3232 skinfile_t *skinfiles;
3233 int i, j, k, meshvertices, meshtriangles;
3234 float biggestorigin;
3235 const unsigned int *inelements;
3237 float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3238 // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3239 const float *vnormal = NULL;
3240 const float *vposition = NULL;
3241 const float *vtangent = NULL;
3242 const float *vtexcoord = NULL;
3243 const float *vcolor4f = NULL;
3244 const unsigned char *vblendindexes = NULL;
3245 const unsigned char *vblendweights = NULL;
3246 const unsigned char *vcolor4ub = NULL;
3247 const unsigned short *framedata = NULL;
3248 // temporary memory allocations (because the data in the file may be misaligned)
3249 iqmanim_t *anims = NULL;
3250 iqmbounds_t *bounds = NULL;
3251 iqmjoint1_t *joint1 = NULL;
3252 iqmjoint_t *joint = NULL;
3253 iqmmesh_t *meshes = NULL;
3254 iqmpose1_t *pose1 = NULL;
3255 iqmpose_t *pose = NULL;
3256 iqmvertexarray_t *vas = NULL;
3258 pbase = (unsigned char *)buffer;
3259 pend = (unsigned char *)bufferend;
3261 if (pbase + sizeof(iqmheader_t) > pend)
3262 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3264 // copy struct (otherwise it may be misaligned)
3265 // LadyHavoc: okay it's definitely not misaligned here, but for consistency...
3266 memcpy(&header, pbase, sizeof(iqmheader_t));
3268 if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3269 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3270 if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3271 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3273 loadmodel->modeldatatypestring = "IQM";
3275 loadmodel->type = mod_alias;
3276 loadmodel->synctype = ST_RAND;
3279 header.version = LittleLong(header.version);
3280 header.filesize = LittleLong(header.filesize);
3281 header.flags = LittleLong(header.flags);
3282 header.num_text = LittleLong(header.num_text);
3283 header.ofs_text = LittleLong(header.ofs_text);
3284 header.num_meshes = LittleLong(header.num_meshes);
3285 header.ofs_meshes = LittleLong(header.ofs_meshes);
3286 header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3287 header.num_vertexes = LittleLong(header.num_vertexes);
3288 header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3289 header.num_triangles = LittleLong(header.num_triangles);
3290 header.ofs_triangles = LittleLong(header.ofs_triangles);
3291 header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3292 header.num_joints = LittleLong(header.num_joints);
3293 header.ofs_joints = LittleLong(header.ofs_joints);
3294 header.num_poses = LittleLong(header.num_poses);
3295 header.ofs_poses = LittleLong(header.ofs_poses);
3296 header.num_anims = LittleLong(header.num_anims);
3297 header.ofs_anims = LittleLong(header.ofs_anims);
3298 header.num_frames = LittleLong(header.num_frames);
3299 header.num_framechannels = LittleLong(header.num_framechannels);
3300 header.ofs_frames = LittleLong(header.ofs_frames);
3301 header.ofs_bounds = LittleLong(header.ofs_bounds);
3302 header.num_comment = LittleLong(header.num_comment);
3303 header.ofs_comment = LittleLong(header.ofs_comment);
3304 header.num_extensions = LittleLong(header.num_extensions);
3305 header.ofs_extensions = LittleLong(header.ofs_extensions);
3307 if (header.version == 1)
3309 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3310 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3312 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3318 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3319 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3321 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3325 if (pbase + header.ofs_text + header.num_text > pend ||
3326 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3327 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3328 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3329 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3330 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3331 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3332 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3333 pbase + header.ofs_comment + header.num_comment > pend)
3335 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3339 // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3340 if (header.num_vertexarrays)
3341 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3342 if (header.num_anims)
3343 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3344 if (header.ofs_bounds)
3345 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3346 if (header.num_meshes)
3347 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3349 for (i = 0;i < (int)header.num_vertexarrays;i++)
3351 iqmvertexarray_t va;
3353 va.type = LittleLong(vas[i].type);
3354 va.flags = LittleLong(vas[i].flags);
3355 va.format = LittleLong(vas[i].format);
3356 va.size = LittleLong(vas[i].size);
3357 va.offset = LittleLong(vas[i].offset);
3358 vsize = header.num_vertexes*va.size;
3361 case IQM_FLOAT: vsize *= sizeof(float); break;
3362 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3365 if (pbase + va.offset + vsize > pend)
3367 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3371 if (va.format == IQM_FLOAT && va.size == 3)
3372 vposition = (const float *)(pbase + va.offset);
3375 if (va.format == IQM_FLOAT && va.size == 2)
3376 vtexcoord = (const float *)(pbase + va.offset);
3379 if (va.format == IQM_FLOAT && va.size == 3)
3380 vnormal = (const float *)(pbase + va.offset);
3383 if (va.format == IQM_FLOAT && va.size == 4)
3384 vtangent = (const float *)(pbase + va.offset);
3386 case IQM_BLENDINDEXES:
3387 if (va.format == IQM_UBYTE && va.size == 4)
3388 vblendindexes = (const unsigned char *)(pbase + va.offset);
3390 case IQM_BLENDWEIGHTS:
3391 if (va.format == IQM_UBYTE && va.size == 4)
3392 vblendweights = (const unsigned char *)(pbase + va.offset);
3395 if (va.format == IQM_FLOAT && va.size == 4)
3396 vcolor4f = (const float *)(pbase + va.offset);
3397 if (va.format == IQM_UBYTE && va.size == 4)
3398 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3402 if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3404 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3408 text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3410 loadmodel->DrawSky = NULL;
3411 loadmodel->DrawAddWaterPlanes = NULL;
3412 loadmodel->Draw = R_Q1BSP_Draw;
3413 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
3414 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
3415 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
3416 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
3417 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
3418 loadmodel->DrawLight = R_Q1BSP_DrawLight;
3419 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3420 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3421 loadmodel->PointSuperContents = NULL;
3422 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3424 // load external .skin files if present
3425 skinfiles = Mod_LoadSkinFiles();
3426 if (loadmodel->numskins < 1)
3427 loadmodel->numskins = 1;
3429 loadmodel->numframes = max(header.num_anims, 1);
3430 loadmodel->num_bones = header.num_joints;
3431 loadmodel->num_poses = max(header.num_frames, 1);
3432 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
3433 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3434 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3436 meshvertices = header.num_vertexes;
3437 meshtriangles = header.num_triangles;
3439 // do most allocations as one merged chunk
3440 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));
3441 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3442 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3443 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3444 loadmodel->surfmesh.num_vertices = meshvertices;
3445 loadmodel->surfmesh.num_triangles = meshtriangles;
3446 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3447 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3448 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3449 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3450 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3451 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3452 if (vcolor4f || vcolor4ub)
3454 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3456 if (vblendindexes && vblendweights)
3458 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3459 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3461 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3462 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3463 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3464 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3465 if (vblendindexes && vblendweights)
3467 loadmodel->surfmesh.num_blends = 0;
3468 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3470 if (meshvertices <= 65536)
3472 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3474 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3475 if (vblendindexes && vblendweights)
3476 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3478 for (i = 0;i < loadmodel->numskins;i++)
3480 loadmodel->skinscenes[i].firstframe = i;
3481 loadmodel->skinscenes[i].framecount = 1;
3482 loadmodel->skinscenes[i].loop = true;
3483 loadmodel->skinscenes[i].framerate = 10;
3486 // load the bone info
3487 if (header.version == 1)
3489 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3490 if (loadmodel->num_bones)
3491 joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3492 for (i = 0;i < loadmodel->num_bones;i++)
3494 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3495 joint1[i].name = LittleLong(injoint1[i].name);
3496 joint1[i].parent = LittleLong(injoint1[i].parent);
3497 for (j = 0;j < 3;j++)
3499 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3500 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3501 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3503 strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3504 loadmodel->data_bones[i].parent = joint1[i].parent;
3505 if (loadmodel->data_bones[i].parent >= i)
3506 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3507 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]);
3508 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3509 if (loadmodel->data_bones[i].parent >= 0)
3511 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3512 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3513 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3515 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3520 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3521 if (header.num_joints)
3522 joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3523 for (i = 0;i < loadmodel->num_bones;i++)
3525 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3526 joint[i].name = LittleLong(injoint[i].name);
3527 joint[i].parent = LittleLong(injoint[i].parent);
3528 for (j = 0;j < 3;j++)
3530 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3531 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3532 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3534 joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3535 strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3536 loadmodel->data_bones[i].parent = joint[i].parent;
3537 if (loadmodel->data_bones[i].parent >= i)
3538 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3539 if (joint[i].rotation[3] > 0)
3540 Vector4Negate(joint[i].rotation, joint[i].rotation);
3541 Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3542 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]);
3543 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3544 if (loadmodel->data_bones[i].parent >= 0)
3546 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3547 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3548 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3550 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3554 // set up the animscenes based on the anims
3555 for (i = 0;i < (int)header.num_anims;i++)
3558 anim.name = LittleLong(anims[i].name);
3559 anim.first_frame = LittleLong(anims[i].first_frame);
3560 anim.num_frames = LittleLong(anims[i].num_frames);
3561 anim.framerate = LittleFloat(anims[i].framerate);
3562 anim.flags = LittleLong(anims[i].flags);
3563 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3564 loadmodel->animscenes[i].firstframe = anim.first_frame;
3565 loadmodel->animscenes[i].framecount = anim.num_frames;
3566 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3567 loadmodel->animscenes[i].framerate = anim.framerate;
3569 if (header.num_anims <= 0)
3571 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3572 loadmodel->animscenes[0].firstframe = 0;
3573 loadmodel->animscenes[0].framecount = 1;
3574 loadmodel->animscenes[0].loop = true;
3575 loadmodel->animscenes[0].framerate = 10;
3578 loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3579 if(mod_alias_force_animated.string[0])
3580 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3583 if (header.version == 1)
3585 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3586 if (header.num_poses)
3587 pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3588 for (i = 0;i < (int)header.num_poses;i++)
3591 pose1[i].parent = LittleLong(inpose1[i].parent);
3592 pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3593 for (j = 0;j < 9;j++)
3595 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3596 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3598 f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3599 f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3600 f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3601 f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3602 f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3603 f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3605 if (header.num_frames <= 0)
3607 for (i = 0;i < loadmodel->num_bones;i++)
3610 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3611 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3612 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3618 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3619 if (header.num_poses)
3620 pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3621 for (i = 0;i < (int)header.num_poses;i++)
3624 pose[i].parent = LittleLong(inpose[i].parent);
3625 pose[i].channelmask = LittleLong(inpose[i].channelmask);
3626 for (j = 0;j < 10;j++)
3628 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3629 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3631 f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3632 f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3633 f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3634 f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3635 f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3636 f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3638 if (header.num_frames <= 0)
3640 for (i = 0;i < loadmodel->num_bones;i++)
3643 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3644 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3645 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3649 loadmodel->num_posescale = biggestorigin / 32767.0f;
3650 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3652 // load the pose data
3653 // this unaligned memory access is safe (LittleShort reads as bytes)
3654 framedata = (const unsigned short *)(pbase + header.ofs_frames);
3655 if (header.version == 1)
3657 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3659 for (j = 0;j < (int)header.num_poses;j++, k++)
3661 float qx, qy, qz, qw;
3662 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));
3663 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));
3664 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));
3665 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3666 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3667 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3668 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3669 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3670 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3671 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3672 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3673 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3674 // skip scale data for now
3675 if(pose1[j].channelmask&64) framedata++;
3676 if(pose1[j].channelmask&128) framedata++;
3677 if(pose1[j].channelmask&256) framedata++;
3680 if (header.num_frames <= 0)
3682 for (i = 0;i < loadmodel->num_bones;i++)
3684 float qx, qy, qz, qw;
3685 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3686 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3687 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3688 qx = joint1[i].rotation[0];
3689 qy = joint1[i].rotation[1];
3690 qz = joint1[i].rotation[2];
3691 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3692 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3693 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3694 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3695 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3696 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3702 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3704 for (j = 0;j < (int)header.num_poses;j++, k++)
3707 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));
3708 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));
3709 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));
3710 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3711 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3712 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3713 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3715 Vector4Negate(rot, rot);
3716 Vector4Normalize2(rot, rot);
3717 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3718 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3719 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3720 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3721 // skip scale data for now
3722 if(pose[j].channelmask&128) framedata++;
3723 if(pose[j].channelmask&256) framedata++;
3724 if(pose[j].channelmask&512) framedata++;
3727 if (header.num_frames <= 0)
3729 for (i = 0;i < loadmodel->num_bones;i++)
3731 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3732 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3733 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3734 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3735 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3736 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3737 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3742 // load bounding box data
3743 if (header.ofs_bounds)
3745 float xyradius = 0, radius = 0;
3746 VectorClear(loadmodel->normalmins);
3747 VectorClear(loadmodel->normalmaxs);
3748 for (i = 0; i < (int)header.num_frames;i++)
3751 bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3752 bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3753 bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3754 bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);
3755 bound.maxs[1] = LittleFloat(bounds[i].maxs[1]);
3756 bound.maxs[2] = LittleFloat(bounds[i].maxs[2]);
3757 bound.xyradius = LittleFloat(bounds[i].xyradius);
3758 bound.radius = LittleFloat(bounds[i].radius);
3761 VectorCopy(bound.mins, loadmodel->normalmins);
3762 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3766 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3767 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3768 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3769 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3770 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3771 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3773 if (bound.xyradius > xyradius)
3774 xyradius = bound.xyradius;
3775 if (bound.radius > radius)
3776 radius = bound.radius;
3778 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3779 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3780 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3781 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3782 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3783 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3784 loadmodel->radius = radius;
3785 loadmodel->radius2 = radius * radius;
3788 // load triangle data
3789 // this unaligned memory access is safe (LittleLong reads as bytes)
3790 inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3791 outelements = loadmodel->surfmesh.data_element3i;
3792 for (i = 0;i < (int)header.num_triangles;i++)
3794 outelements[0] = LittleLong(inelements[0]);
3795 outelements[1] = LittleLong(inelements[1]);
3796 outelements[2] = LittleLong(inelements[2]);
3800 if (loadmodel->surfmesh.data_element3s)
3801 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3802 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3803 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3806 // this unaligned memory access is safe (LittleFloat reads as bytes)
3807 outvertex = loadmodel->surfmesh.data_vertex3f;
3808 for (i = 0;i < (int)header.num_vertexes;i++)
3810 outvertex[0] = LittleFloat(vposition[0]);
3811 outvertex[1] = LittleFloat(vposition[1]);
3812 outvertex[2] = LittleFloat(vposition[2]);
3817 outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3818 // this unaligned memory access is safe (LittleFloat reads as bytes)
3819 for (i = 0;i < (int)header.num_vertexes;i++)
3821 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3822 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3827 // this unaligned memory access is safe (LittleFloat reads as bytes)
3830 outnormal = loadmodel->surfmesh.data_normal3f;
3831 for (i = 0;i < (int)header.num_vertexes;i++)
3833 outnormal[0] = LittleFloat(vnormal[0]);
3834 outnormal[1] = LittleFloat(vnormal[1]);
3835 outnormal[2] = LittleFloat(vnormal[2]);
3841 // this unaligned memory access is safe (LittleFloat reads as bytes)
3842 if(vnormal && vtangent)
3844 outnormal = loadmodel->surfmesh.data_normal3f;
3845 outsvector = loadmodel->surfmesh.data_svector3f;
3846 outtvector = loadmodel->surfmesh.data_tvector3f;
3847 for (i = 0;i < (int)header.num_vertexes;i++)
3849 outsvector[0] = LittleFloat(vtangent[0]);
3850 outsvector[1] = LittleFloat(vtangent[1]);
3851 outsvector[2] = LittleFloat(vtangent[2]);
3852 if(LittleFloat(vtangent[3]) < 0)
3853 CrossProduct(outsvector, outnormal, outtvector);
3855 CrossProduct(outnormal, outsvector, outtvector);
3863 // this unaligned memory access is safe (all bytes)
3864 if (vblendindexes && vblendweights)
3866 for (i = 0; i < (int)header.num_vertexes;i++)
3868 blendweights_t weights;
3869 memcpy(weights.index, vblendindexes + i*4, 4);
3870 memcpy(weights.influence, vblendweights + i*4, 4);
3871 loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3872 loadmodel->surfmesh.data_skeletalindex4ub[i*4 ] = weights.index[0];
3873 loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3874 loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3875 loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3876 loadmodel->surfmesh.data_skeletalweight4ub[i*4 ] = weights.influence[0];
3877 loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3878 loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3879 loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3885 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3886 // this unaligned memory access is safe (LittleFloat reads as bytes)
3887 for (i = 0;i < (int)header.num_vertexes;i++)
3889 outcolor[0] = LittleFloat(vcolor4f[0]);
3890 outcolor[1] = LittleFloat(vcolor4f[1]);
3891 outcolor[2] = LittleFloat(vcolor4f[2]);
3892 outcolor[3] = LittleFloat(vcolor4f[3]);
3899 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3900 // this unaligned memory access is safe (all bytes)
3901 for (i = 0;i < (int)header.num_vertexes;i++)
3903 outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3904 outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3905 outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3906 outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3913 for (i = 0;i < (int)header.num_meshes;i++)
3916 msurface_t *surface;
3918 mesh.name = LittleLong(meshes[i].name);
3919 mesh.material = LittleLong(meshes[i].material);
3920 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3921 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3922 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3923 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3925 loadmodel->sortedmodelsurfaces[i] = i;
3926 surface = loadmodel->data_surfaces + i;
3927 surface->texture = loadmodel->data_textures + i;
3928 surface->num_firsttriangle = mesh.first_triangle;
3929 surface->num_triangles = mesh.num_triangles;
3930 surface->num_firstvertex = mesh.first_vertex;
3931 surface->num_vertices = mesh.num_vertexes;
3933 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3936 Mod_FreeSkinFiles(skinfiles);
3937 Mod_MakeSortedSurfaces(loadmodel);
3939 // compute all the mesh information that was not loaded from the file
3941 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);
3942 if (!vnormal || !vtangent)
3943 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);
3944 if (!header.ofs_bounds)
3945 Mod_Alias_CalculateBoundingBox();
3947 // Always make a BIH for the first frame, we can use it where possible.
3948 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3949 if (!loadmodel->surfmesh.isanimated)
3951 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3952 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3953 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3954 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3955 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3958 if (joint ) Mem_Free(joint );joint = NULL;
3959 if (joint1 ) Mem_Free(joint1 );joint1 = NULL;
3960 if (pose ) Mem_Free(pose );pose = NULL;
3961 if (pose1 ) Mem_Free(pose1 );pose1 = NULL;
3963 // because shaders can do somewhat unexpected things, check for unusual features now
3964 for (i = 0;i < loadmodel->num_textures;i++)
3966 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3967 mod->DrawSky = R_Q1BSP_DrawSky;
3968 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3969 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;