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, loadmodel->surfmesh.data_element3s, 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 const float *intexcoord;
2410 msurface_t *surface;
2412 loadmodel->sortedmodelsurfaces[i] = i;
2413 surface = loadmodel->data_surfaces + i;
2414 surface->texture = loadmodel->data_textures + i;
2415 surface->num_firsttriangle = meshtriangles;
2416 surface->num_triangles = BigLong(dpmmesh->num_tris);
2417 surface->num_firstvertex = meshvertices;
2418 surface->num_vertices = BigLong(dpmmesh->num_verts);
2419 meshvertices += surface->num_vertices;
2420 meshtriangles += surface->num_triangles;
2422 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2423 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2424 for (j = 0;j < surface->num_triangles;j++)
2426 // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2427 outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2428 outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2429 outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2434 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2435 for (j = 0;j < surface->num_vertices*2;j++)
2436 loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2438 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2439 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2441 int weightindex[4] = { 0, 0, 0, 0 };
2442 float weightinfluence[4] = { 0, 0, 0, 0 };
2444 int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2445 data += sizeof(dpmvertex_t);
2446 for (k = 0;k < numweights;k++)
2448 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2449 int boneindex = BigLong(vert->bonenum);
2450 const float *m = bonepose + 12 * boneindex;
2451 float influence = BigFloat(vert->influence);
2452 float relativeorigin[3], relativenormal[3];
2453 relativeorigin[0] = BigFloat(vert->origin[0]);
2454 relativeorigin[1] = BigFloat(vert->origin[1]);
2455 relativeorigin[2] = BigFloat(vert->origin[2]);
2456 relativenormal[0] = BigFloat(vert->normal[0]);
2457 relativenormal[1] = BigFloat(vert->normal[1]);
2458 relativenormal[2] = BigFloat(vert->normal[2]);
2459 // blend the vertex bone weights into the base mesh
2460 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2461 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2462 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2463 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2464 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2465 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2468 // store the first (and often only) weight
2469 weightinfluence[0] = influence;
2470 weightindex[0] = boneindex;
2474 // sort the new weight into this vertex's weight table
2475 // (which only accepts up to 4 bones per vertex)
2476 for (l = 0;l < 4;l++)
2478 if (weightinfluence[l] < influence)
2480 // move weaker influence weights out of the way first
2482 for (l2 = 3;l2 > l;l2--)
2484 weightinfluence[l2] = weightinfluence[l2-1];
2485 weightindex[l2] = weightindex[l2-1];
2487 // store the new weight
2488 weightinfluence[l] = influence;
2489 weightindex[l] = boneindex;
2494 data += sizeof(dpmbonevert_t);
2496 loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2497 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = weightindex[0];
2498 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2499 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2500 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2501 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
2502 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2503 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2504 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2507 // since dpm models do not have named sections, reuse their shader name as the section name
2508 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2510 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__);
2512 if (loadmodel->surfmesh.num_blends < meshvertices)
2513 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2515 Mod_FreeSkinFiles(skinfiles);
2516 Mod_MakeSortedSurfaces(loadmodel);
2518 // compute all the mesh information that was not loaded from the file
2519 if (loadmodel->surfmesh.data_element3s)
2520 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2521 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2522 Mod_BuildBaseBonePoses();
2523 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);
2524 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2525 if(mod_alias_force_animated.string[0])
2526 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2528 // Always make a BIH for the first frame, we can use it where possible.
2529 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2530 if (!loadmodel->surfmesh.isanimated)
2532 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2533 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2534 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2535 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2536 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2539 // because shaders can do somewhat unexpected things, check for unusual features now
2540 for (i = 0;i < loadmodel->num_textures;i++)
2542 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2543 mod->DrawSky = R_Q1BSP_DrawSky;
2544 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2545 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2549 // no idea why PSK/PSA files contain weird quaternions but they do...
2550 #define PSKQUATNEGATIONS
2551 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2553 int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2554 int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2555 fs_offset_t filesize;
2560 pskboneinfo_t *bones;
2561 pskrawweights_t *rawweights;
2562 //pskboneinfo_t *animbones;
2563 pskaniminfo_t *anims;
2564 pskanimkeys_t *animkeys;
2565 void *animfilebuffer, *animbuffer, *animbufferend;
2566 unsigned char *data;
2568 skinfile_t *skinfiles;
2569 char animname[MAX_QPATH];
2571 float biggestorigin;
2573 pchunk = (pskchunk_t *)buffer;
2574 if (strcmp(pchunk->id, "ACTRHEAD"))
2575 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2577 loadmodel->modeldatatypestring = "PSK";
2579 loadmodel->type = mod_alias;
2580 loadmodel->DrawSky = NULL;
2581 loadmodel->DrawAddWaterPlanes = NULL;
2582 loadmodel->Draw = R_Q1BSP_Draw;
2583 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2584 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2585 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2586 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2587 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2588 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2589 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2590 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2591 loadmodel->PointSuperContents = NULL;
2592 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2593 loadmodel->synctype = ST_RAND;
2595 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2596 strlcat(animname, ".psa", sizeof(animname));
2597 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2598 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2600 animbufferend = animbuffer;
2619 while (buffer < bufferend)
2621 pchunk = (pskchunk_t *)buffer;
2622 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2623 version = LittleLong(pchunk->version);
2624 recordsize = LittleLong(pchunk->recordsize);
2625 numrecords = LittleLong(pchunk->numrecords);
2626 if (developer_extra.integer)
2627 Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2628 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2629 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);
2630 if (!strcmp(pchunk->id, "ACTRHEAD"))
2634 else if (!strcmp(pchunk->id, "PNTS0000"))
2637 if (recordsize != sizeof(*p))
2638 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2639 // byteswap in place and keep the pointer
2640 numpnts = numrecords;
2641 pnts = (pskpnts_t *)buffer;
2642 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2644 p->origin[0] = LittleFloat(p->origin[0]);
2645 p->origin[1] = LittleFloat(p->origin[1]);
2646 p->origin[2] = LittleFloat(p->origin[2]);
2650 else if (!strcmp(pchunk->id, "VTXW0000"))
2653 if (recordsize != sizeof(*p))
2654 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2655 // byteswap in place and keep the pointer
2656 numvtxw = numrecords;
2657 vtxw = (pskvtxw_t *)buffer;
2658 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2660 p->pntsindex = LittleShort(p->pntsindex);
2661 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2662 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2663 if (p->pntsindex >= numpnts)
2665 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2671 else if (!strcmp(pchunk->id, "FACE0000"))
2674 if (recordsize != sizeof(*p))
2675 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2676 // byteswap in place and keep the pointer
2677 numfaces = numrecords;
2678 faces = (pskface_t *)buffer;
2679 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2681 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2682 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2683 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2684 p->group = LittleLong(p->group);
2685 if (p->vtxwindex[0] >= numvtxw)
2687 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2688 p->vtxwindex[0] = 0;
2690 if (p->vtxwindex[1] >= numvtxw)
2692 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2693 p->vtxwindex[1] = 0;
2695 if (p->vtxwindex[2] >= numvtxw)
2697 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2698 p->vtxwindex[2] = 0;
2703 else if (!strcmp(pchunk->id, "MATT0000"))
2706 if (recordsize != sizeof(*p))
2707 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2708 // byteswap in place and keep the pointer
2709 nummatts = numrecords;
2710 matts = (pskmatt_t *)buffer;
2711 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2717 else if (!strcmp(pchunk->id, "REFSKELT"))
2720 if (recordsize != sizeof(*p))
2721 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2722 // byteswap in place and keep the pointer
2723 numbones = numrecords;
2724 bones = (pskboneinfo_t *)buffer;
2725 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2727 p->numchildren = LittleLong(p->numchildren);
2728 p->parent = LittleLong(p->parent);
2729 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2730 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2731 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2732 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2733 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2734 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2735 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2736 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2737 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2738 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2739 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2740 #ifdef PSKQUATNEGATIONS
2743 p->basepose.quat[0] *= -1;
2744 p->basepose.quat[1] *= -1;
2745 p->basepose.quat[2] *= -1;
2749 p->basepose.quat[0] *= 1;
2750 p->basepose.quat[1] *= -1;
2751 p->basepose.quat[2] *= 1;
2754 if (p->parent < 0 || p->parent >= numbones)
2756 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2762 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2765 if (recordsize != sizeof(*p))
2766 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2767 // byteswap in place and keep the pointer
2768 numrawweights = numrecords;
2769 rawweights = (pskrawweights_t *)buffer;
2770 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2772 p->weight = LittleFloat(p->weight);
2773 p->pntsindex = LittleLong(p->pntsindex);
2774 p->boneindex = LittleLong(p->boneindex);
2775 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2777 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2780 if (p->boneindex < 0 || p->boneindex >= numbones)
2782 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2790 while (animbuffer < animbufferend)
2792 pchunk = (pskchunk_t *)animbuffer;
2793 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2794 version = LittleLong(pchunk->version);
2795 recordsize = LittleLong(pchunk->recordsize);
2796 numrecords = LittleLong(pchunk->numrecords);
2797 if (developer_extra.integer)
2798 Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2799 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2800 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);
2801 if (!strcmp(pchunk->id, "ANIMHEAD"))
2805 else if (!strcmp(pchunk->id, "BONENAMES"))
2808 if (recordsize != sizeof(*p))
2809 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2810 // byteswap in place and keep the pointer
2811 numanimbones = numrecords;
2812 //animbones = (pskboneinfo_t *)animbuffer;
2813 // NOTE: supposedly psa does not need to match the psk model, the
2814 // bones missing from the psa would simply use their base
2815 // positions from the psk, but this is hard for me to implement
2816 // and people can easily make animations that match.
2817 if (numanimbones != numbones)
2818 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2819 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2821 p->numchildren = LittleLong(p->numchildren);
2822 p->parent = LittleLong(p->parent);
2823 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2824 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2825 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2826 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2827 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2828 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2829 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2830 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2831 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2832 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2833 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2834 #ifdef PSKQUATNEGATIONS
2837 p->basepose.quat[0] *= -1;
2838 p->basepose.quat[1] *= -1;
2839 p->basepose.quat[2] *= -1;
2843 p->basepose.quat[0] *= 1;
2844 p->basepose.quat[1] *= -1;
2845 p->basepose.quat[2] *= 1;
2848 if (p->parent < 0 || p->parent >= numanimbones)
2850 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2853 // check that bones are the same as in the base
2854 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2855 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2859 else if (!strcmp(pchunk->id, "ANIMINFO"))
2862 if (recordsize != sizeof(*p))
2863 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2864 // byteswap in place and keep the pointer
2865 numanims = numrecords;
2866 anims = (pskaniminfo_t *)animbuffer;
2867 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2869 p->numbones = LittleLong(p->numbones);
2870 p->playtime = LittleFloat(p->playtime);
2871 p->fps = LittleFloat(p->fps);
2872 p->firstframe = LittleLong(p->firstframe);
2873 p->numframes = LittleLong(p->numframes);
2874 if (p->numbones != numbones)
2875 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2879 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2882 if (recordsize != sizeof(*p))
2883 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2884 numanimkeys = numrecords;
2885 animkeys = (pskanimkeys_t *)animbuffer;
2886 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2888 p->origin[0] = LittleFloat(p->origin[0]);
2889 p->origin[1] = LittleFloat(p->origin[1]);
2890 p->origin[2] = LittleFloat(p->origin[2]);
2891 p->quat[0] = LittleFloat(p->quat[0]);
2892 p->quat[1] = LittleFloat(p->quat[1]);
2893 p->quat[2] = LittleFloat(p->quat[2]);
2894 p->quat[3] = LittleFloat(p->quat[3]);
2895 p->frametime = LittleFloat(p->frametime);
2896 #ifdef PSKQUATNEGATIONS
2897 if (index % numbones)
2912 // TODO: allocate bonepose stuff
2915 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2918 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2919 Host_Error("%s: missing required chunks", loadmodel->name);
2923 loadmodel->numframes = 0;
2924 for (index = 0;index < numanims;index++)
2925 loadmodel->numframes += anims[index].numframes;
2926 if (numanimkeys != numbones * loadmodel->numframes)
2927 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2930 loadmodel->numframes = loadmodel->num_poses = 1;
2932 meshvertices = numvtxw;
2933 meshtriangles = numfaces;
2935 // load external .skin files if present
2936 skinfiles = Mod_LoadSkinFiles();
2937 if (loadmodel->numskins < 1)
2938 loadmodel->numskins = 1;
2939 loadmodel->num_bones = numbones;
2940 loadmodel->num_poses = loadmodel->numframes;
2941 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2942 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2943 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2944 loadmodel->surfmesh.num_vertices = meshvertices;
2945 loadmodel->surfmesh.num_triangles = meshtriangles;
2946 // do most allocations as one merged chunk
2947 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);
2948 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2949 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2950 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2951 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2952 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2953 loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2954 loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2955 loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2956 loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2957 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2958 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2959 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2960 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2961 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2962 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2963 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2964 loadmodel->surfmesh.num_blends = 0;
2965 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2966 if (loadmodel->surfmesh.num_vertices <= 65536)
2968 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2970 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2971 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2973 for (i = 0;i < loadmodel->numskins;i++)
2975 loadmodel->skinscenes[i].firstframe = i;
2976 loadmodel->skinscenes[i].framecount = 1;
2977 loadmodel->skinscenes[i].loop = true;
2978 loadmodel->skinscenes[i].framerate = 10;
2982 for (index = 0, i = 0;index < nummatts;index++)
2984 // since psk models do not have named sections, reuse their shader name as the section name
2985 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2986 loadmodel->sortedmodelsurfaces[index] = index;
2987 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2988 loadmodel->data_surfaces[index].num_firstvertex = 0;
2989 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2992 // copy over the vertex locations and texcoords
2993 for (index = 0;index < numvtxw;index++)
2995 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2996 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2997 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2998 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2999 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
3002 // loading the faces is complicated because we need to sort them into surfaces by mattindex
3003 for (index = 0;index < numfaces;index++)
3004 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
3005 for (index = 0, i = 0;index < nummatts;index++)
3007 loadmodel->data_surfaces[index].num_firsttriangle = i;
3008 i += loadmodel->data_surfaces[index].num_triangles;
3009 loadmodel->data_surfaces[index].num_triangles = 0;
3011 for (index = 0;index < numfaces;index++)
3013 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3014 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3015 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3016 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3019 // copy over the bones
3020 for (index = 0;index < numbones;index++)
3022 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3023 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3024 if (loadmodel->data_bones[index].parent >= index)
3025 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3028 // convert the basepose data
3029 if (loadmodel->num_bones)
3032 matrix4x4_t *basebonepose;
3033 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3034 matrix4x4_t bonematrix;
3035 matrix4x4_t tempbonematrix;
3036 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3037 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3039 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]);
3040 if (loadmodel->data_bones[boneindex].parent >= 0)
3042 tempbonematrix = bonematrix;
3043 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3045 basebonepose[boneindex] = bonematrix;
3046 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3047 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3049 Mem_Free(basebonepose);
3052 // sort the psk point weights into the vertex weight tables
3053 // (which only accept up to 4 bones per vertex)
3054 for (index = 0;index < numvtxw;index++)
3056 int weightindex[4] = { 0, 0, 0, 0 };
3057 float weightinfluence[4] = { 0, 0, 0, 0 };
3059 for (j = 0;j < numrawweights;j++)
3061 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3063 int boneindex = rawweights[j].boneindex;
3064 float influence = rawweights[j].weight;
3065 for (l = 0;l < 4;l++)
3067 if (weightinfluence[l] < influence)
3069 // move lower influence weights out of the way first
3071 for (l2 = 3;l2 > l;l2--)
3073 weightinfluence[l2] = weightinfluence[l2-1];
3074 weightindex[l2] = weightindex[l2-1];
3076 // store the new weight
3077 weightinfluence[l] = influence;
3078 weightindex[l] = boneindex;
3084 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3085 loadmodel->surfmesh.data_skeletalindex4ub[index*4 ] = weightindex[0];
3086 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3087 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3088 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3089 loadmodel->surfmesh.data_skeletalweight4ub[index*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
3090 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3091 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3092 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3094 if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3095 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3097 // set up the animscenes based on the anims
3100 for (index = 0, i = 0;index < numanims;index++)
3102 for (j = 0;j < anims[index].numframes;j++, i++)
3104 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3105 loadmodel->animscenes[i].firstframe = i;
3106 loadmodel->animscenes[i].framecount = 1;
3107 loadmodel->animscenes[i].loop = true;
3108 loadmodel->animscenes[i].framerate = anims[index].fps;
3111 // calculate the scaling value for bone origins so they can be compressed to short
3113 for (index = 0;index < numanimkeys;index++)
3115 pskanimkeys_t *k = animkeys + index;
3116 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3117 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3118 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3120 loadmodel->num_posescale = biggestorigin / 32767.0f;
3121 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3123 // load the poses from the animkeys
3124 for (index = 0;index < numanimkeys;index++)
3126 pskanimkeys_t *k = animkeys + index;
3128 Vector4Copy(k->quat, quat);
3130 Vector4Negate(quat, quat);
3131 Vector4Normalize2(quat, quat);
3132 // compress poses to the short[7] format for longterm storage
3133 loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3134 loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3135 loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3136 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3137 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3138 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3139 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3144 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3145 loadmodel->animscenes[0].firstframe = 0;
3146 loadmodel->animscenes[0].framecount = 1;
3147 loadmodel->animscenes[0].loop = true;
3148 loadmodel->animscenes[0].framerate = 10;
3150 // calculate the scaling value for bone origins so they can be compressed to short
3152 for (index = 0;index < numbones;index++)
3154 pskboneinfo_t *p = bones + index;
3155 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3156 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3157 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3159 loadmodel->num_posescale = biggestorigin / 32767.0f;
3160 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3162 // load the basepose as a frame
3163 for (index = 0;index < numbones;index++)
3165 pskboneinfo_t *p = bones + index;
3167 Vector4Copy(p->basepose.quat, quat);
3169 Vector4Negate(quat, quat);
3170 Vector4Normalize2(quat, quat);
3171 // compress poses to the short[7] format for longterm storage
3172 loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3173 loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3174 loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3175 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3176 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3177 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3178 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3182 Mod_FreeSkinFiles(skinfiles);
3184 Mem_Free(animfilebuffer);
3185 Mod_MakeSortedSurfaces(loadmodel);
3187 // compute all the mesh information that was not loaded from the file
3188 // TODO: honor smoothing groups somehow?
3189 if (loadmodel->surfmesh.data_element3s)
3190 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3191 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3192 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3193 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);
3194 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);
3195 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3196 if(mod_alias_force_animated.string[0])
3197 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3199 // Always make a BIH for the first frame, we can use it where possible.
3200 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3201 if (!loadmodel->surfmesh.isanimated)
3203 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3204 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3205 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3206 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3207 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3210 // because shaders can do somewhat unexpected things, check for unusual features now
3211 for (i = 0;i < loadmodel->num_textures;i++)
3213 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3214 mod->DrawSky = R_Q1BSP_DrawSky;
3215 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3216 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3220 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
3222 unsigned char *data;
3224 const unsigned char *pbase, *pend;
3226 skinfile_t *skinfiles;
3227 int i, j, k, meshvertices, meshtriangles;
3228 float biggestorigin;
3229 const unsigned int *inelements;
3231 float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3232 // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3233 const float *vnormal = NULL;
3234 const float *vposition = NULL;
3235 const float *vtangent = NULL;
3236 const float *vtexcoord = NULL;
3237 const float *vcolor4f = NULL;
3238 const unsigned char *vblendindexes = NULL;
3239 const unsigned char *vblendweights = NULL;
3240 const unsigned char *vcolor4ub = NULL;
3241 const unsigned short *framedata = NULL;
3242 // temporary memory allocations (because the data in the file may be misaligned)
3243 iqmanim_t *anims = NULL;
3244 iqmbounds_t *bounds = NULL;
3245 iqmjoint1_t *joint1 = NULL;
3246 iqmjoint_t *joint = NULL;
3247 iqmmesh_t *meshes = NULL;
3248 iqmpose1_t *pose1 = NULL;
3249 iqmpose_t *pose = NULL;
3250 iqmvertexarray_t *vas = NULL;
3252 pbase = (unsigned char *)buffer;
3253 pend = (unsigned char *)bufferend;
3255 if (pbase + sizeof(iqmheader_t) > pend)
3256 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3258 // copy struct (otherwise it may be misaligned)
3259 // LordHavoc: okay it's definitely not misaligned here, but for consistency...
3260 memcpy(&header, pbase, sizeof(iqmheader_t));
3262 if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3263 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3264 if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3265 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3267 loadmodel->modeldatatypestring = "IQM";
3269 loadmodel->type = mod_alias;
3270 loadmodel->synctype = ST_RAND;
3273 header.version = LittleLong(header.version);
3274 header.filesize = LittleLong(header.filesize);
3275 header.flags = LittleLong(header.flags);
3276 header.num_text = LittleLong(header.num_text);
3277 header.ofs_text = LittleLong(header.ofs_text);
3278 header.num_meshes = LittleLong(header.num_meshes);
3279 header.ofs_meshes = LittleLong(header.ofs_meshes);
3280 header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3281 header.num_vertexes = LittleLong(header.num_vertexes);
3282 header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3283 header.num_triangles = LittleLong(header.num_triangles);
3284 header.ofs_triangles = LittleLong(header.ofs_triangles);
3285 header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3286 header.num_joints = LittleLong(header.num_joints);
3287 header.ofs_joints = LittleLong(header.ofs_joints);
3288 header.num_poses = LittleLong(header.num_poses);
3289 header.ofs_poses = LittleLong(header.ofs_poses);
3290 header.num_anims = LittleLong(header.num_anims);
3291 header.ofs_anims = LittleLong(header.ofs_anims);
3292 header.num_frames = LittleLong(header.num_frames);
3293 header.num_framechannels = LittleLong(header.num_framechannels);
3294 header.ofs_frames = LittleLong(header.ofs_frames);
3295 header.ofs_bounds = LittleLong(header.ofs_bounds);
3296 header.num_comment = LittleLong(header.num_comment);
3297 header.ofs_comment = LittleLong(header.ofs_comment);
3298 header.num_extensions = LittleLong(header.num_extensions);
3299 header.ofs_extensions = LittleLong(header.ofs_extensions);
3301 if (header.version == 1)
3303 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3304 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3306 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3312 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3313 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3315 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3319 if (pbase + header.ofs_text + header.num_text > pend ||
3320 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3321 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3322 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3323 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3324 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3325 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3326 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3327 pbase + header.ofs_comment + header.num_comment > pend)
3329 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3333 // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3334 if (header.num_vertexarrays)
3335 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3336 if (header.num_anims)
3337 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3338 if (header.ofs_bounds)
3339 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3340 if (header.num_meshes)
3341 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3343 for (i = 0;i < (int)header.num_vertexarrays;i++)
3345 iqmvertexarray_t va;
3347 va.type = LittleLong(vas[i].type);
3348 va.flags = LittleLong(vas[i].flags);
3349 va.format = LittleLong(vas[i].format);
3350 va.size = LittleLong(vas[i].size);
3351 va.offset = LittleLong(vas[i].offset);
3352 vsize = header.num_vertexes*va.size;
3355 case IQM_FLOAT: vsize *= sizeof(float); break;
3356 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3359 if (pbase + va.offset + vsize > pend)
3361 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3365 if (va.format == IQM_FLOAT && va.size == 3)
3366 vposition = (const float *)(pbase + va.offset);
3369 if (va.format == IQM_FLOAT && va.size == 2)
3370 vtexcoord = (const float *)(pbase + va.offset);
3373 if (va.format == IQM_FLOAT && va.size == 3)
3374 vnormal = (const float *)(pbase + va.offset);
3377 if (va.format == IQM_FLOAT && va.size == 4)
3378 vtangent = (const float *)(pbase + va.offset);
3380 case IQM_BLENDINDEXES:
3381 if (va.format == IQM_UBYTE && va.size == 4)
3382 vblendindexes = (const unsigned char *)(pbase + va.offset);
3384 case IQM_BLENDWEIGHTS:
3385 if (va.format == IQM_UBYTE && va.size == 4)
3386 vblendweights = (const unsigned char *)(pbase + va.offset);
3389 if (va.format == IQM_FLOAT && va.size == 4)
3390 vcolor4f = (const float *)(pbase + va.offset);
3391 if (va.format == IQM_UBYTE && va.size == 4)
3392 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3396 if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3398 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3402 text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3404 loadmodel->DrawSky = NULL;
3405 loadmodel->DrawAddWaterPlanes = NULL;
3406 loadmodel->Draw = R_Q1BSP_Draw;
3407 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
3408 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
3409 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
3410 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
3411 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
3412 loadmodel->DrawLight = R_Q1BSP_DrawLight;
3413 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3414 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3415 loadmodel->PointSuperContents = NULL;
3416 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3418 // load external .skin files if present
3419 skinfiles = Mod_LoadSkinFiles();
3420 if (loadmodel->numskins < 1)
3421 loadmodel->numskins = 1;
3423 loadmodel->numframes = max(header.num_anims, 1);
3424 loadmodel->num_bones = header.num_joints;
3425 loadmodel->num_poses = max(header.num_frames, 1);
3426 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
3427 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3428 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3430 meshvertices = header.num_vertexes;
3431 meshtriangles = header.num_triangles;
3433 // do most allocations as one merged chunk
3434 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));
3435 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3436 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3437 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3438 loadmodel->surfmesh.num_vertices = meshvertices;
3439 loadmodel->surfmesh.num_triangles = meshtriangles;
3440 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3441 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3442 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3443 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3444 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3445 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3446 if (vcolor4f || vcolor4ub)
3448 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3450 if (vblendindexes && vblendweights)
3452 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3453 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3455 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3456 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3457 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3458 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3459 if (vblendindexes && vblendweights)
3461 loadmodel->surfmesh.num_blends = 0;
3462 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3464 if (meshvertices <= 65536)
3466 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3468 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3469 if (vblendindexes && vblendweights)
3470 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3472 for (i = 0;i < loadmodel->numskins;i++)
3474 loadmodel->skinscenes[i].firstframe = i;
3475 loadmodel->skinscenes[i].framecount = 1;
3476 loadmodel->skinscenes[i].loop = true;
3477 loadmodel->skinscenes[i].framerate = 10;
3480 // load the bone info
3481 if (header.version == 1)
3483 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3484 if (loadmodel->num_bones)
3485 joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3486 for (i = 0;i < loadmodel->num_bones;i++)
3488 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3489 joint1[i].name = LittleLong(injoint1[i].name);
3490 joint1[i].parent = LittleLong(injoint1[i].parent);
3491 for (j = 0;j < 3;j++)
3493 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3494 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3495 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3497 strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3498 loadmodel->data_bones[i].parent = joint1[i].parent;
3499 if (loadmodel->data_bones[i].parent >= i)
3500 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3501 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]);
3502 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3503 if (loadmodel->data_bones[i].parent >= 0)
3505 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3506 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3507 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3509 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3514 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3515 if (header.num_joints)
3516 joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3517 for (i = 0;i < loadmodel->num_bones;i++)
3519 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3520 joint[i].name = LittleLong(injoint[i].name);
3521 joint[i].parent = LittleLong(injoint[i].parent);
3522 for (j = 0;j < 3;j++)
3524 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3525 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3526 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3528 joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3529 strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3530 loadmodel->data_bones[i].parent = joint[i].parent;
3531 if (loadmodel->data_bones[i].parent >= i)
3532 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3533 if (joint[i].rotation[3] > 0)
3534 Vector4Negate(joint[i].rotation, joint[i].rotation);
3535 Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3536 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]);
3537 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3538 if (loadmodel->data_bones[i].parent >= 0)
3540 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3541 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3542 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3544 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3548 // set up the animscenes based on the anims
3549 for (i = 0;i < (int)header.num_anims;i++)
3552 anim.name = LittleLong(anims[i].name);
3553 anim.first_frame = LittleLong(anims[i].first_frame);
3554 anim.num_frames = LittleLong(anims[i].num_frames);
3555 anim.framerate = LittleFloat(anims[i].framerate);
3556 anim.flags = LittleLong(anims[i].flags);
3557 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3558 loadmodel->animscenes[i].firstframe = anim.first_frame;
3559 loadmodel->animscenes[i].framecount = anim.num_frames;
3560 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3561 loadmodel->animscenes[i].framerate = anim.framerate;
3563 if (header.num_anims <= 0)
3565 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3566 loadmodel->animscenes[0].firstframe = 0;
3567 loadmodel->animscenes[0].framecount = 1;
3568 loadmodel->animscenes[0].loop = true;
3569 loadmodel->animscenes[0].framerate = 10;
3572 loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3573 if(mod_alias_force_animated.string[0])
3574 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3577 if (header.version == 1)
3579 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3580 if (header.num_poses)
3581 pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3582 for (i = 0;i < (int)header.num_poses;i++)
3585 pose1[i].parent = LittleLong(inpose1[i].parent);
3586 pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3587 for (j = 0;j < 9;j++)
3589 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3590 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3592 f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3593 f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3594 f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3595 f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3596 f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3597 f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3599 if (header.num_frames <= 0)
3601 for (i = 0;i < loadmodel->num_bones;i++)
3604 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3605 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3606 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3612 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3613 if (header.num_poses)
3614 pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3615 for (i = 0;i < (int)header.num_poses;i++)
3618 pose[i].parent = LittleLong(inpose[i].parent);
3619 pose[i].channelmask = LittleLong(inpose[i].channelmask);
3620 for (j = 0;j < 10;j++)
3622 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3623 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3625 f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3626 f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3627 f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3628 f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3629 f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3630 f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3632 if (header.num_frames <= 0)
3634 for (i = 0;i < loadmodel->num_bones;i++)
3637 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3638 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3639 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3643 loadmodel->num_posescale = biggestorigin / 32767.0f;
3644 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3646 // load the pose data
3647 // this unaligned memory access is safe (LittleShort reads as bytes)
3648 framedata = (const unsigned short *)(pbase + header.ofs_frames);
3649 if (header.version == 1)
3651 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3653 for (j = 0;j < (int)header.num_poses;j++, k++)
3655 float qx, qy, qz, qw;
3656 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));
3657 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));
3658 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));
3659 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3660 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3661 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3662 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3663 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3664 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3665 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3666 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3667 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3668 // skip scale data for now
3669 if(pose1[j].channelmask&64) framedata++;
3670 if(pose1[j].channelmask&128) framedata++;
3671 if(pose1[j].channelmask&256) framedata++;
3674 if (header.num_frames <= 0)
3676 for (i = 0;i < loadmodel->num_bones;i++)
3678 float qx, qy, qz, qw;
3679 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3680 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3681 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3682 qx = joint1[i].rotation[0];
3683 qy = joint1[i].rotation[1];
3684 qz = joint1[i].rotation[2];
3685 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3686 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3687 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3688 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3689 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3690 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3696 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3698 for (j = 0;j < (int)header.num_poses;j++, k++)
3701 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));
3702 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));
3703 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));
3704 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3705 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3706 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3707 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3709 Vector4Negate(rot, rot);
3710 Vector4Normalize2(rot, rot);
3711 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3712 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3713 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3714 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3715 // skip scale data for now
3716 if(pose[j].channelmask&128) framedata++;
3717 if(pose[j].channelmask&256) framedata++;
3718 if(pose[j].channelmask&512) framedata++;
3721 if (header.num_frames <= 0)
3723 for (i = 0;i < loadmodel->num_bones;i++)
3725 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3726 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3727 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3728 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3729 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3730 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3731 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3736 // load bounding box data
3737 if (header.ofs_bounds)
3739 float xyradius = 0, radius = 0;
3740 VectorClear(loadmodel->normalmins);
3741 VectorClear(loadmodel->normalmaxs);
3742 for (i = 0; i < (int)header.num_frames;i++)
3745 bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3746 bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3747 bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3748 bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);
3749 bound.maxs[1] = LittleFloat(bounds[i].maxs[1]);
3750 bound.maxs[2] = LittleFloat(bounds[i].maxs[2]);
3751 bound.xyradius = LittleFloat(bounds[i].xyradius);
3752 bound.radius = LittleFloat(bounds[i].radius);
3755 VectorCopy(bound.mins, loadmodel->normalmins);
3756 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3760 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3761 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3762 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3763 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3764 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3765 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3767 if (bound.xyradius > xyradius)
3768 xyradius = bound.xyradius;
3769 if (bound.radius > radius)
3770 radius = bound.radius;
3772 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3773 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3774 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3775 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3776 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3777 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3778 loadmodel->radius = radius;
3779 loadmodel->radius2 = radius * radius;
3782 // load triangle data
3783 // this unaligned memory access is safe (LittleLong reads as bytes)
3784 inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3785 outelements = loadmodel->surfmesh.data_element3i;
3786 for (i = 0;i < (int)header.num_triangles;i++)
3788 outelements[0] = LittleLong(inelements[0]);
3789 outelements[1] = LittleLong(inelements[1]);
3790 outelements[2] = LittleLong(inelements[2]);
3794 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3797 // this unaligned memory access is safe (LittleFloat reads as bytes)
3798 outvertex = loadmodel->surfmesh.data_vertex3f;
3799 for (i = 0;i < (int)header.num_vertexes;i++)
3801 outvertex[0] = LittleFloat(vposition[0]);
3802 outvertex[1] = LittleFloat(vposition[1]);
3803 outvertex[2] = LittleFloat(vposition[2]);
3808 outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3809 // this unaligned memory access is safe (LittleFloat reads as bytes)
3810 for (i = 0;i < (int)header.num_vertexes;i++)
3812 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3813 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3818 // this unaligned memory access is safe (LittleFloat reads as bytes)
3821 outnormal = loadmodel->surfmesh.data_normal3f;
3822 for (i = 0;i < (int)header.num_vertexes;i++)
3824 outnormal[0] = LittleFloat(vnormal[0]);
3825 outnormal[1] = LittleFloat(vnormal[1]);
3826 outnormal[2] = LittleFloat(vnormal[2]);
3832 // this unaligned memory access is safe (LittleFloat reads as bytes)
3833 if(vnormal && vtangent)
3835 outnormal = loadmodel->surfmesh.data_normal3f;
3836 outsvector = loadmodel->surfmesh.data_svector3f;
3837 outtvector = loadmodel->surfmesh.data_tvector3f;
3838 for (i = 0;i < (int)header.num_vertexes;i++)
3840 outsvector[0] = LittleFloat(vtangent[0]);
3841 outsvector[1] = LittleFloat(vtangent[1]);
3842 outsvector[2] = LittleFloat(vtangent[2]);
3843 if(LittleFloat(vtangent[3]) < 0)
3844 CrossProduct(outsvector, outnormal, outtvector);
3846 CrossProduct(outnormal, outsvector, outtvector);
3854 // this unaligned memory access is safe (all bytes)
3855 if (vblendindexes && vblendweights)
3857 for (i = 0; i < (int)header.num_vertexes;i++)
3859 blendweights_t weights;
3860 memcpy(weights.index, vblendindexes + i*4, 4);
3861 memcpy(weights.influence, vblendweights + i*4, 4);
3862 loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3863 loadmodel->surfmesh.data_skeletalindex4ub[i*4 ] = weights.index[0];
3864 loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3865 loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3866 loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3867 loadmodel->surfmesh.data_skeletalweight4ub[i*4 ] = weights.influence[0];
3868 loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3869 loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3870 loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3876 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3877 // this unaligned memory access is safe (LittleFloat reads as bytes)
3878 for (i = 0;i < (int)header.num_vertexes;i++)
3880 outcolor[0] = LittleFloat(vcolor4f[0]);
3881 outcolor[1] = LittleFloat(vcolor4f[1]);
3882 outcolor[2] = LittleFloat(vcolor4f[2]);
3883 outcolor[3] = LittleFloat(vcolor4f[3]);
3890 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3891 // this unaligned memory access is safe (all bytes)
3892 for (i = 0;i < (int)header.num_vertexes;i++)
3894 outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3895 outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3896 outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3897 outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3904 for (i = 0;i < (int)header.num_meshes;i++)
3907 msurface_t *surface;
3909 mesh.name = LittleLong(meshes[i].name);
3910 mesh.material = LittleLong(meshes[i].material);
3911 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3912 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3913 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3914 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3916 loadmodel->sortedmodelsurfaces[i] = i;
3917 surface = loadmodel->data_surfaces + i;
3918 surface->texture = loadmodel->data_textures + i;
3919 surface->num_firsttriangle = mesh.first_triangle;
3920 surface->num_triangles = mesh.num_triangles;
3921 surface->num_firstvertex = mesh.first_vertex;
3922 surface->num_vertices = mesh.num_vertexes;
3924 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3927 Mod_FreeSkinFiles(skinfiles);
3928 Mod_MakeSortedSurfaces(loadmodel);
3930 // compute all the mesh information that was not loaded from the file
3931 if (loadmodel->surfmesh.data_element3s)
3932 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3933 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3935 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);
3936 if (!vnormal || !vtangent)
3937 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);
3938 if (!header.ofs_bounds)
3939 Mod_Alias_CalculateBoundingBox();
3941 // Always make a BIH for the first frame, we can use it where possible.
3942 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3943 if (!loadmodel->surfmesh.isanimated)
3945 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3946 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3947 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3948 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3949 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3952 if (joint ) Mem_Free(joint );joint = NULL;
3953 if (joint1 ) Mem_Free(joint1 );joint1 = NULL;
3954 if (pose ) Mem_Free(pose );pose = NULL;
3955 if (pose1 ) Mem_Free(pose1 );pose1 = NULL;
3957 // because shaders can do somewhat unexpected things, check for unusual features now
3958 for (i = 0;i < loadmodel->num_textures;i++)
3960 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3961 mod->DrawSky = R_Q1BSP_DrawSky;
3962 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3963 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;