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 = {0, "r_skeletal_use_sse", "1", "use SSE for skeletal model animation"};
33 cvar_t r_skeletal_debugbone = {0, "r_skeletal_debugbone", "-1", "development cvar for testing skeletal model code"};
34 cvar_t r_skeletal_debugbonecomponent = {0, "r_skeletal_debugbonecomponent", "3", "development cvar for testing skeletal model code"};
35 cvar_t r_skeletal_debugbonevalue = {0, "r_skeletal_debugbonevalue", "100", "development cvar for testing skeletal model code"};
36 cvar_t r_skeletal_debugtranslatex = {0, "r_skeletal_debugtranslatex", "1", "development cvar for testing skeletal model code"};
37 cvar_t r_skeletal_debugtranslatey = {0, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"};
38 cvar_t r_skeletal_debugtranslatez = {0, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"};
39 cvar_t mod_alias_supporttagscale = {0, "mod_alias_supporttagscale", "1", "support scaling factors in bone/tag attachment matrices as supported by MD3"};
40 cvar_t mod_alias_force_animated = {0, "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, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
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, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
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);
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 for (i = 0;i < 3;i++)
1049 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1050 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1053 startskins = datapointer;
1055 for (i = 0;i < loadmodel->numskins;i++)
1057 pinskintype = (daliasskintype_t *)datapointer;
1058 datapointer += sizeof(daliasskintype_t);
1059 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1063 pinskingroup = (daliasskingroup_t *)datapointer;
1064 datapointer += sizeof(daliasskingroup_t);
1065 groupskins = LittleLong(pinskingroup->numskins);
1066 datapointer += sizeof(daliasskininterval_t) * groupskins;
1069 for (j = 0;j < groupskins;j++)
1071 datapointer += skinwidth * skinheight;
1076 pinstverts = (stvert_t *)datapointer;
1077 datapointer += sizeof(stvert_t) * numverts;
1079 pintriangles = (dtriangle_t *)datapointer;
1080 datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1082 startframes = datapointer;
1083 loadmodel->surfmesh.num_morphframes = 0;
1084 for (i = 0;i < loadmodel->numframes;i++)
1086 pinframetype = (daliasframetype_t *)datapointer;
1087 datapointer += sizeof(daliasframetype_t);
1088 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1092 pinframegroup = (daliasgroup_t *)datapointer;
1093 datapointer += sizeof(daliasgroup_t);
1094 groupframes = LittleLong(pinframegroup->numframes);
1095 datapointer += sizeof(daliasinterval_t) * groupframes;
1098 for (j = 0;j < groupframes;j++)
1100 datapointer += sizeof(daliasframe_t);
1101 datapointer += sizeof(trivertx_t) * numverts;
1102 loadmodel->surfmesh.num_morphframes++;
1105 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1107 // store texture coordinates into temporary array, they will be stored
1108 // after usage is determined (triangle data)
1109 vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1110 vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1111 vertonseam = vertremap + numverts * 2;
1113 scales = 1.0 / skinwidth;
1114 scalet = 1.0 / skinheight;
1115 for (i = 0;i < numverts;i++)
1117 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1118 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1119 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1120 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1121 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1124 // load triangle data
1125 loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1127 // read the triangle elements
1128 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1129 for (j = 0;j < 3;j++)
1130 loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1131 // validate (note numverts is used because this is the original data)
1132 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, NULL, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1133 // now butcher the elements according to vertonseam and tri->facesfront
1134 // and then compact the vertex set to remove duplicates
1135 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1136 if (!LittleLong(pintriangles[i].facesfront)) // backface
1137 for (j = 0;j < 3;j++)
1138 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1139 loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1141 // (this uses vertremap to count usage to save some memory)
1142 for (i = 0;i < numverts*2;i++)
1144 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1145 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1146 // build remapping table and compact array
1147 loadmodel->surfmesh.num_vertices = 0;
1148 for (i = 0;i < numverts*2;i++)
1152 vertremap[i] = loadmodel->surfmesh.num_vertices;
1153 vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1154 vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1155 loadmodel->surfmesh.num_vertices++;
1158 vertremap[i] = -1; // not used at all
1160 // remap the elements to the new vertex set
1161 for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1162 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1163 // store the texture coordinates
1164 loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1165 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1167 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1168 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1171 // generate ushort elements array if possible
1172 if (loadmodel->surfmesh.num_vertices <= 65536)
1173 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1174 if (loadmodel->surfmesh.data_element3s)
1175 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1176 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1179 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1180 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1181 Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1182 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1183 Mod_Alias_MorphMesh_CompileFrames();
1186 Mem_Free(vertremap);
1189 skinfiles = Mod_LoadSkinFiles();
1192 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1193 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1194 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1195 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1196 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1197 Mod_FreeSkinFiles(skinfiles);
1198 for (i = 0;i < loadmodel->numskins;i++)
1200 loadmodel->skinscenes[i].firstframe = i;
1201 loadmodel->skinscenes[i].framecount = 1;
1202 loadmodel->skinscenes[i].loop = true;
1203 loadmodel->skinscenes[i].framerate = 10;
1208 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1209 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1210 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1211 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1213 datapointer = startskins;
1214 for (i = 0;i < loadmodel->numskins;i++)
1216 pinskintype = (daliasskintype_t *)datapointer;
1217 datapointer += sizeof(daliasskintype_t);
1219 if (pinskintype->type == ALIAS_SKIN_SINGLE)
1226 pinskingroup = (daliasskingroup_t *)datapointer;
1227 datapointer += sizeof(daliasskingroup_t);
1229 groupskins = LittleLong (pinskingroup->numskins);
1231 pinskinintervals = (daliasskininterval_t *)datapointer;
1232 datapointer += sizeof(daliasskininterval_t) * groupskins;
1234 interval = LittleFloat(pinskinintervals[0].interval);
1235 if (interval < 0.01f)
1237 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1242 dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1243 loadmodel->skinscenes[i].firstframe = totalskins;
1244 loadmodel->skinscenes[i].framecount = groupskins;
1245 loadmodel->skinscenes[i].framerate = 1.0f / interval;
1246 loadmodel->skinscenes[i].loop = true;
1248 for (j = 0;j < groupskins;j++)
1251 dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1253 dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1254 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))
1255 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));
1256 datapointer += skinwidth * skinheight;
1260 // check for skins that don't exist in the model, but do exist as external images
1261 // (this was added because yummyluv kept pestering me about support for it)
1262 // TODO: support shaders here?
1265 dpsnprintf(name, sizeof(name), "%s_%i", loadmodel->name, loadmodel->numskins);
1266 tempskinframe = R_SkinFrame_LoadExternal(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false, false);
1269 // expand the arrays to make room
1270 tempskinscenes = loadmodel->skinscenes;
1271 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1272 memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1273 Mem_Free(tempskinscenes);
1275 tempaliasskins = loadmodel->data_textures;
1276 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1277 memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1278 Mem_Free(tempaliasskins);
1280 // store the info about the new skin
1281 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, tempskinframe);
1282 strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1283 loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1284 loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1285 loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1286 loadmodel->skinscenes[loadmodel->numskins].loop = true;
1288 //increase skin counts
1289 loadmodel->num_textures++;
1290 loadmodel->numskins++;
1293 // fix up the pointers since they are pointing at the old textures array
1294 // FIXME: this is a hack!
1295 for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1296 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1300 surface = loadmodel->data_surfaces;
1301 surface->texture = loadmodel->data_textures;
1302 surface->num_firsttriangle = 0;
1303 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1304 surface->num_firstvertex = 0;
1305 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1307 if(mod_alias_force_animated.string[0])
1308 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1310 // Always make a BIH for the first frame, we can use it where possible.
1311 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1312 if (!loadmodel->surfmesh.isanimated)
1314 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1315 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1316 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1317 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1318 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1321 // because shaders can do somewhat unexpected things, check for unusual features now
1322 for (i = 0;i < loadmodel->num_textures;i++)
1324 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1325 mod->DrawSky = R_Q1BSP_DrawSky;
1326 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1327 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1331 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1333 int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1334 float iskinwidth, iskinheight;
1335 unsigned char *data;
1336 msurface_t *surface;
1338 unsigned char *base, *datapointer;
1339 md2frame_t *pinframe;
1341 md2triangle_t *intri;
1342 unsigned short *inst;
1343 struct md2verthash_s
1345 struct md2verthash_s *next;
1349 *hash, **md2verthash, *md2verthashdata;
1350 skinfile_t *skinfiles;
1352 pinmodel = (md2_t *)buffer;
1353 base = (unsigned char *)buffer;
1355 version = LittleLong (pinmodel->version);
1356 if (version != MD2ALIAS_VERSION)
1357 Host_Error ("%s has wrong version number (%i should be %i)",
1358 loadmodel->name, version, MD2ALIAS_VERSION);
1360 loadmodel->modeldatatypestring = "MD2";
1362 loadmodel->type = mod_alias;
1363 loadmodel->DrawSky = NULL;
1364 loadmodel->DrawAddWaterPlanes = NULL;
1365 loadmodel->Draw = R_Q1BSP_Draw;
1366 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1367 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1368 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1369 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1370 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1371 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1372 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1373 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1374 loadmodel->PointSuperContents = NULL;
1375 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1377 if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1378 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1379 if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1380 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1381 if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1382 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1383 if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1384 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1386 end = LittleLong(pinmodel->ofs_end);
1387 if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1388 Host_Error ("%s is not a valid model", loadmodel->name);
1389 if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1390 Host_Error ("%s is not a valid model", loadmodel->name);
1391 if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1392 Host_Error ("%s is not a valid model", loadmodel->name);
1393 if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1394 Host_Error ("%s is not a valid model", loadmodel->name);
1395 if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1396 Host_Error ("%s is not a valid model", loadmodel->name);
1398 loadmodel->numskins = LittleLong(pinmodel->num_skins);
1399 numxyz = LittleLong(pinmodel->num_xyz);
1400 numst = LittleLong(pinmodel->num_st);
1401 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1402 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1403 loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1404 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1405 skinwidth = LittleLong(pinmodel->skinwidth);
1406 skinheight = LittleLong(pinmodel->skinheight);
1407 iskinwidth = 1.0f / skinwidth;
1408 iskinheight = 1.0f / skinheight;
1410 loadmodel->num_surfaces = 1;
1411 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1412 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]));
1413 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1414 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1415 loadmodel->sortedmodelsurfaces[0] = 0;
1416 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1417 loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1418 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1420 loadmodel->synctype = ST_RAND;
1423 inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1424 skinfiles = Mod_LoadSkinFiles();
1427 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1428 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1429 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1430 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1431 Mod_FreeSkinFiles(skinfiles);
1433 else if (loadmodel->numskins)
1435 // skins found (most likely not a player model)
1436 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1437 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1438 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1439 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1440 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);
1444 // no skins (most likely a player model)
1445 loadmodel->numskins = 1;
1446 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1447 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1448 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1449 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures, loadmodel->name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
1452 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1453 for (i = 0;i < loadmodel->numskins;i++)
1455 loadmodel->skinscenes[i].firstframe = i;
1456 loadmodel->skinscenes[i].framecount = 1;
1457 loadmodel->skinscenes[i].loop = true;
1458 loadmodel->skinscenes[i].framerate = 10;
1461 // load the triangles and stvert data
1462 inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1463 intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1464 md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1465 md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1466 // swap the triangle list
1467 loadmodel->surfmesh.num_vertices = 0;
1468 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1470 for (j = 0;j < 3;j++)
1472 xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1473 st = (unsigned short) LittleShort (intri[i].index_st[j]);
1476 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1481 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1484 hashindex = (xyz * 256 + st) & 65535;
1485 for (hash = md2verthash[hashindex];hash;hash = hash->next)
1486 if (hash->xyz == xyz && hash->st == st)
1490 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1493 hash->next = md2verthash[hashindex];
1494 md2verthash[hashindex] = hash;
1496 loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1500 vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1501 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));
1502 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1503 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1504 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1507 hash = md2verthashdata + i;
1508 vertremap[i] = hash->xyz;
1509 sts = LittleShort(inst[hash->st*2+0]);
1510 stt = LittleShort(inst[hash->st*2+1]);
1511 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1513 Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1517 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1518 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1521 Mem_Free(md2verthash);
1522 Mem_Free(md2verthashdata);
1524 // generate ushort elements array if possible
1525 if (loadmodel->surfmesh.num_vertices <= 65536)
1526 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1527 if (loadmodel->surfmesh.data_element3s)
1528 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1529 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1532 datapointer = (base + LittleLong(pinmodel->ofs_frames));
1533 for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1538 pinframe = (md2frame_t *)datapointer;
1539 datapointer += sizeof(md2frame_t);
1540 // store the frame scale/translate into the appropriate array
1541 for (j = 0;j < 3;j++)
1543 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1544 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1546 // convert the vertices
1547 v = (trivertx_t *)datapointer;
1548 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1549 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1550 out[k] = v[vertremap[k]];
1551 datapointer += numxyz * sizeof(trivertx_t);
1553 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1554 loadmodel->animscenes[i].firstframe = i;
1555 loadmodel->animscenes[i].framecount = 1;
1556 loadmodel->animscenes[i].framerate = 10;
1557 loadmodel->animscenes[i].loop = true;
1560 Mem_Free(vertremap);
1562 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1563 Mod_Alias_MorphMesh_CompileFrames();
1564 if(mod_alias_force_animated.string[0])
1565 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1567 surface = loadmodel->data_surfaces;
1568 surface->texture = loadmodel->data_textures;
1569 surface->num_firsttriangle = 0;
1570 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1571 surface->num_firstvertex = 0;
1572 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1574 // Always make a BIH for the first frame, we can use it where possible.
1575 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1576 if (!loadmodel->surfmesh.isanimated)
1578 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1579 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1580 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1581 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1582 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1585 // because shaders can do somewhat unexpected things, check for unusual features now
1586 for (i = 0;i < loadmodel->num_textures;i++)
1588 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1589 mod->DrawSky = R_Q1BSP_DrawSky;
1590 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1591 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1595 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1597 int i, j, k, version, meshvertices, meshtriangles;
1598 unsigned char *data;
1599 msurface_t *surface;
1600 md3modelheader_t *pinmodel;
1601 md3frameinfo_t *pinframe;
1604 skinfile_t *skinfiles;
1606 pinmodel = (md3modelheader_t *)buffer;
1608 if (memcmp(pinmodel->identifier, "IDP3", 4))
1609 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1610 version = LittleLong (pinmodel->version);
1611 if (version != MD3VERSION)
1612 Host_Error ("%s has wrong version number (%i should be %i)",
1613 loadmodel->name, version, MD3VERSION);
1615 skinfiles = Mod_LoadSkinFiles();
1616 if (loadmodel->numskins < 1)
1617 loadmodel->numskins = 1;
1619 loadmodel->modeldatatypestring = "MD3";
1621 loadmodel->type = mod_alias;
1622 loadmodel->DrawSky = NULL;
1623 loadmodel->DrawAddWaterPlanes = NULL;
1624 loadmodel->Draw = R_Q1BSP_Draw;
1625 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1626 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1627 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1628 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1629 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1630 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1631 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1632 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1633 loadmodel->PointSuperContents = NULL;
1634 loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1635 loadmodel->synctype = ST_RAND;
1636 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1637 i = LittleLong (pinmodel->flags);
1638 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1640 // set up some global info about the model
1641 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1642 loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1644 // make skinscenes for the skins (no groups)
1645 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1646 for (i = 0;i < loadmodel->numskins;i++)
1648 loadmodel->skinscenes[i].firstframe = i;
1649 loadmodel->skinscenes[i].framecount = 1;
1650 loadmodel->skinscenes[i].loop = true;
1651 loadmodel->skinscenes[i].framerate = 10;
1655 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1656 for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1658 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1659 loadmodel->animscenes[i].firstframe = i;
1660 loadmodel->animscenes[i].framecount = 1;
1661 loadmodel->animscenes[i].framerate = 10;
1662 loadmodel->animscenes[i].loop = true;
1666 loadmodel->num_tagframes = loadmodel->numframes;
1667 loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1668 loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1669 for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1671 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1672 for (j = 0;j < 9;j++)
1673 loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1674 for (j = 0;j < 3;j++)
1675 loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1676 //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);
1682 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)))
1684 if (memcmp(pinmesh->identifier, "IDP3", 4))
1685 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1686 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1687 Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1688 meshvertices += LittleLong(pinmesh->num_vertices);
1689 meshtriangles += LittleLong(pinmesh->num_triangles);
1692 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1693 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1694 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1695 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));
1696 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1697 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1698 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1699 loadmodel->surfmesh.num_vertices = meshvertices;
1700 loadmodel->surfmesh.num_triangles = meshtriangles;
1701 loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1702 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1703 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1704 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1705 loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1706 if (meshvertices <= 65536)
1708 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1713 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)))
1715 if (memcmp(pinmesh->identifier, "IDP3", 4))
1716 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1717 loadmodel->sortedmodelsurfaces[i] = i;
1718 surface = loadmodel->data_surfaces + i;
1719 surface->texture = loadmodel->data_textures + i;
1720 surface->num_firsttriangle = meshtriangles;
1721 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1722 surface->num_firstvertex = meshvertices;
1723 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1724 meshvertices += surface->num_vertices;
1725 meshtriangles += surface->num_triangles;
1727 for (j = 0;j < surface->num_triangles * 3;j++)
1729 int e = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1730 loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = e;
1731 if (loadmodel->surfmesh.data_element3s)
1732 loadmodel->surfmesh.data_element3s[j + surface->num_firsttriangle * 3] = e;
1734 for (j = 0;j < surface->num_vertices;j++)
1736 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1737 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1739 for (j = 0;j < loadmodel->numframes;j++)
1741 const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1742 md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1743 for (k = 0;k < surface->num_vertices;k++, in++, out++)
1745 out->origin[0] = LittleShort(in->origin[0]);
1746 out->origin[1] = LittleShort(in->origin[1]);
1747 out->origin[2] = LittleShort(in->origin[2]);
1748 out->pitch = in->pitch;
1753 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1755 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__);
1757 Mod_Alias_MorphMesh_CompileFrames();
1758 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1759 Mod_FreeSkinFiles(skinfiles);
1760 Mod_MakeSortedSurfaces(loadmodel);
1761 if(mod_alias_force_animated.string[0])
1762 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1764 // Always make a BIH for the first frame, we can use it where possible.
1765 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1766 if (!loadmodel->surfmesh.isanimated)
1768 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1769 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1770 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1771 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1772 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1775 // because shaders can do somewhat unexpected things, check for unusual features now
1776 for (i = 0;i < loadmodel->num_textures;i++)
1778 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1779 mod->DrawSky = R_Q1BSP_DrawSky;
1780 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1781 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1785 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1787 zymtype1header_t *pinmodel, *pheader;
1788 unsigned char *pbase;
1789 int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1790 float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1791 zymvertex_t *verts, *vertdata;
1795 skinfile_t *skinfiles;
1796 unsigned char *data;
1797 msurface_t *surface;
1799 pinmodel = (zymtype1header_t *)buffer;
1800 pbase = (unsigned char *)buffer;
1801 if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1802 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1803 if (BigLong(pinmodel->type) != 1)
1804 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1806 loadmodel->modeldatatypestring = "ZYM";
1808 loadmodel->type = mod_alias;
1809 loadmodel->synctype = ST_RAND;
1813 pheader->type = BigLong(pinmodel->type);
1814 pheader->filesize = BigLong(pinmodel->filesize);
1815 pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1816 pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1817 pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1818 pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1819 pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1820 pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1821 pheader->radius = BigFloat(pinmodel->radius);
1822 pheader->numverts = BigLong(pinmodel->numverts);
1823 pheader->numtris = BigLong(pinmodel->numtris);
1824 pheader->numshaders = BigLong(pinmodel->numshaders);
1825 pheader->numbones = BigLong(pinmodel->numbones);
1826 pheader->numscenes = BigLong(pinmodel->numscenes);
1827 pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1828 pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1829 pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1830 pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1831 pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1832 pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1833 pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1834 pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1835 pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1836 pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1837 pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1838 pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1839 pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1840 pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1841 pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1842 pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1843 pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1844 pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1846 if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1848 Con_Printf("%s has no geometry\n", loadmodel->name);
1851 if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1853 Con_Printf("%s has no animations\n", loadmodel->name);
1857 loadmodel->DrawSky = NULL;
1858 loadmodel->DrawAddWaterPlanes = NULL;
1859 loadmodel->Draw = R_Q1BSP_Draw;
1860 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1861 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1862 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1863 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1864 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1865 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1866 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1867 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1868 loadmodel->PointSuperContents = NULL;
1869 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1871 loadmodel->numframes = pheader->numscenes;
1872 loadmodel->num_surfaces = pheader->numshaders;
1874 skinfiles = Mod_LoadSkinFiles();
1875 if (loadmodel->numskins < 1)
1876 loadmodel->numskins = 1;
1878 // make skinscenes for the skins (no groups)
1879 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1880 for (i = 0;i < loadmodel->numskins;i++)
1882 loadmodel->skinscenes[i].firstframe = i;
1883 loadmodel->skinscenes[i].framecount = 1;
1884 loadmodel->skinscenes[i].loop = true;
1885 loadmodel->skinscenes[i].framerate = 10;
1889 // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1890 modelradius = pheader->radius;
1891 for (i = 0;i < 3;i++)
1893 loadmodel->normalmins[i] = pheader->mins[i];
1894 loadmodel->normalmaxs[i] = pheader->maxs[i];
1895 loadmodel->rotatedmins[i] = -modelradius;
1896 loadmodel->rotatedmaxs[i] = modelradius;
1898 corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1899 corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1900 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1901 if (loadmodel->yawmaxs[0] > modelradius)
1902 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1903 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1904 loadmodel->yawmins[2] = loadmodel->normalmins[2];
1905 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1906 loadmodel->radius = modelradius;
1907 loadmodel->radius2 = modelradius * modelradius;
1909 // go through the lumps, swapping things
1911 //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1912 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1913 scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1914 numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1915 for (i = 0;i < pheader->numscenes;i++)
1917 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1918 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1919 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1920 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1921 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1922 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1923 Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1924 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1925 Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1926 if (loadmodel->animscenes[i].framerate < 0)
1927 Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1931 //zymlump_t lump_bones; // zymbone_t bone[numbones];
1932 loadmodel->num_bones = pheader->numbones;
1933 loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1934 bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1935 for (i = 0;i < pheader->numbones;i++)
1937 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1938 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1939 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1940 if (loadmodel->data_bones[i].parent >= i)
1941 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1944 //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1945 vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1946 bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1947 for (i = 0;i < pheader->numverts;i++)
1949 vertbonecounts[i] = BigLong(bonecount[i]);
1950 if (vertbonecounts[i] != 1)
1951 Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1954 loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1956 meshvertices = pheader->numverts;
1957 meshtriangles = pheader->numtris;
1959 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1960 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1961 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1962 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]));
1963 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1964 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1965 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1966 loadmodel->surfmesh.num_vertices = meshvertices;
1967 loadmodel->surfmesh.num_triangles = meshtriangles;
1968 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1969 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1970 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1971 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1972 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1973 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1974 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1975 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1976 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1977 loadmodel->surfmesh.num_blends = 0;
1978 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
1979 if (loadmodel->surfmesh.num_vertices <= 65536)
1981 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1983 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
1984 loadmodel->surfmesh.data_blendweights = NULL;
1986 //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1987 poses = (float *) (pheader->lump_poses.start + pbase);
1988 // figure out scale of model from root bone, for compatibility with old zmodel versions
1989 tempvec[0] = BigFloat(poses[0]);
1990 tempvec[1] = BigFloat(poses[1]);
1991 tempvec[2] = BigFloat(poses[2]);
1992 modelscale = VectorLength(tempvec);
1994 for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
1996 f = fabs(BigFloat(poses[i]));
1997 biggestorigin = max(biggestorigin, f);
1999 loadmodel->num_posescale = biggestorigin / 32767.0f;
2000 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2001 for (i = 0;i < numposes;i++)
2003 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
2004 for (j = 0;j < loadmodel->num_bones;j++)
2007 matrix4x4_t posematrix;
2008 for (k = 0;k < 12;k++)
2009 pose[k] = BigFloat(frameposes[j*12+k]);
2010 //if (j < loadmodel->num_bones)
2011 // 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));
2012 // scale child bones to match the root scale
2013 if (loadmodel->data_bones[j].parent >= 0)
2015 pose[3] *= modelscale;
2016 pose[7] *= modelscale;
2017 pose[11] *= modelscale;
2019 // normalize rotation matrix
2020 VectorNormalize(pose + 0);
2021 VectorNormalize(pose + 4);
2022 VectorNormalize(pose + 8);
2023 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2024 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2028 //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2029 verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2030 vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2031 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2032 // (converting from weight-blending skeletal animation to
2033 // deformation-based skeletal animation)
2034 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2035 for (i = 0;i < loadmodel->num_bones;i++)
2038 for (k = 0;k < 12;k++)
2039 m[k] = BigFloat(poses[i*12+k]);
2040 if (loadmodel->data_bones[i].parent >= 0)
2041 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2043 for (k = 0;k < 12;k++)
2044 bonepose[12*i+k] = m[k];
2046 for (j = 0;j < pheader->numverts;j++)
2048 // this format really should have had a per vertexweight weight value...
2049 // but since it does not, the weighting is completely ignored and
2050 // only one weight is allowed per vertex
2051 int boneindex = BigLong(vertdata[j].bonenum);
2052 const float *m = bonepose + 12 * boneindex;
2053 float relativeorigin[3];
2054 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2055 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2056 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2057 // transform the vertex bone weight into the base mesh
2058 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2059 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2060 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2061 // store the weight as the primary weight on this vertex
2062 loadmodel->surfmesh.blends[j] = boneindex;
2063 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = boneindex;
2064 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2065 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2066 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2067 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = 255;
2068 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2069 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2070 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2073 // normals and tangents are calculated after elements are loaded
2075 //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2076 outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2077 intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2078 for (i = 0;i < pheader->numverts;i++)
2080 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2081 // flip T coordinate for OpenGL
2082 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2085 //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2086 //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2087 //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2089 //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2090 //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)
2091 // byteswap, validate, and swap winding order of tris
2092 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2093 if (pheader->lump_render.length != count)
2094 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2095 renderlist = (int *) (pheader->lump_render.start + pbase);
2096 renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2098 for (i = 0;i < loadmodel->num_surfaces;i++)
2100 int firstvertex, lastvertex;
2101 if (renderlist >= renderlistend)
2102 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2103 count = BigLong(*renderlist);renderlist++;
2104 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2105 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2107 loadmodel->sortedmodelsurfaces[i] = i;
2108 surface = loadmodel->data_surfaces + i;
2109 surface->texture = loadmodel->data_textures + i;
2110 surface->num_firsttriangle = meshtriangles;
2111 surface->num_triangles = count;
2112 meshtriangles += surface->num_triangles;
2114 // load the elements
2115 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2116 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2118 outelements[j*3+2] = BigLong(renderlist[0]);
2119 outelements[j*3+1] = BigLong(renderlist[1]);
2120 outelements[j*3+0] = BigLong(renderlist[2]);
2122 // validate the elements and find the used vertex range
2123 firstvertex = meshvertices;
2125 for (j = 0;j < surface->num_triangles * 3;j++)
2127 if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2128 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2129 firstvertex = min(firstvertex, outelements[j]);
2130 lastvertex = max(lastvertex, outelements[j]);
2132 surface->num_firstvertex = firstvertex;
2133 surface->num_vertices = lastvertex + 1 - firstvertex;
2135 // since zym models do not have named sections, reuse their shader
2136 // name as the section name
2137 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2138 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2140 Mod_FreeSkinFiles(skinfiles);
2141 Mem_Free(vertbonecounts);
2143 Mod_MakeSortedSurfaces(loadmodel);
2145 // compute all the mesh information that was not loaded from the file
2146 if (loadmodel->surfmesh.data_element3s)
2147 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2148 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2149 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2150 Mod_BuildBaseBonePoses();
2151 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);
2152 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);
2153 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2154 if(mod_alias_force_animated.string[0])
2155 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2157 // Always make a BIH for the first frame, we can use it where possible.
2158 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2159 if (!loadmodel->surfmesh.isanimated)
2161 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2162 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2163 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2164 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2165 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2168 // because shaders can do somewhat unexpected things, check for unusual features now
2169 for (i = 0;i < loadmodel->num_textures;i++)
2171 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2172 mod->DrawSky = R_Q1BSP_DrawSky;
2173 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2174 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2178 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2180 dpmheader_t *pheader;
2184 unsigned char *pbase;
2185 int i, j, k, meshvertices, meshtriangles;
2186 skinfile_t *skinfiles;
2187 unsigned char *data;
2189 float biggestorigin, tempvec[3], modelscale;
2193 pheader = (dpmheader_t *)buffer;
2194 pbase = (unsigned char *)buffer;
2195 if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2196 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2197 if (BigLong(pheader->type) != 2)
2198 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2200 loadmodel->modeldatatypestring = "DPM";
2202 loadmodel->type = mod_alias;
2203 loadmodel->synctype = ST_RAND;
2206 pheader->type = BigLong(pheader->type);
2207 pheader->filesize = BigLong(pheader->filesize);
2208 pheader->mins[0] = BigFloat(pheader->mins[0]);
2209 pheader->mins[1] = BigFloat(pheader->mins[1]);
2210 pheader->mins[2] = BigFloat(pheader->mins[2]);
2211 pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2212 pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2213 pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2214 pheader->yawradius = BigFloat(pheader->yawradius);
2215 pheader->allradius = BigFloat(pheader->allradius);
2216 pheader->num_bones = BigLong(pheader->num_bones);
2217 pheader->num_meshs = BigLong(pheader->num_meshs);
2218 pheader->num_frames = BigLong(pheader->num_frames);
2219 pheader->ofs_bones = BigLong(pheader->ofs_bones);
2220 pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2221 pheader->ofs_frames = BigLong(pheader->ofs_frames);
2223 if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2225 Con_Printf("%s has no geometry\n", loadmodel->name);
2228 if (pheader->num_frames < 1)
2230 Con_Printf("%s has no frames\n", loadmodel->name);
2234 loadmodel->DrawSky = NULL;
2235 loadmodel->DrawAddWaterPlanes = NULL;
2236 loadmodel->Draw = R_Q1BSP_Draw;
2237 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2238 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2239 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2240 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2241 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2242 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2243 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2244 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2245 loadmodel->PointSuperContents = NULL;
2246 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2249 // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2250 for (i = 0;i < 3;i++)
2252 loadmodel->normalmins[i] = pheader->mins[i];
2253 loadmodel->normalmaxs[i] = pheader->maxs[i];
2254 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2255 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2256 loadmodel->rotatedmins[i] = -pheader->allradius;
2257 loadmodel->rotatedmaxs[i] = pheader->allradius;
2259 loadmodel->radius = pheader->allradius;
2260 loadmodel->radius2 = pheader->allradius * pheader->allradius;
2262 // load external .skin files if present
2263 skinfiles = Mod_LoadSkinFiles();
2264 if (loadmodel->numskins < 1)
2265 loadmodel->numskins = 1;
2270 // gather combined statistics from the meshes
2271 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2272 for (i = 0;i < (int)pheader->num_meshs;i++)
2274 int numverts = BigLong(dpmmesh->num_verts);
2275 meshvertices += numverts;
2276 meshtriangles += BigLong(dpmmesh->num_tris);
2280 loadmodel->numframes = pheader->num_frames;
2281 loadmodel->num_bones = pheader->num_bones;
2282 loadmodel->num_poses = loadmodel->numframes;
2283 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2284 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2285 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2286 // do most allocations as one merged chunk
2287 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));
2288 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2289 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2290 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2291 loadmodel->surfmesh.num_vertices = meshvertices;
2292 loadmodel->surfmesh.num_triangles = meshtriangles;
2293 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2294 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2295 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2296 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2297 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2298 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2299 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2300 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2301 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2302 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2303 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2304 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2305 loadmodel->surfmesh.num_blends = 0;
2306 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2307 if (meshvertices <= 65536)
2309 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2311 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2312 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2314 for (i = 0;i < loadmodel->numskins;i++)
2316 loadmodel->skinscenes[i].firstframe = i;
2317 loadmodel->skinscenes[i].framecount = 1;
2318 loadmodel->skinscenes[i].loop = true;
2319 loadmodel->skinscenes[i].framerate = 10;
2322 // load the bone info
2323 bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2324 for (i = 0;i < loadmodel->num_bones;i++)
2326 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2327 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2328 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2329 if (loadmodel->data_bones[i].parent >= i)
2330 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2334 frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2335 // figure out scale of model from root bone, for compatibility with old dpmodel versions
2336 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2337 tempvec[0] = BigFloat(poses[0]);
2338 tempvec[1] = BigFloat(poses[1]);
2339 tempvec[2] = BigFloat(poses[2]);
2340 modelscale = VectorLength(tempvec);
2342 for (i = 0;i < loadmodel->numframes;i++)
2344 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2345 loadmodel->animscenes[i].firstframe = i;
2346 loadmodel->animscenes[i].framecount = 1;
2347 loadmodel->animscenes[i].loop = true;
2348 loadmodel->animscenes[i].framerate = 10;
2349 // load the bone poses for this frame
2350 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2351 for (j = 0;j < loadmodel->num_bones*12;j++)
2353 f = fabs(BigFloat(poses[j]));
2354 biggestorigin = max(biggestorigin, f);
2356 // stuff not processed here: mins, maxs, yawradius, allradius
2358 loadmodel->num_posescale = biggestorigin / 32767.0f;
2359 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2360 for (i = 0;i < loadmodel->numframes;i++)
2362 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2363 for (j = 0;j < loadmodel->num_bones;j++)
2366 matrix4x4_t posematrix;
2367 for (k = 0;k < 12;k++)
2368 pose[k] = BigFloat(frameposes[j*12+k]);
2369 // scale child bones to match the root scale
2370 if (loadmodel->data_bones[j].parent >= 0)
2372 pose[3] *= modelscale;
2373 pose[7] *= modelscale;
2374 pose[11] *= modelscale;
2376 // normalize rotation matrix
2377 VectorNormalize(pose + 0);
2378 VectorNormalize(pose + 4);
2379 VectorNormalize(pose + 8);
2380 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2381 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2385 // load the meshes now
2386 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2389 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2390 // (converting from weight-blending skeletal animation to
2391 // deformation-based skeletal animation)
2392 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2393 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2394 for (i = 0;i < loadmodel->num_bones;i++)
2397 for (k = 0;k < 12;k++)
2398 m[k] = BigFloat(poses[i*12+k]);
2399 if (loadmodel->data_bones[i].parent >= 0)
2400 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2402 for (k = 0;k < 12;k++)
2403 bonepose[12*i+k] = m[k];
2405 for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2407 const int *inelements;
2409 unsigned short *outelement3s;
2410 const float *intexcoord;
2411 msurface_t *surface;
2413 loadmodel->sortedmodelsurfaces[i] = i;
2414 surface = loadmodel->data_surfaces + i;
2415 surface->texture = loadmodel->data_textures + i;
2416 surface->num_firsttriangle = meshtriangles;
2417 surface->num_triangles = BigLong(dpmmesh->num_tris);
2418 surface->num_firstvertex = meshvertices;
2419 surface->num_vertices = BigLong(dpmmesh->num_verts);
2420 meshvertices += surface->num_vertices;
2421 meshtriangles += surface->num_triangles;
2423 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2424 outelement3i = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2425 outelement3s = loadmodel->surfmesh.data_element3s ? loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3 : NULL;
2426 for (j = 0;j < surface->num_triangles;j++)
2428 // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2429 outelement3i[j * 3 + 0] = surface->num_firstvertex + BigLong(inelements[j * 3 + 2]);
2430 outelement3i[j * 3 + 1] = surface->num_firstvertex + BigLong(inelements[j * 3 + 1]);
2431 outelement3i[j * 3 + 2] = surface->num_firstvertex + BigLong(inelements[j * 3 + 0]);
2434 outelement3s[j * 3 + 0] = outelement3i[j * 3 + 0];
2435 outelement3s[j * 3 + 1] = outelement3i[j * 3 + 1];
2436 outelement3s[j * 3 + 2] = outelement3i[j * 3 + 2];
2440 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2441 for (j = 0;j < surface->num_vertices*2;j++)
2442 loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2444 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2445 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2447 int weightindex[4] = { 0, 0, 0, 0 };
2448 float weightinfluence[4] = { 0, 0, 0, 0 };
2450 int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2451 data += sizeof(dpmvertex_t);
2452 for (k = 0;k < numweights;k++)
2454 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2455 int boneindex = BigLong(vert->bonenum);
2456 const float *m = bonepose + 12 * boneindex;
2457 float influence = BigFloat(vert->influence);
2458 float relativeorigin[3], relativenormal[3];
2459 relativeorigin[0] = BigFloat(vert->origin[0]);
2460 relativeorigin[1] = BigFloat(vert->origin[1]);
2461 relativeorigin[2] = BigFloat(vert->origin[2]);
2462 relativenormal[0] = BigFloat(vert->normal[0]);
2463 relativenormal[1] = BigFloat(vert->normal[1]);
2464 relativenormal[2] = BigFloat(vert->normal[2]);
2465 // blend the vertex bone weights into the base mesh
2466 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2467 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2468 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2469 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2470 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2471 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2474 // store the first (and often only) weight
2475 weightinfluence[0] = influence;
2476 weightindex[0] = boneindex;
2480 // sort the new weight into this vertex's weight table
2481 // (which only accepts up to 4 bones per vertex)
2482 for (l = 0;l < 4;l++)
2484 if (weightinfluence[l] < influence)
2486 // move weaker influence weights out of the way first
2488 for (l2 = 3;l2 > l;l2--)
2490 weightinfluence[l2] = weightinfluence[l2-1];
2491 weightindex[l2] = weightindex[l2-1];
2493 // store the new weight
2494 weightinfluence[l] = influence;
2495 weightindex[l] = boneindex;
2500 data += sizeof(dpmbonevert_t);
2502 loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2503 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = weightindex[0];
2504 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2505 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2506 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2507 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
2508 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2509 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2510 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2513 // since dpm models do not have named sections, reuse their shader name as the section name
2514 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2516 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__);
2518 if (loadmodel->surfmesh.num_blends < meshvertices)
2519 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2521 Mod_FreeSkinFiles(skinfiles);
2522 Mod_MakeSortedSurfaces(loadmodel);
2524 // compute all the mesh information that was not loaded from the file
2525 Mod_BuildBaseBonePoses();
2526 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);
2527 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2528 if(mod_alias_force_animated.string[0])
2529 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2531 // Always make a BIH for the first frame, we can use it where possible.
2532 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2533 if (!loadmodel->surfmesh.isanimated)
2535 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2536 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2537 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2538 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2539 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2542 // because shaders can do somewhat unexpected things, check for unusual features now
2543 for (i = 0;i < loadmodel->num_textures;i++)
2545 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2546 mod->DrawSky = R_Q1BSP_DrawSky;
2547 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2548 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2552 // no idea why PSK/PSA files contain weird quaternions but they do...
2553 #define PSKQUATNEGATIONS
2554 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2556 int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2557 int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2558 fs_offset_t filesize;
2563 pskboneinfo_t *bones;
2564 pskrawweights_t *rawweights;
2565 //pskboneinfo_t *animbones;
2566 pskaniminfo_t *anims;
2567 pskanimkeys_t *animkeys;
2568 void *animfilebuffer, *animbuffer, *animbufferend;
2569 unsigned char *data;
2571 skinfile_t *skinfiles;
2572 char animname[MAX_QPATH];
2574 float biggestorigin;
2576 pchunk = (pskchunk_t *)buffer;
2577 if (strcmp(pchunk->id, "ACTRHEAD"))
2578 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2580 loadmodel->modeldatatypestring = "PSK";
2582 loadmodel->type = mod_alias;
2583 loadmodel->DrawSky = NULL;
2584 loadmodel->DrawAddWaterPlanes = NULL;
2585 loadmodel->Draw = R_Q1BSP_Draw;
2586 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2587 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2588 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2589 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2590 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2591 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2592 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2593 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2594 loadmodel->PointSuperContents = NULL;
2595 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2596 loadmodel->synctype = ST_RAND;
2598 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2599 strlcat(animname, ".psa", sizeof(animname));
2600 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2601 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2603 animbufferend = animbuffer;
2622 while (buffer < bufferend)
2624 pchunk = (pskchunk_t *)buffer;
2625 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2626 version = LittleLong(pchunk->version);
2627 recordsize = LittleLong(pchunk->recordsize);
2628 numrecords = LittleLong(pchunk->numrecords);
2629 if (developer_extra.integer)
2630 Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2631 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2632 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);
2633 if (!strcmp(pchunk->id, "ACTRHEAD"))
2637 else if (!strcmp(pchunk->id, "PNTS0000"))
2640 if (recordsize != sizeof(*p))
2641 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2642 // byteswap in place and keep the pointer
2643 numpnts = numrecords;
2644 pnts = (pskpnts_t *)buffer;
2645 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2647 p->origin[0] = LittleFloat(p->origin[0]);
2648 p->origin[1] = LittleFloat(p->origin[1]);
2649 p->origin[2] = LittleFloat(p->origin[2]);
2653 else if (!strcmp(pchunk->id, "VTXW0000"))
2656 if (recordsize != sizeof(*p))
2657 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2658 // byteswap in place and keep the pointer
2659 numvtxw = numrecords;
2660 vtxw = (pskvtxw_t *)buffer;
2661 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2663 p->pntsindex = LittleShort(p->pntsindex);
2664 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2665 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2666 if (p->pntsindex >= numpnts)
2668 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2674 else if (!strcmp(pchunk->id, "FACE0000"))
2677 if (recordsize != sizeof(*p))
2678 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2679 // byteswap in place and keep the pointer
2680 numfaces = numrecords;
2681 faces = (pskface_t *)buffer;
2682 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2684 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2685 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2686 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2687 p->group = LittleLong(p->group);
2688 if (p->vtxwindex[0] >= numvtxw)
2690 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2691 p->vtxwindex[0] = 0;
2693 if (p->vtxwindex[1] >= numvtxw)
2695 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2696 p->vtxwindex[1] = 0;
2698 if (p->vtxwindex[2] >= numvtxw)
2700 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2701 p->vtxwindex[2] = 0;
2706 else if (!strcmp(pchunk->id, "MATT0000"))
2709 if (recordsize != sizeof(*p))
2710 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2711 // byteswap in place and keep the pointer
2712 nummatts = numrecords;
2713 matts = (pskmatt_t *)buffer;
2714 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2720 else if (!strcmp(pchunk->id, "REFSKELT"))
2723 if (recordsize != sizeof(*p))
2724 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2725 // byteswap in place and keep the pointer
2726 numbones = numrecords;
2727 bones = (pskboneinfo_t *)buffer;
2728 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2730 p->numchildren = LittleLong(p->numchildren);
2731 p->parent = LittleLong(p->parent);
2732 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2733 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2734 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2735 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2736 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2737 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2738 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2739 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2740 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2741 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2742 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2743 #ifdef PSKQUATNEGATIONS
2746 p->basepose.quat[0] *= -1;
2747 p->basepose.quat[1] *= -1;
2748 p->basepose.quat[2] *= -1;
2752 p->basepose.quat[0] *= 1;
2753 p->basepose.quat[1] *= -1;
2754 p->basepose.quat[2] *= 1;
2757 if (p->parent < 0 || p->parent >= numbones)
2759 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2765 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2768 if (recordsize != sizeof(*p))
2769 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2770 // byteswap in place and keep the pointer
2771 numrawweights = numrecords;
2772 rawweights = (pskrawweights_t *)buffer;
2773 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2775 p->weight = LittleFloat(p->weight);
2776 p->pntsindex = LittleLong(p->pntsindex);
2777 p->boneindex = LittleLong(p->boneindex);
2778 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2780 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2783 if (p->boneindex < 0 || p->boneindex >= numbones)
2785 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2793 while (animbuffer < animbufferend)
2795 pchunk = (pskchunk_t *)animbuffer;
2796 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2797 version = LittleLong(pchunk->version);
2798 recordsize = LittleLong(pchunk->recordsize);
2799 numrecords = LittleLong(pchunk->numrecords);
2800 if (developer_extra.integer)
2801 Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2802 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2803 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);
2804 if (!strcmp(pchunk->id, "ANIMHEAD"))
2808 else if (!strcmp(pchunk->id, "BONENAMES"))
2811 if (recordsize != sizeof(*p))
2812 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2813 // byteswap in place and keep the pointer
2814 numanimbones = numrecords;
2815 //animbones = (pskboneinfo_t *)animbuffer;
2816 // NOTE: supposedly psa does not need to match the psk model, the
2817 // bones missing from the psa would simply use their base
2818 // positions from the psk, but this is hard for me to implement
2819 // and people can easily make animations that match.
2820 if (numanimbones != numbones)
2821 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2822 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2824 p->numchildren = LittleLong(p->numchildren);
2825 p->parent = LittleLong(p->parent);
2826 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2827 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2828 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2829 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2830 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2831 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2832 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2833 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2834 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2835 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2836 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2837 #ifdef PSKQUATNEGATIONS
2840 p->basepose.quat[0] *= -1;
2841 p->basepose.quat[1] *= -1;
2842 p->basepose.quat[2] *= -1;
2846 p->basepose.quat[0] *= 1;
2847 p->basepose.quat[1] *= -1;
2848 p->basepose.quat[2] *= 1;
2851 if (p->parent < 0 || p->parent >= numanimbones)
2853 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2856 // check that bones are the same as in the base
2857 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2858 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2862 else if (!strcmp(pchunk->id, "ANIMINFO"))
2865 if (recordsize != sizeof(*p))
2866 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2867 // byteswap in place and keep the pointer
2868 numanims = numrecords;
2869 anims = (pskaniminfo_t *)animbuffer;
2870 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2872 p->numbones = LittleLong(p->numbones);
2873 p->playtime = LittleFloat(p->playtime);
2874 p->fps = LittleFloat(p->fps);
2875 p->firstframe = LittleLong(p->firstframe);
2876 p->numframes = LittleLong(p->numframes);
2877 if (p->numbones != numbones)
2878 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2882 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2885 if (recordsize != sizeof(*p))
2886 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2887 numanimkeys = numrecords;
2888 animkeys = (pskanimkeys_t *)animbuffer;
2889 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2891 p->origin[0] = LittleFloat(p->origin[0]);
2892 p->origin[1] = LittleFloat(p->origin[1]);
2893 p->origin[2] = LittleFloat(p->origin[2]);
2894 p->quat[0] = LittleFloat(p->quat[0]);
2895 p->quat[1] = LittleFloat(p->quat[1]);
2896 p->quat[2] = LittleFloat(p->quat[2]);
2897 p->quat[3] = LittleFloat(p->quat[3]);
2898 p->frametime = LittleFloat(p->frametime);
2899 #ifdef PSKQUATNEGATIONS
2900 if (index % numbones)
2915 // TODO: allocate bonepose stuff
2918 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2921 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2922 Host_Error("%s: missing required chunks", loadmodel->name);
2926 loadmodel->numframes = 0;
2927 for (index = 0;index < numanims;index++)
2928 loadmodel->numframes += anims[index].numframes;
2929 if (numanimkeys != numbones * loadmodel->numframes)
2930 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2933 loadmodel->numframes = loadmodel->num_poses = 1;
2935 meshvertices = numvtxw;
2936 meshtriangles = numfaces;
2938 // load external .skin files if present
2939 skinfiles = Mod_LoadSkinFiles();
2940 if (loadmodel->numskins < 1)
2941 loadmodel->numskins = 1;
2942 loadmodel->num_bones = numbones;
2943 loadmodel->num_poses = loadmodel->numframes;
2944 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2945 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2946 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2947 loadmodel->surfmesh.num_vertices = meshvertices;
2948 loadmodel->surfmesh.num_triangles = meshtriangles;
2949 // do most allocations as one merged chunk
2950 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);
2951 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2952 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2953 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2954 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2955 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2956 loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2957 loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2958 loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2959 loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2960 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2961 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2962 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2963 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2964 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2965 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2966 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2967 loadmodel->surfmesh.num_blends = 0;
2968 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2969 if (loadmodel->surfmesh.num_vertices <= 65536)
2971 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2973 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2974 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2976 for (i = 0;i < loadmodel->numskins;i++)
2978 loadmodel->skinscenes[i].firstframe = i;
2979 loadmodel->skinscenes[i].framecount = 1;
2980 loadmodel->skinscenes[i].loop = true;
2981 loadmodel->skinscenes[i].framerate = 10;
2985 for (index = 0, i = 0;index < nummatts;index++)
2987 // since psk models do not have named sections, reuse their shader name as the section name
2988 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2989 loadmodel->sortedmodelsurfaces[index] = index;
2990 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2991 loadmodel->data_surfaces[index].num_firstvertex = 0;
2992 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2995 // copy over the vertex locations and texcoords
2996 for (index = 0;index < numvtxw;index++)
2998 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2999 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
3000 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
3001 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
3002 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
3005 // loading the faces is complicated because we need to sort them into surfaces by mattindex
3006 for (index = 0;index < numfaces;index++)
3007 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
3008 for (index = 0, i = 0;index < nummatts;index++)
3010 loadmodel->data_surfaces[index].num_firsttriangle = i;
3011 i += loadmodel->data_surfaces[index].num_triangles;
3012 loadmodel->data_surfaces[index].num_triangles = 0;
3014 for (index = 0;index < numfaces;index++)
3016 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3017 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3018 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3019 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3022 // copy over the bones
3023 for (index = 0;index < numbones;index++)
3025 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3026 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3027 if (loadmodel->data_bones[index].parent >= index)
3028 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3031 // convert the basepose data
3032 if (loadmodel->num_bones)
3035 matrix4x4_t *basebonepose;
3036 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3037 matrix4x4_t bonematrix;
3038 matrix4x4_t tempbonematrix;
3039 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3040 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3042 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]);
3043 if (loadmodel->data_bones[boneindex].parent >= 0)
3045 tempbonematrix = bonematrix;
3046 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3048 basebonepose[boneindex] = bonematrix;
3049 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3050 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3052 Mem_Free(basebonepose);
3055 // sort the psk point weights into the vertex weight tables
3056 // (which only accept up to 4 bones per vertex)
3057 for (index = 0;index < numvtxw;index++)
3059 int weightindex[4] = { 0, 0, 0, 0 };
3060 float weightinfluence[4] = { 0, 0, 0, 0 };
3062 for (j = 0;j < numrawweights;j++)
3064 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3066 int boneindex = rawweights[j].boneindex;
3067 float influence = rawweights[j].weight;
3068 for (l = 0;l < 4;l++)
3070 if (weightinfluence[l] < influence)
3072 // move lower influence weights out of the way first
3074 for (l2 = 3;l2 > l;l2--)
3076 weightinfluence[l2] = weightinfluence[l2-1];
3077 weightindex[l2] = weightindex[l2-1];
3079 // store the new weight
3080 weightinfluence[l] = influence;
3081 weightindex[l] = boneindex;
3087 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3088 loadmodel->surfmesh.data_skeletalindex4ub[index*4 ] = weightindex[0];
3089 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3090 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3091 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3092 loadmodel->surfmesh.data_skeletalweight4ub[index*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
3093 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3094 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3095 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3097 if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3098 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3100 // set up the animscenes based on the anims
3103 for (index = 0, i = 0;index < numanims;index++)
3105 for (j = 0;j < anims[index].numframes;j++, i++)
3107 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3108 loadmodel->animscenes[i].firstframe = i;
3109 loadmodel->animscenes[i].framecount = 1;
3110 loadmodel->animscenes[i].loop = true;
3111 loadmodel->animscenes[i].framerate = anims[index].fps;
3114 // calculate the scaling value for bone origins so they can be compressed to short
3116 for (index = 0;index < numanimkeys;index++)
3118 pskanimkeys_t *k = animkeys + index;
3119 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3120 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3121 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3123 loadmodel->num_posescale = biggestorigin / 32767.0f;
3124 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3126 // load the poses from the animkeys
3127 for (index = 0;index < numanimkeys;index++)
3129 pskanimkeys_t *k = animkeys + index;
3131 Vector4Copy(k->quat, quat);
3133 Vector4Negate(quat, quat);
3134 Vector4Normalize2(quat, quat);
3135 // compress poses to the short[7] format for longterm storage
3136 loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3137 loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3138 loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3139 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3140 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3141 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3142 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3147 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3148 loadmodel->animscenes[0].firstframe = 0;
3149 loadmodel->animscenes[0].framecount = 1;
3150 loadmodel->animscenes[0].loop = true;
3151 loadmodel->animscenes[0].framerate = 10;
3153 // calculate the scaling value for bone origins so they can be compressed to short
3155 for (index = 0;index < numbones;index++)
3157 pskboneinfo_t *p = bones + index;
3158 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3159 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3160 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3162 loadmodel->num_posescale = biggestorigin / 32767.0f;
3163 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3165 // load the basepose as a frame
3166 for (index = 0;index < numbones;index++)
3168 pskboneinfo_t *p = bones + index;
3170 Vector4Copy(p->basepose.quat, quat);
3172 Vector4Negate(quat, quat);
3173 Vector4Normalize2(quat, quat);
3174 // compress poses to the short[7] format for longterm storage
3175 loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3176 loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3177 loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3178 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3179 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3180 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3181 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3185 Mod_FreeSkinFiles(skinfiles);
3187 Mem_Free(animfilebuffer);
3188 Mod_MakeSortedSurfaces(loadmodel);
3190 // compute all the mesh information that was not loaded from the file
3191 // TODO: honor smoothing groups somehow?
3192 if (loadmodel->surfmesh.data_element3s)
3193 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3194 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3195 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3196 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);
3197 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);
3198 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3199 if(mod_alias_force_animated.string[0])
3200 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3202 // Always make a BIH for the first frame, we can use it where possible.
3203 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3204 if (!loadmodel->surfmesh.isanimated)
3206 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3207 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3208 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3209 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3210 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3213 // because shaders can do somewhat unexpected things, check for unusual features now
3214 for (i = 0;i < loadmodel->num_textures;i++)
3216 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3217 mod->DrawSky = R_Q1BSP_DrawSky;
3218 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3219 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3223 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
3225 unsigned char *data;
3227 const unsigned char *pbase, *pend;
3229 skinfile_t *skinfiles;
3230 int i, j, k, meshvertices, meshtriangles;
3231 float biggestorigin;
3232 const unsigned int *inelements;
3234 float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3235 // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3236 const float *vnormal = NULL;
3237 const float *vposition = NULL;
3238 const float *vtangent = NULL;
3239 const float *vtexcoord = NULL;
3240 const float *vcolor4f = NULL;
3241 const unsigned char *vblendindexes = NULL;
3242 const unsigned char *vblendweights = NULL;
3243 const unsigned char *vcolor4ub = NULL;
3244 const unsigned short *framedata = NULL;
3245 // temporary memory allocations (because the data in the file may be misaligned)
3246 iqmanim_t *anims = NULL;
3247 iqmbounds_t *bounds = NULL;
3248 iqmjoint1_t *joint1 = NULL;
3249 iqmjoint_t *joint = NULL;
3250 iqmmesh_t *meshes = NULL;
3251 iqmpose1_t *pose1 = NULL;
3252 iqmpose_t *pose = NULL;
3253 iqmvertexarray_t *vas = NULL;
3255 pbase = (unsigned char *)buffer;
3256 pend = (unsigned char *)bufferend;
3258 if (pbase + sizeof(iqmheader_t) > pend)
3259 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3261 // copy struct (otherwise it may be misaligned)
3262 // LordHavoc: okay it's definitely not misaligned here, but for consistency...
3263 memcpy(&header, pbase, sizeof(iqmheader_t));
3265 if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3266 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3267 if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3268 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3270 loadmodel->modeldatatypestring = "IQM";
3272 loadmodel->type = mod_alias;
3273 loadmodel->synctype = ST_RAND;
3276 header.version = LittleLong(header.version);
3277 header.filesize = LittleLong(header.filesize);
3278 header.flags = LittleLong(header.flags);
3279 header.num_text = LittleLong(header.num_text);
3280 header.ofs_text = LittleLong(header.ofs_text);
3281 header.num_meshes = LittleLong(header.num_meshes);
3282 header.ofs_meshes = LittleLong(header.ofs_meshes);
3283 header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3284 header.num_vertexes = LittleLong(header.num_vertexes);
3285 header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3286 header.num_triangles = LittleLong(header.num_triangles);
3287 header.ofs_triangles = LittleLong(header.ofs_triangles);
3288 header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3289 header.num_joints = LittleLong(header.num_joints);
3290 header.ofs_joints = LittleLong(header.ofs_joints);
3291 header.num_poses = LittleLong(header.num_poses);
3292 header.ofs_poses = LittleLong(header.ofs_poses);
3293 header.num_anims = LittleLong(header.num_anims);
3294 header.ofs_anims = LittleLong(header.ofs_anims);
3295 header.num_frames = LittleLong(header.num_frames);
3296 header.num_framechannels = LittleLong(header.num_framechannels);
3297 header.ofs_frames = LittleLong(header.ofs_frames);
3298 header.ofs_bounds = LittleLong(header.ofs_bounds);
3299 header.num_comment = LittleLong(header.num_comment);
3300 header.ofs_comment = LittleLong(header.ofs_comment);
3301 header.num_extensions = LittleLong(header.num_extensions);
3302 header.ofs_extensions = LittleLong(header.ofs_extensions);
3304 if (header.version == 1)
3306 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3307 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3309 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3315 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3316 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3318 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3322 if (pbase + header.ofs_text + header.num_text > pend ||
3323 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3324 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3325 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3326 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3327 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3328 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3329 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3330 pbase + header.ofs_comment + header.num_comment > pend)
3332 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3336 // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3337 if (header.num_vertexarrays)
3338 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3339 if (header.num_anims)
3340 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3341 if (header.ofs_bounds)
3342 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3343 if (header.num_meshes)
3344 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3346 for (i = 0;i < (int)header.num_vertexarrays;i++)
3348 iqmvertexarray_t va;
3350 va.type = LittleLong(vas[i].type);
3351 va.flags = LittleLong(vas[i].flags);
3352 va.format = LittleLong(vas[i].format);
3353 va.size = LittleLong(vas[i].size);
3354 va.offset = LittleLong(vas[i].offset);
3355 vsize = header.num_vertexes*va.size;
3358 case IQM_FLOAT: vsize *= sizeof(float); break;
3359 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3362 if (pbase + va.offset + vsize > pend)
3364 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3368 if (va.format == IQM_FLOAT && va.size == 3)
3369 vposition = (const float *)(pbase + va.offset);
3372 if (va.format == IQM_FLOAT && va.size == 2)
3373 vtexcoord = (const float *)(pbase + va.offset);
3376 if (va.format == IQM_FLOAT && va.size == 3)
3377 vnormal = (const float *)(pbase + va.offset);
3380 if (va.format == IQM_FLOAT && va.size == 4)
3381 vtangent = (const float *)(pbase + va.offset);
3383 case IQM_BLENDINDEXES:
3384 if (va.format == IQM_UBYTE && va.size == 4)
3385 vblendindexes = (const unsigned char *)(pbase + va.offset);
3387 case IQM_BLENDWEIGHTS:
3388 if (va.format == IQM_UBYTE && va.size == 4)
3389 vblendweights = (const unsigned char *)(pbase + va.offset);
3392 if (va.format == IQM_FLOAT && va.size == 4)
3393 vcolor4f = (const float *)(pbase + va.offset);
3394 if (va.format == IQM_UBYTE && va.size == 4)
3395 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3399 if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3401 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3405 text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3407 loadmodel->DrawSky = NULL;
3408 loadmodel->DrawAddWaterPlanes = NULL;
3409 loadmodel->Draw = R_Q1BSP_Draw;
3410 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
3411 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
3412 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
3413 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
3414 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
3415 loadmodel->DrawLight = R_Q1BSP_DrawLight;
3416 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3417 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3418 loadmodel->PointSuperContents = NULL;
3419 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3421 // load external .skin files if present
3422 skinfiles = Mod_LoadSkinFiles();
3423 if (loadmodel->numskins < 1)
3424 loadmodel->numskins = 1;
3426 loadmodel->numframes = max(header.num_anims, 1);
3427 loadmodel->num_bones = header.num_joints;
3428 loadmodel->num_poses = max(header.num_frames, 1);
3429 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
3430 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3431 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3433 meshvertices = header.num_vertexes;
3434 meshtriangles = header.num_triangles;
3436 // do most allocations as one merged chunk
3437 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));
3438 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3439 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3440 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3441 loadmodel->surfmesh.num_vertices = meshvertices;
3442 loadmodel->surfmesh.num_triangles = meshtriangles;
3443 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3444 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3445 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3446 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3447 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3448 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3449 if (vcolor4f || vcolor4ub)
3451 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3453 if (vblendindexes && vblendweights)
3455 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3456 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3458 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3459 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3460 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3461 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3462 if (vblendindexes && vblendweights)
3464 loadmodel->surfmesh.num_blends = 0;
3465 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3467 if (meshvertices <= 65536)
3469 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3471 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3472 if (vblendindexes && vblendweights)
3473 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3475 for (i = 0;i < loadmodel->numskins;i++)
3477 loadmodel->skinscenes[i].firstframe = i;
3478 loadmodel->skinscenes[i].framecount = 1;
3479 loadmodel->skinscenes[i].loop = true;
3480 loadmodel->skinscenes[i].framerate = 10;
3483 // load the bone info
3484 if (header.version == 1)
3486 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3487 if (loadmodel->num_bones)
3488 joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3489 for (i = 0;i < loadmodel->num_bones;i++)
3491 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3492 joint1[i].name = LittleLong(injoint1[i].name);
3493 joint1[i].parent = LittleLong(injoint1[i].parent);
3494 for (j = 0;j < 3;j++)
3496 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3497 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3498 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3500 strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3501 loadmodel->data_bones[i].parent = joint1[i].parent;
3502 if (loadmodel->data_bones[i].parent >= i)
3503 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3504 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]);
3505 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3506 if (loadmodel->data_bones[i].parent >= 0)
3508 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3509 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3510 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3512 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3517 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3518 if (header.num_joints)
3519 joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3520 for (i = 0;i < loadmodel->num_bones;i++)
3522 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3523 joint[i].name = LittleLong(injoint[i].name);
3524 joint[i].parent = LittleLong(injoint[i].parent);
3525 for (j = 0;j < 3;j++)
3527 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3528 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3529 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3531 joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3532 strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3533 loadmodel->data_bones[i].parent = joint[i].parent;
3534 if (loadmodel->data_bones[i].parent >= i)
3535 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3536 if (joint[i].rotation[3] > 0)
3537 Vector4Negate(joint[i].rotation, joint[i].rotation);
3538 Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3539 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]);
3540 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3541 if (loadmodel->data_bones[i].parent >= 0)
3543 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3544 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3545 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3547 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3551 // set up the animscenes based on the anims
3552 for (i = 0;i < (int)header.num_anims;i++)
3555 anim.name = LittleLong(anims[i].name);
3556 anim.first_frame = LittleLong(anims[i].first_frame);
3557 anim.num_frames = LittleLong(anims[i].num_frames);
3558 anim.framerate = LittleFloat(anims[i].framerate);
3559 anim.flags = LittleLong(anims[i].flags);
3560 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3561 loadmodel->animscenes[i].firstframe = anim.first_frame;
3562 loadmodel->animscenes[i].framecount = anim.num_frames;
3563 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3564 loadmodel->animscenes[i].framerate = anim.framerate;
3566 if (header.num_anims <= 0)
3568 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3569 loadmodel->animscenes[0].firstframe = 0;
3570 loadmodel->animscenes[0].framecount = 1;
3571 loadmodel->animscenes[0].loop = true;
3572 loadmodel->animscenes[0].framerate = 10;
3575 loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3576 if(mod_alias_force_animated.string[0])
3577 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3580 if (header.version == 1)
3582 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3583 if (header.num_poses)
3584 pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3585 for (i = 0;i < (int)header.num_poses;i++)
3588 pose1[i].parent = LittleLong(inpose1[i].parent);
3589 pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3590 for (j = 0;j < 9;j++)
3592 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3593 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3595 f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3596 f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3597 f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3598 f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3599 f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3600 f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3602 if (header.num_frames <= 0)
3604 for (i = 0;i < loadmodel->num_bones;i++)
3607 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3608 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3609 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3615 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3616 if (header.num_poses)
3617 pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3618 for (i = 0;i < (int)header.num_poses;i++)
3621 pose[i].parent = LittleLong(inpose[i].parent);
3622 pose[i].channelmask = LittleLong(inpose[i].channelmask);
3623 for (j = 0;j < 10;j++)
3625 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3626 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3628 f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3629 f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3630 f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3631 f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3632 f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3633 f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3635 if (header.num_frames <= 0)
3637 for (i = 0;i < loadmodel->num_bones;i++)
3640 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3641 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3642 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3646 loadmodel->num_posescale = biggestorigin / 32767.0f;
3647 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3649 // load the pose data
3650 // this unaligned memory access is safe (LittleShort reads as bytes)
3651 framedata = (const unsigned short *)(pbase + header.ofs_frames);
3652 if (header.version == 1)
3654 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3656 for (j = 0;j < (int)header.num_poses;j++, k++)
3658 float qx, qy, qz, qw;
3659 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));
3660 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));
3661 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));
3662 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3663 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3664 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3665 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3666 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3667 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3668 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3669 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3670 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3671 // skip scale data for now
3672 if(pose1[j].channelmask&64) framedata++;
3673 if(pose1[j].channelmask&128) framedata++;
3674 if(pose1[j].channelmask&256) framedata++;
3677 if (header.num_frames <= 0)
3679 for (i = 0;i < loadmodel->num_bones;i++)
3681 float qx, qy, qz, qw;
3682 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3683 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3684 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3685 qx = joint1[i].rotation[0];
3686 qy = joint1[i].rotation[1];
3687 qz = joint1[i].rotation[2];
3688 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3689 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3690 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3691 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3692 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3693 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3699 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3701 for (j = 0;j < (int)header.num_poses;j++, k++)
3704 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));
3705 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));
3706 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));
3707 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3708 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3709 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3710 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3712 Vector4Negate(rot, rot);
3713 Vector4Normalize2(rot, rot);
3714 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3715 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3716 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3717 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3718 // skip scale data for now
3719 if(pose[j].channelmask&128) framedata++;
3720 if(pose[j].channelmask&256) framedata++;
3721 if(pose[j].channelmask&512) framedata++;
3724 if (header.num_frames <= 0)
3726 for (i = 0;i < loadmodel->num_bones;i++)
3728 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3729 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3730 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3731 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3732 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3733 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3734 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3739 // load bounding box data
3740 if (header.ofs_bounds)
3742 float xyradius = 0, radius = 0;
3743 VectorClear(loadmodel->normalmins);
3744 VectorClear(loadmodel->normalmaxs);
3745 for (i = 0; i < (int)header.num_frames;i++)
3748 bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3749 bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3750 bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3751 bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);
3752 bound.maxs[1] = LittleFloat(bounds[i].maxs[1]);
3753 bound.maxs[2] = LittleFloat(bounds[i].maxs[2]);
3754 bound.xyradius = LittleFloat(bounds[i].xyradius);
3755 bound.radius = LittleFloat(bounds[i].radius);
3758 VectorCopy(bound.mins, loadmodel->normalmins);
3759 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3763 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3764 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3765 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3766 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3767 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3768 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3770 if (bound.xyradius > xyradius)
3771 xyradius = bound.xyradius;
3772 if (bound.radius > radius)
3773 radius = bound.radius;
3775 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3776 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3777 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3778 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3779 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3780 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3781 loadmodel->radius = radius;
3782 loadmodel->radius2 = radius * radius;
3785 // load triangle data
3786 // this unaligned memory access is safe (LittleLong reads as bytes)
3787 inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3788 outelements = loadmodel->surfmesh.data_element3i;
3789 for (i = 0;i < (int)header.num_triangles;i++)
3791 outelements[0] = LittleLong(inelements[0]);
3792 outelements[1] = LittleLong(inelements[1]);
3793 outelements[2] = LittleLong(inelements[2]);
3797 if (loadmodel->surfmesh.data_element3s)
3798 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3799 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3800 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3803 // this unaligned memory access is safe (LittleFloat reads as bytes)
3804 outvertex = loadmodel->surfmesh.data_vertex3f;
3805 for (i = 0;i < (int)header.num_vertexes;i++)
3807 outvertex[0] = LittleFloat(vposition[0]);
3808 outvertex[1] = LittleFloat(vposition[1]);
3809 outvertex[2] = LittleFloat(vposition[2]);
3814 outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3815 // this unaligned memory access is safe (LittleFloat reads as bytes)
3816 for (i = 0;i < (int)header.num_vertexes;i++)
3818 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3819 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3824 // this unaligned memory access is safe (LittleFloat reads as bytes)
3827 outnormal = loadmodel->surfmesh.data_normal3f;
3828 for (i = 0;i < (int)header.num_vertexes;i++)
3830 outnormal[0] = LittleFloat(vnormal[0]);
3831 outnormal[1] = LittleFloat(vnormal[1]);
3832 outnormal[2] = LittleFloat(vnormal[2]);
3838 // this unaligned memory access is safe (LittleFloat reads as bytes)
3839 if(vnormal && vtangent)
3841 outnormal = loadmodel->surfmesh.data_normal3f;
3842 outsvector = loadmodel->surfmesh.data_svector3f;
3843 outtvector = loadmodel->surfmesh.data_tvector3f;
3844 for (i = 0;i < (int)header.num_vertexes;i++)
3846 outsvector[0] = LittleFloat(vtangent[0]);
3847 outsvector[1] = LittleFloat(vtangent[1]);
3848 outsvector[2] = LittleFloat(vtangent[2]);
3849 if(LittleFloat(vtangent[3]) < 0)
3850 CrossProduct(outsvector, outnormal, outtvector);
3852 CrossProduct(outnormal, outsvector, outtvector);
3860 // this unaligned memory access is safe (all bytes)
3861 if (vblendindexes && vblendweights)
3863 for (i = 0; i < (int)header.num_vertexes;i++)
3865 blendweights_t weights;
3866 memcpy(weights.index, vblendindexes + i*4, 4);
3867 memcpy(weights.influence, vblendweights + i*4, 4);
3868 loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3869 loadmodel->surfmesh.data_skeletalindex4ub[i*4 ] = weights.index[0];
3870 loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3871 loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3872 loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3873 loadmodel->surfmesh.data_skeletalweight4ub[i*4 ] = weights.influence[0];
3874 loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3875 loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3876 loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3882 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3883 // this unaligned memory access is safe (LittleFloat reads as bytes)
3884 for (i = 0;i < (int)header.num_vertexes;i++)
3886 outcolor[0] = LittleFloat(vcolor4f[0]);
3887 outcolor[1] = LittleFloat(vcolor4f[1]);
3888 outcolor[2] = LittleFloat(vcolor4f[2]);
3889 outcolor[3] = LittleFloat(vcolor4f[3]);
3896 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3897 // this unaligned memory access is safe (all bytes)
3898 for (i = 0;i < (int)header.num_vertexes;i++)
3900 outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3901 outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3902 outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3903 outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3910 for (i = 0;i < (int)header.num_meshes;i++)
3913 msurface_t *surface;
3915 mesh.name = LittleLong(meshes[i].name);
3916 mesh.material = LittleLong(meshes[i].material);
3917 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3918 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3919 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3920 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3922 loadmodel->sortedmodelsurfaces[i] = i;
3923 surface = loadmodel->data_surfaces + i;
3924 surface->texture = loadmodel->data_textures + i;
3925 surface->num_firsttriangle = mesh.first_triangle;
3926 surface->num_triangles = mesh.num_triangles;
3927 surface->num_firstvertex = mesh.first_vertex;
3928 surface->num_vertices = mesh.num_vertexes;
3930 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3933 Mod_FreeSkinFiles(skinfiles);
3934 Mod_MakeSortedSurfaces(loadmodel);
3936 // compute all the mesh information that was not loaded from the file
3938 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);
3939 if (!vnormal || !vtangent)
3940 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);
3941 if (!header.ofs_bounds)
3942 Mod_Alias_CalculateBoundingBox();
3944 // Always make a BIH for the first frame, we can use it where possible.
3945 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3946 if (!loadmodel->surfmesh.isanimated)
3948 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3949 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3950 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3951 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3952 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3955 if (joint ) Mem_Free(joint );joint = NULL;
3956 if (joint1 ) Mem_Free(joint1 );joint1 = NULL;
3957 if (pose ) Mem_Free(pose );pose = NULL;
3958 if (pose1 ) Mem_Free(pose1 );pose1 = NULL;
3960 // because shaders can do somewhat unexpected things, check for unusual features now
3961 for (i = 0;i < loadmodel->num_textures;i++)
3963 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3964 mod->DrawSky = R_Q1BSP_DrawSky;
3965 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3966 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;