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 static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *skinframe)
927 if (cls.state == ca_dedicated)
931 skinframe = R_SkinFrame_LoadMissing();
932 memset(texture, 0, sizeof(*texture));
933 texture->currentframe = texture;
934 //texture->animated = false;
935 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(skinframe);
936 texture->currentskinframe = skinframe;
937 //texture->backgroundnumskinframes = 0;
938 //texture->customblendfunc[0] = 0;
939 //texture->customblendfunc[1] = 0;
940 //texture->surfaceflags = 0;
941 //texture->supercontents = 0;
942 //texture->surfaceparms = 0;
943 //texture->textureflags = 0;
945 texture->basematerialflags = MATERIALFLAG_WALL;
946 texture->basealpha = 1.0f;
947 if (texture->currentskinframe->hasalpha)
948 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
949 texture->currentmaterialflags = texture->basematerialflags;
950 texture->offsetmapping = OFFSETMAPPING_DEFAULT;
951 texture->offsetscale = 1;
952 texture->offsetbias = 0;
953 texture->specularscalemod = 1;
954 texture->specularpowermod = 1;
955 texture->surfaceflags = 0;
956 texture->supercontents = SUPERCONTENTS_SOLID;
957 if (!(texture->basematerialflags & MATERIALFLAG_BLENDED))
958 texture->supercontents |= SUPERCONTENTS_OPAQUE;
959 texture->transparentsort = TRANSPARENTSORT_DISTANCE;
960 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
961 // JUST GREP FOR "specularscalemod = 1".
964 void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
967 char stripbuf[MAX_QPATH];
968 skinfileitem_t *skinfileitem;
969 if(developer_extra.integer)
970 Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername);
973 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
974 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
976 memset(skin, 0, sizeof(*skin));
978 for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
980 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
981 if (!strcmp(skinfileitem->name, meshname))
983 Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
984 if(developer_extra.integer)
985 Con_DPrintf("--> got %s from skin file\n", stripbuf);
986 Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
992 // don't render unmentioned meshes
993 Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
994 if(developer_extra.integer)
995 Con_DPrintf("--> skipping\n");
996 skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
1002 if(developer_extra.integer)
1003 Con_DPrintf("--> using default\n");
1004 Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
1005 Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
1009 #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);
1010 #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);
1011 void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
1013 int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
1014 float scales, scalet, interval;
1015 msurface_t *surface;
1016 unsigned char *data;
1018 stvert_t *pinstverts;
1019 dtriangle_t *pintriangles;
1020 daliasskintype_t *pinskintype;
1021 daliasskingroup_t *pinskingroup;
1022 daliasskininterval_t *pinskinintervals;
1023 daliasframetype_t *pinframetype;
1024 daliasgroup_t *pinframegroup;
1025 unsigned char *datapointer, *startframes, *startskins;
1026 char name[MAX_QPATH];
1027 skinframe_t *tempskinframe;
1028 animscene_t *tempskinscenes;
1029 texture_t *tempaliasskins;
1031 int *vertonseam, *vertremap;
1032 skinfile_t *skinfiles;
1035 datapointer = (unsigned char *)buffer;
1036 pinmodel = (mdl_t *)datapointer;
1037 datapointer += sizeof(mdl_t);
1039 version = LittleLong (pinmodel->version);
1040 if (version != ALIAS_VERSION)
1041 Host_Error ("%s has wrong version number (%i should be %i)",
1042 loadmodel->name, version, ALIAS_VERSION);
1044 loadmodel->modeldatatypestring = "MDL";
1046 loadmodel->type = mod_alias;
1047 loadmodel->DrawSky = NULL;
1048 loadmodel->DrawAddWaterPlanes = NULL;
1049 loadmodel->Draw = R_Q1BSP_Draw;
1050 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1051 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1052 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1053 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1054 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1055 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1056 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1057 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1058 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1059 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1060 // FIXME add TraceBrush!
1061 loadmodel->PointSuperContents = NULL;
1062 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1064 loadmodel->num_surfaces = 1;
1065 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1066 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1067 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1068 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1069 loadmodel->sortedmodelsurfaces[0] = 0;
1071 loadmodel->numskins = LittleLong(pinmodel->numskins);
1072 BOUNDI(loadmodel->numskins,0,65536);
1073 skinwidth = LittleLong (pinmodel->skinwidth);
1074 BOUNDI(skinwidth,0,65536);
1075 skinheight = LittleLong (pinmodel->skinheight);
1076 BOUNDI(skinheight,0,65536);
1077 numverts = LittleLong(pinmodel->numverts);
1078 BOUNDI(numverts,0,65536);
1079 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1080 BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1081 loadmodel->numframes = LittleLong(pinmodel->numframes);
1082 BOUNDI(loadmodel->numframes,0,65536);
1083 loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1084 BOUNDI((int)loadmodel->synctype,0,2);
1085 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1086 i = LittleLong (pinmodel->flags);
1087 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1089 for (i = 0;i < 3;i++)
1091 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1092 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1095 startskins = datapointer;
1097 for (i = 0;i < loadmodel->numskins;i++)
1099 pinskintype = (daliasskintype_t *)datapointer;
1100 datapointer += sizeof(daliasskintype_t);
1101 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1105 pinskingroup = (daliasskingroup_t *)datapointer;
1106 datapointer += sizeof(daliasskingroup_t);
1107 groupskins = LittleLong(pinskingroup->numskins);
1108 datapointer += sizeof(daliasskininterval_t) * groupskins;
1111 for (j = 0;j < groupskins;j++)
1113 datapointer += skinwidth * skinheight;
1118 pinstverts = (stvert_t *)datapointer;
1119 datapointer += sizeof(stvert_t) * numverts;
1121 pintriangles = (dtriangle_t *)datapointer;
1122 datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1124 startframes = datapointer;
1125 loadmodel->surfmesh.num_morphframes = 0;
1126 for (i = 0;i < loadmodel->numframes;i++)
1128 pinframetype = (daliasframetype_t *)datapointer;
1129 datapointer += sizeof(daliasframetype_t);
1130 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1134 pinframegroup = (daliasgroup_t *)datapointer;
1135 datapointer += sizeof(daliasgroup_t);
1136 groupframes = LittleLong(pinframegroup->numframes);
1137 datapointer += sizeof(daliasinterval_t) * groupframes;
1140 for (j = 0;j < groupframes;j++)
1142 datapointer += sizeof(daliasframe_t);
1143 datapointer += sizeof(trivertx_t) * numverts;
1144 loadmodel->surfmesh.num_morphframes++;
1147 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1149 // store texture coordinates into temporary array, they will be stored
1150 // after usage is determined (triangle data)
1151 vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1152 vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1153 vertonseam = vertremap + numverts * 2;
1155 scales = 1.0 / skinwidth;
1156 scalet = 1.0 / skinheight;
1157 for (i = 0;i < numverts;i++)
1159 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1160 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1161 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1162 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1163 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1166 // load triangle data
1167 loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1169 // read the triangle elements
1170 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1171 for (j = 0;j < 3;j++)
1172 loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1173 // validate (note numverts is used because this is the original data)
1174 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1175 // now butcher the elements according to vertonseam and tri->facesfront
1176 // and then compact the vertex set to remove duplicates
1177 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1178 if (!LittleLong(pintriangles[i].facesfront)) // backface
1179 for (j = 0;j < 3;j++)
1180 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1181 loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1183 // (this uses vertremap to count usage to save some memory)
1184 for (i = 0;i < numverts*2;i++)
1186 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1187 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1188 // build remapping table and compact array
1189 loadmodel->surfmesh.num_vertices = 0;
1190 for (i = 0;i < numverts*2;i++)
1194 vertremap[i] = loadmodel->surfmesh.num_vertices;
1195 vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1196 vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1197 loadmodel->surfmesh.num_vertices++;
1200 vertremap[i] = -1; // not used at all
1202 // remap the elements to the new vertex set
1203 for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1204 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1205 // store the texture coordinates
1206 loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1207 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1209 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1210 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1213 // generate ushort elements array if possible
1214 if (loadmodel->surfmesh.num_vertices <= 65536)
1215 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1216 if (loadmodel->surfmesh.data_element3s)
1217 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1218 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1221 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1222 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1223 if (r_enableshadowvolumes.integer)
1225 loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1227 Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1228 if (loadmodel->surfmesh.data_neighbor3i)
1229 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1230 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1231 Mod_Alias_MorphMesh_CompileFrames();
1234 Mem_Free(vertremap);
1237 skinfiles = Mod_LoadSkinFiles();
1240 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1241 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1242 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1243 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1244 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1245 Mod_FreeSkinFiles(skinfiles);
1246 for (i = 0;i < loadmodel->numskins;i++)
1248 loadmodel->skinscenes[i].firstframe = i;
1249 loadmodel->skinscenes[i].framecount = 1;
1250 loadmodel->skinscenes[i].loop = true;
1251 loadmodel->skinscenes[i].framerate = 10;
1256 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1257 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1258 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1259 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1261 datapointer = startskins;
1262 for (i = 0;i < loadmodel->numskins;i++)
1264 pinskintype = (daliasskintype_t *)datapointer;
1265 datapointer += sizeof(daliasskintype_t);
1267 if (pinskintype->type == ALIAS_SKIN_SINGLE)
1274 pinskingroup = (daliasskingroup_t *)datapointer;
1275 datapointer += sizeof(daliasskingroup_t);
1277 groupskins = LittleLong (pinskingroup->numskins);
1279 pinskinintervals = (daliasskininterval_t *)datapointer;
1280 datapointer += sizeof(daliasskininterval_t) * groupskins;
1282 interval = LittleFloat(pinskinintervals[0].interval);
1283 if (interval < 0.01f)
1285 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1290 dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1291 loadmodel->skinscenes[i].firstframe = totalskins;
1292 loadmodel->skinscenes[i].framecount = groupskins;
1293 loadmodel->skinscenes[i].framerate = 1.0f / interval;
1294 loadmodel->skinscenes[i].loop = true;
1296 for (j = 0;j < groupskins;j++)
1299 dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1301 dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1302 if (!Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS))
1303 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight));
1304 datapointer += skinwidth * skinheight;
1308 // check for skins that don't exist in the model, but do exist as external images
1309 // (this was added because yummyluv kept pestering me about support for it)
1310 // TODO: support shaders here?
1311 while ((tempskinframe = R_SkinFrame_LoadExternal(va(vabuf, sizeof(vabuf), "%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false)))
1313 // expand the arrays to make room
1314 tempskinscenes = loadmodel->skinscenes;
1315 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1316 memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1317 Mem_Free(tempskinscenes);
1319 tempaliasskins = loadmodel->data_textures;
1320 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1321 memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1322 Mem_Free(tempaliasskins);
1324 // store the info about the new skin
1325 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
1326 strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1327 loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1328 loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1329 loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1330 loadmodel->skinscenes[loadmodel->numskins].loop = true;
1332 //increase skin counts
1333 loadmodel->num_textures++;
1334 loadmodel->numskins++;
1337 // fix up the pointers since they are pointing at the old textures array
1338 // FIXME: this is a hack!
1339 for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1340 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1344 surface = loadmodel->data_surfaces;
1345 surface->texture = loadmodel->data_textures;
1346 surface->num_firsttriangle = 0;
1347 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1348 surface->num_firstvertex = 0;
1349 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1351 if(mod_alias_force_animated.string[0])
1352 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1354 // Always make a BIH for the first frame, we can use it where possible.
1355 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1356 if (!loadmodel->surfmesh.isanimated)
1358 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1359 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1360 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1361 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1362 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1365 // because shaders can do somewhat unexpected things, check for unusual features now
1366 for (i = 0;i < loadmodel->num_textures;i++)
1368 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1369 mod->DrawSky = R_Q1BSP_DrawSky;
1370 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1371 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1375 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1377 int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1378 float iskinwidth, iskinheight;
1379 unsigned char *data;
1380 msurface_t *surface;
1382 unsigned char *base, *datapointer;
1383 md2frame_t *pinframe;
1385 md2triangle_t *intri;
1386 unsigned short *inst;
1387 struct md2verthash_s
1389 struct md2verthash_s *next;
1393 *hash, **md2verthash, *md2verthashdata;
1394 skinfile_t *skinfiles;
1396 pinmodel = (md2_t *)buffer;
1397 base = (unsigned char *)buffer;
1399 version = LittleLong (pinmodel->version);
1400 if (version != MD2ALIAS_VERSION)
1401 Host_Error ("%s has wrong version number (%i should be %i)",
1402 loadmodel->name, version, MD2ALIAS_VERSION);
1404 loadmodel->modeldatatypestring = "MD2";
1406 loadmodel->type = mod_alias;
1407 loadmodel->DrawSky = NULL;
1408 loadmodel->DrawAddWaterPlanes = NULL;
1409 loadmodel->Draw = R_Q1BSP_Draw;
1410 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1411 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1412 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1413 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1414 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1415 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1416 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1417 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1418 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1419 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1420 loadmodel->PointSuperContents = NULL;
1421 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1423 if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1424 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1425 if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1426 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1427 if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1428 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1429 if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1430 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1432 end = LittleLong(pinmodel->ofs_end);
1433 if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1434 Host_Error ("%s is not a valid model", loadmodel->name);
1435 if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1436 Host_Error ("%s is not a valid model", loadmodel->name);
1437 if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1438 Host_Error ("%s is not a valid model", loadmodel->name);
1439 if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1440 Host_Error ("%s is not a valid model", loadmodel->name);
1441 if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1442 Host_Error ("%s is not a valid model", loadmodel->name);
1444 loadmodel->numskins = LittleLong(pinmodel->num_skins);
1445 numxyz = LittleLong(pinmodel->num_xyz);
1446 numst = LittleLong(pinmodel->num_st);
1447 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1448 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1449 loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1450 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1451 skinwidth = LittleLong(pinmodel->skinwidth);
1452 skinheight = LittleLong(pinmodel->skinheight);
1453 iskinwidth = 1.0f / skinwidth;
1454 iskinheight = 1.0f / skinheight;
1456 loadmodel->num_surfaces = 1;
1457 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1458 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]) + (r_enableshadowvolumes.integer ? loadmodel->surfmesh.num_triangles * sizeof(int[3]) : 0));
1459 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1460 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1461 loadmodel->sortedmodelsurfaces[0] = 0;
1462 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1463 loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1464 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1465 if (r_enableshadowvolumes.integer)
1467 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1470 loadmodel->synctype = ST_RAND;
1473 inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1474 skinfiles = Mod_LoadSkinFiles();
1477 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1478 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1479 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1480 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1481 Mod_FreeSkinFiles(skinfiles);
1483 else if (loadmodel->numskins)
1485 // skins found (most likely not a player model)
1486 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1487 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1488 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1489 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1490 Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
1494 // no skins (most likely a player model)
1495 loadmodel->numskins = 1;
1496 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1497 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1498 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1499 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL);
1502 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1503 for (i = 0;i < loadmodel->numskins;i++)
1505 loadmodel->skinscenes[i].firstframe = i;
1506 loadmodel->skinscenes[i].framecount = 1;
1507 loadmodel->skinscenes[i].loop = true;
1508 loadmodel->skinscenes[i].framerate = 10;
1511 // load the triangles and stvert data
1512 inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1513 intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1514 md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1515 md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1516 // swap the triangle list
1517 loadmodel->surfmesh.num_vertices = 0;
1518 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1520 for (j = 0;j < 3;j++)
1522 xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1523 st = (unsigned short) LittleShort (intri[i].index_st[j]);
1526 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1531 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1534 hashindex = (xyz * 256 + st) & 65535;
1535 for (hash = md2verthash[hashindex];hash;hash = hash->next)
1536 if (hash->xyz == xyz && hash->st == st)
1540 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1543 hash->next = md2verthash[hashindex];
1544 md2verthash[hashindex] = hash;
1546 loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1550 vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1551 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));
1552 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1553 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1554 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1557 hash = md2verthashdata + i;
1558 vertremap[i] = hash->xyz;
1559 sts = LittleShort(inst[hash->st*2+0]);
1560 stt = LittleShort(inst[hash->st*2+1]);
1561 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1563 Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1567 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1568 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1571 Mem_Free(md2verthash);
1572 Mem_Free(md2verthashdata);
1574 // generate ushort elements array if possible
1575 if (loadmodel->surfmesh.num_vertices <= 65536)
1576 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1577 if (loadmodel->surfmesh.data_element3s)
1578 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1579 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1582 datapointer = (base + LittleLong(pinmodel->ofs_frames));
1583 for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1588 pinframe = (md2frame_t *)datapointer;
1589 datapointer += sizeof(md2frame_t);
1590 // store the frame scale/translate into the appropriate array
1591 for (j = 0;j < 3;j++)
1593 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1594 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1596 // convert the vertices
1597 v = (trivertx_t *)datapointer;
1598 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1599 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1600 out[k] = v[vertremap[k]];
1601 datapointer += numxyz * sizeof(trivertx_t);
1603 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1604 loadmodel->animscenes[i].firstframe = i;
1605 loadmodel->animscenes[i].framecount = 1;
1606 loadmodel->animscenes[i].framerate = 10;
1607 loadmodel->animscenes[i].loop = true;
1610 Mem_Free(vertremap);
1612 if (loadmodel->surfmesh.data_neighbor3i)
1613 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1614 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1615 Mod_Alias_MorphMesh_CompileFrames();
1616 if(mod_alias_force_animated.string[0])
1617 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1619 surface = loadmodel->data_surfaces;
1620 surface->texture = loadmodel->data_textures;
1621 surface->num_firsttriangle = 0;
1622 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1623 surface->num_firstvertex = 0;
1624 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1626 // Always make a BIH for the first frame, we can use it where possible.
1627 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1628 if (!loadmodel->surfmesh.isanimated)
1630 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1631 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1632 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1633 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1634 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1637 // because shaders can do somewhat unexpected things, check for unusual features now
1638 for (i = 0;i < loadmodel->num_textures;i++)
1640 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1641 mod->DrawSky = R_Q1BSP_DrawSky;
1642 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1643 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1647 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1649 int i, j, k, version, meshvertices, meshtriangles;
1650 unsigned char *data;
1651 msurface_t *surface;
1652 md3modelheader_t *pinmodel;
1653 md3frameinfo_t *pinframe;
1656 skinfile_t *skinfiles;
1658 pinmodel = (md3modelheader_t *)buffer;
1660 if (memcmp(pinmodel->identifier, "IDP3", 4))
1661 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1662 version = LittleLong (pinmodel->version);
1663 if (version != MD3VERSION)
1664 Host_Error ("%s has wrong version number (%i should be %i)",
1665 loadmodel->name, version, MD3VERSION);
1667 skinfiles = Mod_LoadSkinFiles();
1668 if (loadmodel->numskins < 1)
1669 loadmodel->numskins = 1;
1671 loadmodel->modeldatatypestring = "MD3";
1673 loadmodel->type = mod_alias;
1674 loadmodel->DrawSky = NULL;
1675 loadmodel->DrawAddWaterPlanes = NULL;
1676 loadmodel->Draw = R_Q1BSP_Draw;
1677 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1678 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1679 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1680 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1681 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1682 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1683 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1684 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1685 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1686 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1687 loadmodel->PointSuperContents = NULL;
1688 loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1689 loadmodel->synctype = ST_RAND;
1690 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1691 i = LittleLong (pinmodel->flags);
1692 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1694 // set up some global info about the model
1695 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1696 loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1698 // make skinscenes for the skins (no groups)
1699 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1700 for (i = 0;i < loadmodel->numskins;i++)
1702 loadmodel->skinscenes[i].firstframe = i;
1703 loadmodel->skinscenes[i].framecount = 1;
1704 loadmodel->skinscenes[i].loop = true;
1705 loadmodel->skinscenes[i].framerate = 10;
1709 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1710 for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1712 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1713 loadmodel->animscenes[i].firstframe = i;
1714 loadmodel->animscenes[i].framecount = 1;
1715 loadmodel->animscenes[i].framerate = 10;
1716 loadmodel->animscenes[i].loop = true;
1720 loadmodel->num_tagframes = loadmodel->numframes;
1721 loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1722 loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1723 for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1725 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1726 for (j = 0;j < 9;j++)
1727 loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1728 for (j = 0;j < 3;j++)
1729 loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1730 //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);
1736 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)))
1738 if (memcmp(pinmesh->identifier, "IDP3", 4))
1739 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1740 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1741 Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1742 meshvertices += LittleLong(pinmesh->num_vertices);
1743 meshtriangles += LittleLong(pinmesh->num_triangles);
1746 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1747 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1748 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1749 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]) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[2]) + meshvertices * loadmodel->numframes * sizeof(md3vertex_t));
1750 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1751 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1752 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1753 loadmodel->surfmesh.num_vertices = meshvertices;
1754 loadmodel->surfmesh.num_triangles = meshtriangles;
1755 loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1756 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1757 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1758 if (r_enableshadowvolumes.integer)
1760 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1762 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1763 loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1764 if (meshvertices <= 65536)
1766 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1771 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)))
1773 if (memcmp(pinmesh->identifier, "IDP3", 4))
1774 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1775 loadmodel->sortedmodelsurfaces[i] = i;
1776 surface = loadmodel->data_surfaces + i;
1777 surface->texture = loadmodel->data_textures + i;
1778 surface->num_firsttriangle = meshtriangles;
1779 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1780 surface->num_firstvertex = meshvertices;
1781 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1782 meshvertices += surface->num_vertices;
1783 meshtriangles += surface->num_triangles;
1785 for (j = 0;j < surface->num_triangles * 3;j++)
1786 loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1787 for (j = 0;j < surface->num_vertices;j++)
1789 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1790 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1792 for (j = 0;j < loadmodel->numframes;j++)
1794 const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1795 md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1796 for (k = 0;k < surface->num_vertices;k++, in++, out++)
1798 out->origin[0] = LittleShort(in->origin[0]);
1799 out->origin[1] = LittleShort(in->origin[1]);
1800 out->origin[2] = LittleShort(in->origin[2]);
1801 out->pitch = in->pitch;
1806 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1808 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1810 if (loadmodel->surfmesh.data_element3s)
1811 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1812 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1813 if (loadmodel->surfmesh.data_neighbor3i)
1814 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1815 Mod_Alias_MorphMesh_CompileFrames();
1816 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1817 Mod_FreeSkinFiles(skinfiles);
1818 Mod_MakeSortedSurfaces(loadmodel);
1819 if(mod_alias_force_animated.string[0])
1820 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1822 // Always make a BIH for the first frame, we can use it where possible.
1823 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1824 if (!loadmodel->surfmesh.isanimated)
1826 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1827 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1828 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1829 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1830 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1833 // because shaders can do somewhat unexpected things, check for unusual features now
1834 for (i = 0;i < loadmodel->num_textures;i++)
1836 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1837 mod->DrawSky = R_Q1BSP_DrawSky;
1838 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1839 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1843 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1845 zymtype1header_t *pinmodel, *pheader;
1846 unsigned char *pbase;
1847 int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1848 float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1849 zymvertex_t *verts, *vertdata;
1853 skinfile_t *skinfiles;
1854 unsigned char *data;
1855 msurface_t *surface;
1857 pinmodel = (zymtype1header_t *)buffer;
1858 pbase = (unsigned char *)buffer;
1859 if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1860 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1861 if (BigLong(pinmodel->type) != 1)
1862 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1864 loadmodel->modeldatatypestring = "ZYM";
1866 loadmodel->type = mod_alias;
1867 loadmodel->synctype = ST_RAND;
1871 pheader->type = BigLong(pinmodel->type);
1872 pheader->filesize = BigLong(pinmodel->filesize);
1873 pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1874 pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1875 pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1876 pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1877 pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1878 pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1879 pheader->radius = BigFloat(pinmodel->radius);
1880 pheader->numverts = BigLong(pinmodel->numverts);
1881 pheader->numtris = BigLong(pinmodel->numtris);
1882 pheader->numshaders = BigLong(pinmodel->numshaders);
1883 pheader->numbones = BigLong(pinmodel->numbones);
1884 pheader->numscenes = BigLong(pinmodel->numscenes);
1885 pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1886 pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1887 pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1888 pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1889 pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1890 pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1891 pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1892 pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1893 pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1894 pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1895 pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1896 pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1897 pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1898 pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1899 pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1900 pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1901 pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1902 pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1904 if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1906 Con_Printf("%s has no geometry\n", loadmodel->name);
1909 if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1911 Con_Printf("%s has no animations\n", loadmodel->name);
1915 loadmodel->DrawSky = NULL;
1916 loadmodel->DrawAddWaterPlanes = NULL;
1917 loadmodel->Draw = R_Q1BSP_Draw;
1918 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1919 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1920 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1921 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1922 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1923 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1924 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1925 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1926 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1927 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1928 loadmodel->PointSuperContents = NULL;
1929 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1931 loadmodel->numframes = pheader->numscenes;
1932 loadmodel->num_surfaces = pheader->numshaders;
1934 skinfiles = Mod_LoadSkinFiles();
1935 if (loadmodel->numskins < 1)
1936 loadmodel->numskins = 1;
1938 // make skinscenes for the skins (no groups)
1939 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1940 for (i = 0;i < loadmodel->numskins;i++)
1942 loadmodel->skinscenes[i].firstframe = i;
1943 loadmodel->skinscenes[i].framecount = 1;
1944 loadmodel->skinscenes[i].loop = true;
1945 loadmodel->skinscenes[i].framerate = 10;
1949 // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1950 modelradius = pheader->radius;
1951 for (i = 0;i < 3;i++)
1953 loadmodel->normalmins[i] = pheader->mins[i];
1954 loadmodel->normalmaxs[i] = pheader->maxs[i];
1955 loadmodel->rotatedmins[i] = -modelradius;
1956 loadmodel->rotatedmaxs[i] = modelradius;
1958 corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1959 corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1960 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1961 if (loadmodel->yawmaxs[0] > modelradius)
1962 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1963 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1964 loadmodel->yawmins[2] = loadmodel->normalmins[2];
1965 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1966 loadmodel->radius = modelradius;
1967 loadmodel->radius2 = modelradius * modelradius;
1969 // go through the lumps, swapping things
1971 //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1972 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1973 scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1974 numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1975 for (i = 0;i < pheader->numscenes;i++)
1977 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1978 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1979 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1980 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1981 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1982 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1983 Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1984 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1985 Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1986 if (loadmodel->animscenes[i].framerate < 0)
1987 Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1991 //zymlump_t lump_bones; // zymbone_t bone[numbones];
1992 loadmodel->num_bones = pheader->numbones;
1993 loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1994 bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1995 for (i = 0;i < pheader->numbones;i++)
1997 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1998 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1999 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2000 if (loadmodel->data_bones[i].parent >= i)
2001 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2004 //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
2005 vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
2006 bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
2007 for (i = 0;i < pheader->numverts;i++)
2009 vertbonecounts[i] = BigLong(bonecount[i]);
2010 if (vertbonecounts[i] != 1)
2011 Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
2014 loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
2016 meshvertices = pheader->numverts;
2017 meshtriangles = pheader->numtris;
2019 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
2020 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2021 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2022 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]) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + (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]));
2023 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2024 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2025 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2026 loadmodel->surfmesh.num_vertices = meshvertices;
2027 loadmodel->surfmesh.num_triangles = meshtriangles;
2028 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2029 if (r_enableshadowvolumes.integer)
2031 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2033 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2034 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2035 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2036 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2037 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2038 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2039 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2040 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2041 loadmodel->surfmesh.num_blends = 0;
2042 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2043 if (loadmodel->surfmesh.num_vertices <= 65536)
2045 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2047 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2048 loadmodel->surfmesh.data_blendweights = NULL;
2050 //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
2051 poses = (float *) (pheader->lump_poses.start + pbase);
2052 // figure out scale of model from root bone, for compatibility with old zmodel versions
2053 tempvec[0] = BigFloat(poses[0]);
2054 tempvec[1] = BigFloat(poses[1]);
2055 tempvec[2] = BigFloat(poses[2]);
2056 modelscale = VectorLength(tempvec);
2058 for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
2060 f = fabs(BigFloat(poses[i]));
2061 biggestorigin = max(biggestorigin, f);
2063 loadmodel->num_posescale = biggestorigin / 32767.0f;
2064 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2065 for (i = 0;i < numposes;i++)
2067 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
2068 for (j = 0;j < loadmodel->num_bones;j++)
2071 matrix4x4_t posematrix;
2072 for (k = 0;k < 12;k++)
2073 pose[k] = BigFloat(frameposes[j*12+k]);
2074 //if (j < loadmodel->num_bones)
2075 // 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));
2076 // scale child bones to match the root scale
2077 if (loadmodel->data_bones[j].parent >= 0)
2079 pose[3] *= modelscale;
2080 pose[7] *= modelscale;
2081 pose[11] *= modelscale;
2083 // normalize rotation matrix
2084 VectorNormalize(pose + 0);
2085 VectorNormalize(pose + 4);
2086 VectorNormalize(pose + 8);
2087 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2088 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2092 //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2093 verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2094 vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2095 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2096 // (converting from weight-blending skeletal animation to
2097 // deformation-based skeletal animation)
2098 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2099 for (i = 0;i < loadmodel->num_bones;i++)
2102 for (k = 0;k < 12;k++)
2103 m[k] = BigFloat(poses[i*12+k]);
2104 if (loadmodel->data_bones[i].parent >= 0)
2105 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2107 for (k = 0;k < 12;k++)
2108 bonepose[12*i+k] = m[k];
2110 for (j = 0;j < pheader->numverts;j++)
2112 // this format really should have had a per vertexweight weight value...
2113 // but since it does not, the weighting is completely ignored and
2114 // only one weight is allowed per vertex
2115 int boneindex = BigLong(vertdata[j].bonenum);
2116 const float *m = bonepose + 12 * boneindex;
2117 float relativeorigin[3];
2118 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2119 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2120 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2121 // transform the vertex bone weight into the base mesh
2122 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2123 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2124 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2125 // store the weight as the primary weight on this vertex
2126 loadmodel->surfmesh.blends[j] = boneindex;
2127 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = boneindex;
2128 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2129 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2130 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2131 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = 255;
2132 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2133 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2134 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2137 // normals and tangents are calculated after elements are loaded
2139 //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2140 outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2141 intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2142 for (i = 0;i < pheader->numverts;i++)
2144 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2145 // flip T coordinate for OpenGL
2146 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2149 //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2150 //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2151 //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2153 //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2154 //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)
2155 // byteswap, validate, and swap winding order of tris
2156 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2157 if (pheader->lump_render.length != count)
2158 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2159 renderlist = (int *) (pheader->lump_render.start + pbase);
2160 renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2162 for (i = 0;i < loadmodel->num_surfaces;i++)
2164 int firstvertex, lastvertex;
2165 if (renderlist >= renderlistend)
2166 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2167 count = BigLong(*renderlist);renderlist++;
2168 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2169 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2171 loadmodel->sortedmodelsurfaces[i] = i;
2172 surface = loadmodel->data_surfaces + i;
2173 surface->texture = loadmodel->data_textures + i;
2174 surface->num_firsttriangle = meshtriangles;
2175 surface->num_triangles = count;
2176 meshtriangles += surface->num_triangles;
2178 // load the elements
2179 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2180 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2182 outelements[j*3+2] = BigLong(renderlist[0]);
2183 outelements[j*3+1] = BigLong(renderlist[1]);
2184 outelements[j*3+0] = BigLong(renderlist[2]);
2186 // validate the elements and find the used vertex range
2187 firstvertex = meshvertices;
2189 for (j = 0;j < surface->num_triangles * 3;j++)
2191 if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2192 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2193 firstvertex = min(firstvertex, outelements[j]);
2194 lastvertex = max(lastvertex, outelements[j]);
2196 surface->num_firstvertex = firstvertex;
2197 surface->num_vertices = lastvertex + 1 - firstvertex;
2199 // since zym models do not have named sections, reuse their shader
2200 // name as the section name
2201 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2202 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2204 Mod_FreeSkinFiles(skinfiles);
2205 Mem_Free(vertbonecounts);
2207 Mod_MakeSortedSurfaces(loadmodel);
2209 // compute all the mesh information that was not loaded from the file
2210 if (loadmodel->surfmesh.data_element3s)
2211 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2212 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2213 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2214 Mod_BuildBaseBonePoses();
2215 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);
2216 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);
2217 if (loadmodel->surfmesh.data_neighbor3i)
2218 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2219 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2220 if(mod_alias_force_animated.string[0])
2221 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2223 // Always make a BIH for the first frame, we can use it where possible.
2224 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2225 if (!loadmodel->surfmesh.isanimated)
2227 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2228 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2229 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2230 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2231 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2234 // because shaders can do somewhat unexpected things, check for unusual features now
2235 for (i = 0;i < loadmodel->num_textures;i++)
2237 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2238 mod->DrawSky = R_Q1BSP_DrawSky;
2239 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2240 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2244 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2246 dpmheader_t *pheader;
2250 unsigned char *pbase;
2251 int i, j, k, meshvertices, meshtriangles;
2252 skinfile_t *skinfiles;
2253 unsigned char *data;
2255 float biggestorigin, tempvec[3], modelscale;
2259 pheader = (dpmheader_t *)buffer;
2260 pbase = (unsigned char *)buffer;
2261 if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2262 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2263 if (BigLong(pheader->type) != 2)
2264 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2266 loadmodel->modeldatatypestring = "DPM";
2268 loadmodel->type = mod_alias;
2269 loadmodel->synctype = ST_RAND;
2272 pheader->type = BigLong(pheader->type);
2273 pheader->filesize = BigLong(pheader->filesize);
2274 pheader->mins[0] = BigFloat(pheader->mins[0]);
2275 pheader->mins[1] = BigFloat(pheader->mins[1]);
2276 pheader->mins[2] = BigFloat(pheader->mins[2]);
2277 pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2278 pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2279 pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2280 pheader->yawradius = BigFloat(pheader->yawradius);
2281 pheader->allradius = BigFloat(pheader->allradius);
2282 pheader->num_bones = BigLong(pheader->num_bones);
2283 pheader->num_meshs = BigLong(pheader->num_meshs);
2284 pheader->num_frames = BigLong(pheader->num_frames);
2285 pheader->ofs_bones = BigLong(pheader->ofs_bones);
2286 pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2287 pheader->ofs_frames = BigLong(pheader->ofs_frames);
2289 if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2291 Con_Printf("%s has no geometry\n", loadmodel->name);
2294 if (pheader->num_frames < 1)
2296 Con_Printf("%s has no frames\n", loadmodel->name);
2300 loadmodel->DrawSky = NULL;
2301 loadmodel->DrawAddWaterPlanes = NULL;
2302 loadmodel->Draw = R_Q1BSP_Draw;
2303 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2304 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2305 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2306 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2307 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2308 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2309 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2310 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2311 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2312 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2313 loadmodel->PointSuperContents = NULL;
2314 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2317 // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2318 for (i = 0;i < 3;i++)
2320 loadmodel->normalmins[i] = pheader->mins[i];
2321 loadmodel->normalmaxs[i] = pheader->maxs[i];
2322 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2323 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2324 loadmodel->rotatedmins[i] = -pheader->allradius;
2325 loadmodel->rotatedmaxs[i] = pheader->allradius;
2327 loadmodel->radius = pheader->allradius;
2328 loadmodel->radius2 = pheader->allradius * pheader->allradius;
2330 // load external .skin files if present
2331 skinfiles = Mod_LoadSkinFiles();
2332 if (loadmodel->numskins < 1)
2333 loadmodel->numskins = 1;
2338 // gather combined statistics from the meshes
2339 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2340 for (i = 0;i < (int)pheader->num_meshs;i++)
2342 int numverts = BigLong(dpmmesh->num_verts);
2343 meshvertices += numverts;
2344 meshtriangles += BigLong(dpmmesh->num_tris);
2348 loadmodel->numframes = pheader->num_frames;
2349 loadmodel->num_bones = pheader->num_bones;
2350 loadmodel->num_poses = loadmodel->numframes;
2351 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2352 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2353 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2354 // do most allocations as one merged chunk
2355 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) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[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));
2356 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2357 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2358 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2359 loadmodel->surfmesh.num_vertices = meshvertices;
2360 loadmodel->surfmesh.num_triangles = meshtriangles;
2361 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2362 if (r_enableshadowvolumes.integer)
2364 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2366 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2367 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2368 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2369 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2370 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2371 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2372 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2373 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2374 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2375 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2376 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2377 loadmodel->surfmesh.num_blends = 0;
2378 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2379 if (meshvertices <= 65536)
2381 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2383 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2384 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2386 for (i = 0;i < loadmodel->numskins;i++)
2388 loadmodel->skinscenes[i].firstframe = i;
2389 loadmodel->skinscenes[i].framecount = 1;
2390 loadmodel->skinscenes[i].loop = true;
2391 loadmodel->skinscenes[i].framerate = 10;
2394 // load the bone info
2395 bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2396 for (i = 0;i < loadmodel->num_bones;i++)
2398 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2399 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2400 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2401 if (loadmodel->data_bones[i].parent >= i)
2402 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2406 frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2407 // figure out scale of model from root bone, for compatibility with old dpmodel versions
2408 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2409 tempvec[0] = BigFloat(poses[0]);
2410 tempvec[1] = BigFloat(poses[1]);
2411 tempvec[2] = BigFloat(poses[2]);
2412 modelscale = VectorLength(tempvec);
2414 for (i = 0;i < loadmodel->numframes;i++)
2416 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2417 loadmodel->animscenes[i].firstframe = i;
2418 loadmodel->animscenes[i].framecount = 1;
2419 loadmodel->animscenes[i].loop = true;
2420 loadmodel->animscenes[i].framerate = 10;
2421 // load the bone poses for this frame
2422 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2423 for (j = 0;j < loadmodel->num_bones*12;j++)
2425 f = fabs(BigFloat(poses[j]));
2426 biggestorigin = max(biggestorigin, f);
2428 // stuff not processed here: mins, maxs, yawradius, allradius
2430 loadmodel->num_posescale = biggestorigin / 32767.0f;
2431 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2432 for (i = 0;i < loadmodel->numframes;i++)
2434 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2435 for (j = 0;j < loadmodel->num_bones;j++)
2438 matrix4x4_t posematrix;
2439 for (k = 0;k < 12;k++)
2440 pose[k] = BigFloat(frameposes[j*12+k]);
2441 // scale child bones to match the root scale
2442 if (loadmodel->data_bones[j].parent >= 0)
2444 pose[3] *= modelscale;
2445 pose[7] *= modelscale;
2446 pose[11] *= modelscale;
2448 // normalize rotation matrix
2449 VectorNormalize(pose + 0);
2450 VectorNormalize(pose + 4);
2451 VectorNormalize(pose + 8);
2452 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2453 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2457 // load the meshes now
2458 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2461 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2462 // (converting from weight-blending skeletal animation to
2463 // deformation-based skeletal animation)
2464 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2465 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2466 for (i = 0;i < loadmodel->num_bones;i++)
2469 for (k = 0;k < 12;k++)
2470 m[k] = BigFloat(poses[i*12+k]);
2471 if (loadmodel->data_bones[i].parent >= 0)
2472 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2474 for (k = 0;k < 12;k++)
2475 bonepose[12*i+k] = m[k];
2477 for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2479 const int *inelements;
2481 const float *intexcoord;
2482 msurface_t *surface;
2484 loadmodel->sortedmodelsurfaces[i] = i;
2485 surface = loadmodel->data_surfaces + i;
2486 surface->texture = loadmodel->data_textures + i;
2487 surface->num_firsttriangle = meshtriangles;
2488 surface->num_triangles = BigLong(dpmmesh->num_tris);
2489 surface->num_firstvertex = meshvertices;
2490 surface->num_vertices = BigLong(dpmmesh->num_verts);
2491 meshvertices += surface->num_vertices;
2492 meshtriangles += surface->num_triangles;
2494 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2495 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2496 for (j = 0;j < surface->num_triangles;j++)
2498 // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2499 outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2500 outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2501 outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2506 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2507 for (j = 0;j < surface->num_vertices*2;j++)
2508 loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2510 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2511 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2513 int weightindex[4] = { 0, 0, 0, 0 };
2514 float weightinfluence[4] = { 0, 0, 0, 0 };
2516 int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2517 data += sizeof(dpmvertex_t);
2518 for (k = 0;k < numweights;k++)
2520 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2521 int boneindex = BigLong(vert->bonenum);
2522 const float *m = bonepose + 12 * boneindex;
2523 float influence = BigFloat(vert->influence);
2524 float relativeorigin[3], relativenormal[3];
2525 relativeorigin[0] = BigFloat(vert->origin[0]);
2526 relativeorigin[1] = BigFloat(vert->origin[1]);
2527 relativeorigin[2] = BigFloat(vert->origin[2]);
2528 relativenormal[0] = BigFloat(vert->normal[0]);
2529 relativenormal[1] = BigFloat(vert->normal[1]);
2530 relativenormal[2] = BigFloat(vert->normal[2]);
2531 // blend the vertex bone weights into the base mesh
2532 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2533 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2534 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2535 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2536 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2537 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2540 // store the first (and often only) weight
2541 weightinfluence[0] = influence;
2542 weightindex[0] = boneindex;
2546 // sort the new weight into this vertex's weight table
2547 // (which only accepts up to 4 bones per vertex)
2548 for (l = 0;l < 4;l++)
2550 if (weightinfluence[l] < influence)
2552 // move weaker influence weights out of the way first
2554 for (l2 = 3;l2 > l;l2--)
2556 weightinfluence[l2] = weightinfluence[l2-1];
2557 weightindex[l2] = weightindex[l2-1];
2559 // store the new weight
2560 weightinfluence[l] = influence;
2561 weightindex[l] = boneindex;
2566 data += sizeof(dpmbonevert_t);
2568 loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2569 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = weightindex[0];
2570 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2571 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2572 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2573 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
2574 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2575 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2576 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2579 // since dpm models do not have named sections, reuse their shader name as the section name
2580 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2582 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2584 if (loadmodel->surfmesh.num_blends < meshvertices)
2585 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2587 Mod_FreeSkinFiles(skinfiles);
2588 Mod_MakeSortedSurfaces(loadmodel);
2590 // compute all the mesh information that was not loaded from the file
2591 if (loadmodel->surfmesh.data_element3s)
2592 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2593 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2594 Mod_BuildBaseBonePoses();
2595 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);
2596 if (loadmodel->surfmesh.data_neighbor3i)
2597 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2598 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2599 if(mod_alias_force_animated.string[0])
2600 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2602 // Always make a BIH for the first frame, we can use it where possible.
2603 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2604 if (!loadmodel->surfmesh.isanimated)
2606 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2607 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2608 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2609 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2610 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2613 // because shaders can do somewhat unexpected things, check for unusual features now
2614 for (i = 0;i < loadmodel->num_textures;i++)
2616 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2617 mod->DrawSky = R_Q1BSP_DrawSky;
2618 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2619 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2623 // no idea why PSK/PSA files contain weird quaternions but they do...
2624 #define PSKQUATNEGATIONS
2625 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2627 int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2628 int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2629 fs_offset_t filesize;
2634 pskboneinfo_t *bones;
2635 pskrawweights_t *rawweights;
2636 //pskboneinfo_t *animbones;
2637 pskaniminfo_t *anims;
2638 pskanimkeys_t *animkeys;
2639 void *animfilebuffer, *animbuffer, *animbufferend;
2640 unsigned char *data;
2642 skinfile_t *skinfiles;
2643 char animname[MAX_QPATH];
2645 float biggestorigin;
2647 pchunk = (pskchunk_t *)buffer;
2648 if (strcmp(pchunk->id, "ACTRHEAD"))
2649 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2651 loadmodel->modeldatatypestring = "PSK";
2653 loadmodel->type = mod_alias;
2654 loadmodel->DrawSky = NULL;
2655 loadmodel->DrawAddWaterPlanes = NULL;
2656 loadmodel->Draw = R_Q1BSP_Draw;
2657 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2658 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2659 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2660 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2661 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2662 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2663 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2664 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2665 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2666 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2667 loadmodel->PointSuperContents = NULL;
2668 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2669 loadmodel->synctype = ST_RAND;
2671 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2672 strlcat(animname, ".psa", sizeof(animname));
2673 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2674 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2676 animbufferend = animbuffer;
2695 while (buffer < bufferend)
2697 pchunk = (pskchunk_t *)buffer;
2698 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2699 version = LittleLong(pchunk->version);
2700 recordsize = LittleLong(pchunk->recordsize);
2701 numrecords = LittleLong(pchunk->numrecords);
2702 if (developer_extra.integer)
2703 Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2704 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2705 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);
2706 if (!strcmp(pchunk->id, "ACTRHEAD"))
2710 else if (!strcmp(pchunk->id, "PNTS0000"))
2713 if (recordsize != sizeof(*p))
2714 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2715 // byteswap in place and keep the pointer
2716 numpnts = numrecords;
2717 pnts = (pskpnts_t *)buffer;
2718 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2720 p->origin[0] = LittleFloat(p->origin[0]);
2721 p->origin[1] = LittleFloat(p->origin[1]);
2722 p->origin[2] = LittleFloat(p->origin[2]);
2726 else if (!strcmp(pchunk->id, "VTXW0000"))
2729 if (recordsize != sizeof(*p))
2730 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2731 // byteswap in place and keep the pointer
2732 numvtxw = numrecords;
2733 vtxw = (pskvtxw_t *)buffer;
2734 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2736 p->pntsindex = LittleShort(p->pntsindex);
2737 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2738 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2739 if (p->pntsindex >= numpnts)
2741 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2747 else if (!strcmp(pchunk->id, "FACE0000"))
2750 if (recordsize != sizeof(*p))
2751 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2752 // byteswap in place and keep the pointer
2753 numfaces = numrecords;
2754 faces = (pskface_t *)buffer;
2755 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2757 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2758 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2759 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2760 p->group = LittleLong(p->group);
2761 if (p->vtxwindex[0] >= numvtxw)
2763 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2764 p->vtxwindex[0] = 0;
2766 if (p->vtxwindex[1] >= numvtxw)
2768 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2769 p->vtxwindex[1] = 0;
2771 if (p->vtxwindex[2] >= numvtxw)
2773 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2774 p->vtxwindex[2] = 0;
2779 else if (!strcmp(pchunk->id, "MATT0000"))
2782 if (recordsize != sizeof(*p))
2783 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2784 // byteswap in place and keep the pointer
2785 nummatts = numrecords;
2786 matts = (pskmatt_t *)buffer;
2787 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2793 else if (!strcmp(pchunk->id, "REFSKELT"))
2796 if (recordsize != sizeof(*p))
2797 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2798 // byteswap in place and keep the pointer
2799 numbones = numrecords;
2800 bones = (pskboneinfo_t *)buffer;
2801 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2803 p->numchildren = LittleLong(p->numchildren);
2804 p->parent = LittleLong(p->parent);
2805 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2806 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2807 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2808 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2809 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2810 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2811 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2812 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2813 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2814 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2815 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2816 #ifdef PSKQUATNEGATIONS
2819 p->basepose.quat[0] *= -1;
2820 p->basepose.quat[1] *= -1;
2821 p->basepose.quat[2] *= -1;
2825 p->basepose.quat[0] *= 1;
2826 p->basepose.quat[1] *= -1;
2827 p->basepose.quat[2] *= 1;
2830 if (p->parent < 0 || p->parent >= numbones)
2832 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2838 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2841 if (recordsize != sizeof(*p))
2842 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2843 // byteswap in place and keep the pointer
2844 numrawweights = numrecords;
2845 rawweights = (pskrawweights_t *)buffer;
2846 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2848 p->weight = LittleFloat(p->weight);
2849 p->pntsindex = LittleLong(p->pntsindex);
2850 p->boneindex = LittleLong(p->boneindex);
2851 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2853 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2856 if (p->boneindex < 0 || p->boneindex >= numbones)
2858 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2866 while (animbuffer < animbufferend)
2868 pchunk = (pskchunk_t *)animbuffer;
2869 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2870 version = LittleLong(pchunk->version);
2871 recordsize = LittleLong(pchunk->recordsize);
2872 numrecords = LittleLong(pchunk->numrecords);
2873 if (developer_extra.integer)
2874 Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2875 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2876 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);
2877 if (!strcmp(pchunk->id, "ANIMHEAD"))
2881 else if (!strcmp(pchunk->id, "BONENAMES"))
2884 if (recordsize != sizeof(*p))
2885 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2886 // byteswap in place and keep the pointer
2887 numanimbones = numrecords;
2888 //animbones = (pskboneinfo_t *)animbuffer;
2889 // NOTE: supposedly psa does not need to match the psk model, the
2890 // bones missing from the psa would simply use their base
2891 // positions from the psk, but this is hard for me to implement
2892 // and people can easily make animations that match.
2893 if (numanimbones != numbones)
2894 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2895 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2897 p->numchildren = LittleLong(p->numchildren);
2898 p->parent = LittleLong(p->parent);
2899 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2900 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2901 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2902 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2903 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2904 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2905 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2906 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2907 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2908 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2909 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2910 #ifdef PSKQUATNEGATIONS
2913 p->basepose.quat[0] *= -1;
2914 p->basepose.quat[1] *= -1;
2915 p->basepose.quat[2] *= -1;
2919 p->basepose.quat[0] *= 1;
2920 p->basepose.quat[1] *= -1;
2921 p->basepose.quat[2] *= 1;
2924 if (p->parent < 0 || p->parent >= numanimbones)
2926 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2929 // check that bones are the same as in the base
2930 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2931 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2935 else if (!strcmp(pchunk->id, "ANIMINFO"))
2938 if (recordsize != sizeof(*p))
2939 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2940 // byteswap in place and keep the pointer
2941 numanims = numrecords;
2942 anims = (pskaniminfo_t *)animbuffer;
2943 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2945 p->numbones = LittleLong(p->numbones);
2946 p->playtime = LittleFloat(p->playtime);
2947 p->fps = LittleFloat(p->fps);
2948 p->firstframe = LittleLong(p->firstframe);
2949 p->numframes = LittleLong(p->numframes);
2950 if (p->numbones != numbones)
2951 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2955 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2958 if (recordsize != sizeof(*p))
2959 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2960 numanimkeys = numrecords;
2961 animkeys = (pskanimkeys_t *)animbuffer;
2962 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2964 p->origin[0] = LittleFloat(p->origin[0]);
2965 p->origin[1] = LittleFloat(p->origin[1]);
2966 p->origin[2] = LittleFloat(p->origin[2]);
2967 p->quat[0] = LittleFloat(p->quat[0]);
2968 p->quat[1] = LittleFloat(p->quat[1]);
2969 p->quat[2] = LittleFloat(p->quat[2]);
2970 p->quat[3] = LittleFloat(p->quat[3]);
2971 p->frametime = LittleFloat(p->frametime);
2972 #ifdef PSKQUATNEGATIONS
2973 if (index % numbones)
2988 // TODO: allocate bonepose stuff
2991 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2994 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2995 Host_Error("%s: missing required chunks", loadmodel->name);
2999 loadmodel->numframes = 0;
3000 for (index = 0;index < numanims;index++)
3001 loadmodel->numframes += anims[index].numframes;
3002 if (numanimkeys != numbones * loadmodel->numframes)
3003 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
3006 loadmodel->numframes = loadmodel->num_poses = 1;
3008 meshvertices = numvtxw;
3009 meshtriangles = numfaces;
3011 // load external .skin files if present
3012 skinfiles = Mod_LoadSkinFiles();
3013 if (loadmodel->numskins < 1)
3014 loadmodel->numskins = 1;
3015 loadmodel->num_bones = numbones;
3016 loadmodel->num_poses = loadmodel->numframes;
3017 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
3018 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3019 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3020 loadmodel->surfmesh.num_vertices = meshvertices;
3021 loadmodel->surfmesh.num_triangles = meshtriangles;
3022 // do most allocations as one merged chunk
3023 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]) + (r_enableshadowvolumes.integer ? loadmodel->surfmesh.num_triangles * sizeof(int[3]) : 0) + 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);
3024 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
3025 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3026 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3027 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3028 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3029 if (r_enableshadowvolumes.integer)
3031 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3033 loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3034 loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3035 loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3036 loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3037 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3038 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3039 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3040 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3041 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3042 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3043 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3044 loadmodel->surfmesh.num_blends = 0;
3045 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3046 if (loadmodel->surfmesh.num_vertices <= 65536)
3048 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
3050 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3051 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
3053 for (i = 0;i < loadmodel->numskins;i++)
3055 loadmodel->skinscenes[i].firstframe = i;
3056 loadmodel->skinscenes[i].framecount = 1;
3057 loadmodel->skinscenes[i].loop = true;
3058 loadmodel->skinscenes[i].framerate = 10;
3062 for (index = 0, i = 0;index < nummatts;index++)
3064 // since psk models do not have named sections, reuse their shader name as the section name
3065 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
3066 loadmodel->sortedmodelsurfaces[index] = index;
3067 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
3068 loadmodel->data_surfaces[index].num_firstvertex = 0;
3069 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
3072 // copy over the vertex locations and texcoords
3073 for (index = 0;index < numvtxw;index++)
3075 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
3076 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
3077 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
3078 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
3079 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
3082 // loading the faces is complicated because we need to sort them into surfaces by mattindex
3083 for (index = 0;index < numfaces;index++)
3084 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
3085 for (index = 0, i = 0;index < nummatts;index++)
3087 loadmodel->data_surfaces[index].num_firsttriangle = i;
3088 i += loadmodel->data_surfaces[index].num_triangles;
3089 loadmodel->data_surfaces[index].num_triangles = 0;
3091 for (index = 0;index < numfaces;index++)
3093 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3094 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3095 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3096 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3099 // copy over the bones
3100 for (index = 0;index < numbones;index++)
3102 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3103 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3104 if (loadmodel->data_bones[index].parent >= index)
3105 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3108 // convert the basepose data
3109 if (loadmodel->num_bones)
3112 matrix4x4_t *basebonepose;
3113 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3114 matrix4x4_t bonematrix;
3115 matrix4x4_t tempbonematrix;
3116 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3117 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3119 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]);
3120 if (loadmodel->data_bones[boneindex].parent >= 0)
3122 tempbonematrix = bonematrix;
3123 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3125 basebonepose[boneindex] = bonematrix;
3126 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3127 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3129 Mem_Free(basebonepose);
3132 // sort the psk point weights into the vertex weight tables
3133 // (which only accept up to 4 bones per vertex)
3134 for (index = 0;index < numvtxw;index++)
3136 int weightindex[4] = { 0, 0, 0, 0 };
3137 float weightinfluence[4] = { 0, 0, 0, 0 };
3139 for (j = 0;j < numrawweights;j++)
3141 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3143 int boneindex = rawweights[j].boneindex;
3144 float influence = rawweights[j].weight;
3145 for (l = 0;l < 4;l++)
3147 if (weightinfluence[l] < influence)
3149 // move lower influence weights out of the way first
3151 for (l2 = 3;l2 > l;l2--)
3153 weightinfluence[l2] = weightinfluence[l2-1];
3154 weightindex[l2] = weightindex[l2-1];
3156 // store the new weight
3157 weightinfluence[l] = influence;
3158 weightindex[l] = boneindex;
3164 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3165 loadmodel->surfmesh.data_skeletalindex4ub[index*4 ] = weightindex[0];
3166 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3167 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3168 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3169 loadmodel->surfmesh.data_skeletalweight4ub[index*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
3170 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3171 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3172 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3174 if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3175 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3177 // set up the animscenes based on the anims
3180 for (index = 0, i = 0;index < numanims;index++)
3182 for (j = 0;j < anims[index].numframes;j++, i++)
3184 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3185 loadmodel->animscenes[i].firstframe = i;
3186 loadmodel->animscenes[i].framecount = 1;
3187 loadmodel->animscenes[i].loop = true;
3188 loadmodel->animscenes[i].framerate = anims[index].fps;
3191 // calculate the scaling value for bone origins so they can be compressed to short
3193 for (index = 0;index < numanimkeys;index++)
3195 pskanimkeys_t *k = animkeys + index;
3196 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3197 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3198 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3200 loadmodel->num_posescale = biggestorigin / 32767.0f;
3201 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3203 // load the poses from the animkeys
3204 for (index = 0;index < numanimkeys;index++)
3206 pskanimkeys_t *k = animkeys + index;
3208 Vector4Copy(k->quat, quat);
3210 Vector4Negate(quat, quat);
3211 Vector4Normalize2(quat, quat);
3212 // compress poses to the short[7] format for longterm storage
3213 loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3214 loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3215 loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3216 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3217 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3218 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3219 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3224 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3225 loadmodel->animscenes[0].firstframe = 0;
3226 loadmodel->animscenes[0].framecount = 1;
3227 loadmodel->animscenes[0].loop = true;
3228 loadmodel->animscenes[0].framerate = 10;
3230 // calculate the scaling value for bone origins so they can be compressed to short
3232 for (index = 0;index < numbones;index++)
3234 pskboneinfo_t *p = bones + index;
3235 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3236 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3237 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3239 loadmodel->num_posescale = biggestorigin / 32767.0f;
3240 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3242 // load the basepose as a frame
3243 for (index = 0;index < numbones;index++)
3245 pskboneinfo_t *p = bones + index;
3247 Vector4Copy(p->basepose.quat, quat);
3249 Vector4Negate(quat, quat);
3250 Vector4Normalize2(quat, quat);
3251 // compress poses to the short[7] format for longterm storage
3252 loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3253 loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3254 loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3255 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3256 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3257 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3258 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3262 Mod_FreeSkinFiles(skinfiles);
3264 Mem_Free(animfilebuffer);
3265 Mod_MakeSortedSurfaces(loadmodel);
3267 // compute all the mesh information that was not loaded from the file
3268 // TODO: honor smoothing groups somehow?
3269 if (loadmodel->surfmesh.data_element3s)
3270 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3271 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3272 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3273 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);
3274 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);
3275 if (loadmodel->surfmesh.data_neighbor3i)
3276 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
3277 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3278 if(mod_alias_force_animated.string[0])
3279 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3281 // Always make a BIH for the first frame, we can use it where possible.
3282 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3283 if (!loadmodel->surfmesh.isanimated)
3285 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3286 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3287 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3288 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3289 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3292 // because shaders can do somewhat unexpected things, check for unusual features now
3293 for (i = 0;i < loadmodel->num_textures;i++)
3295 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3296 mod->DrawSky = R_Q1BSP_DrawSky;
3297 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3298 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3302 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
3304 unsigned char *data;
3306 const unsigned char *pbase, *pend;
3308 skinfile_t *skinfiles;
3309 int i, j, k, meshvertices, meshtriangles;
3310 float biggestorigin;
3311 const unsigned int *inelements;
3313 const int *inneighbors;
3315 float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3316 // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3317 const float *vnormal = NULL;
3318 const float *vposition = NULL;
3319 const float *vtangent = NULL;
3320 const float *vtexcoord = NULL;
3321 const float *vcolor4f = NULL;
3322 const unsigned char *vblendindexes = NULL;
3323 const unsigned char *vblendweights = NULL;
3324 const unsigned char *vcolor4ub = NULL;
3325 const unsigned short *framedata = NULL;
3326 // temporary memory allocations (because the data in the file may be misaligned)
3327 iqmanim_t *anims = NULL;
3328 iqmbounds_t *bounds = NULL;
3329 iqmjoint1_t *joint1 = NULL;
3330 iqmjoint_t *joint = NULL;
3331 iqmmesh_t *meshes = NULL;
3332 iqmpose1_t *pose1 = NULL;
3333 iqmpose_t *pose = NULL;
3334 iqmvertexarray_t *vas = NULL;
3336 pbase = (unsigned char *)buffer;
3337 pend = (unsigned char *)bufferend;
3339 if (pbase + sizeof(iqmheader_t) > pend)
3340 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3342 // copy struct (otherwise it may be misaligned)
3343 // LordHavoc: okay it's definitely not misaligned here, but for consistency...
3344 memcpy(&header, pbase, sizeof(iqmheader_t));
3346 if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3347 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3348 if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3349 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3351 loadmodel->modeldatatypestring = "IQM";
3353 loadmodel->type = mod_alias;
3354 loadmodel->synctype = ST_RAND;
3357 header.version = LittleLong(header.version);
3358 header.filesize = LittleLong(header.filesize);
3359 header.flags = LittleLong(header.flags);
3360 header.num_text = LittleLong(header.num_text);
3361 header.ofs_text = LittleLong(header.ofs_text);
3362 header.num_meshes = LittleLong(header.num_meshes);
3363 header.ofs_meshes = LittleLong(header.ofs_meshes);
3364 header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3365 header.num_vertexes = LittleLong(header.num_vertexes);
3366 header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3367 header.num_triangles = LittleLong(header.num_triangles);
3368 header.ofs_triangles = LittleLong(header.ofs_triangles);
3369 header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3370 header.num_joints = LittleLong(header.num_joints);
3371 header.ofs_joints = LittleLong(header.ofs_joints);
3372 header.num_poses = LittleLong(header.num_poses);
3373 header.ofs_poses = LittleLong(header.ofs_poses);
3374 header.num_anims = LittleLong(header.num_anims);
3375 header.ofs_anims = LittleLong(header.ofs_anims);
3376 header.num_frames = LittleLong(header.num_frames);
3377 header.num_framechannels = LittleLong(header.num_framechannels);
3378 header.ofs_frames = LittleLong(header.ofs_frames);
3379 header.ofs_bounds = LittleLong(header.ofs_bounds);
3380 header.num_comment = LittleLong(header.num_comment);
3381 header.ofs_comment = LittleLong(header.ofs_comment);
3382 header.num_extensions = LittleLong(header.num_extensions);
3383 header.ofs_extensions = LittleLong(header.ofs_extensions);
3385 if (header.version == 1)
3387 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3388 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3390 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3396 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3397 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3399 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3403 if (pbase + header.ofs_text + header.num_text > pend ||
3404 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3405 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3406 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3407 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3408 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3409 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3410 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3411 pbase + header.ofs_comment + header.num_comment > pend)
3413 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3417 // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3418 if (header.num_vertexarrays)
3419 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3420 if (header.num_anims)
3421 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3422 if (header.ofs_bounds)
3423 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3424 if (header.num_meshes)
3425 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3427 for (i = 0;i < (int)header.num_vertexarrays;i++)
3429 iqmvertexarray_t va;
3431 va.type = LittleLong(vas[i].type);
3432 va.flags = LittleLong(vas[i].flags);
3433 va.format = LittleLong(vas[i].format);
3434 va.size = LittleLong(vas[i].size);
3435 va.offset = LittleLong(vas[i].offset);
3436 vsize = header.num_vertexes*va.size;
3439 case IQM_FLOAT: vsize *= sizeof(float); break;
3440 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3443 if (pbase + va.offset + vsize > pend)
3445 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3449 if (va.format == IQM_FLOAT && va.size == 3)
3450 vposition = (const float *)(pbase + va.offset);
3453 if (va.format == IQM_FLOAT && va.size == 2)
3454 vtexcoord = (const float *)(pbase + va.offset);
3457 if (va.format == IQM_FLOAT && va.size == 3)
3458 vnormal = (const float *)(pbase + va.offset);
3461 if (va.format == IQM_FLOAT && va.size == 4)
3462 vtangent = (const float *)(pbase + va.offset);
3464 case IQM_BLENDINDEXES:
3465 if (va.format == IQM_UBYTE && va.size == 4)
3466 vblendindexes = (const unsigned char *)(pbase + va.offset);
3468 case IQM_BLENDWEIGHTS:
3469 if (va.format == IQM_UBYTE && va.size == 4)
3470 vblendweights = (const unsigned char *)(pbase + va.offset);
3473 if (va.format == IQM_FLOAT && va.size == 4)
3474 vcolor4f = (const float *)(pbase + va.offset);
3475 if (va.format == IQM_UBYTE && va.size == 4)
3476 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3480 if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3482 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3486 text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3488 loadmodel->DrawSky = NULL;
3489 loadmodel->DrawAddWaterPlanes = NULL;
3490 loadmodel->Draw = R_Q1BSP_Draw;
3491 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
3492 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
3493 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
3494 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
3495 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
3496 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
3497 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
3498 loadmodel->DrawLight = R_Q1BSP_DrawLight;
3499 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3500 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3501 loadmodel->PointSuperContents = NULL;
3502 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3504 // load external .skin files if present
3505 skinfiles = Mod_LoadSkinFiles();
3506 if (loadmodel->numskins < 1)
3507 loadmodel->numskins = 1;
3509 loadmodel->numframes = max(header.num_anims, 1);
3510 loadmodel->num_bones = header.num_joints;
3511 loadmodel->num_poses = max(header.num_frames, 1);
3512 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
3513 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3514 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3516 meshvertices = header.num_vertexes;
3517 meshtriangles = header.num_triangles;
3519 // do most allocations as one merged chunk
3520 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) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[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));
3521 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3522 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3523 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3524 loadmodel->surfmesh.num_vertices = meshvertices;
3525 loadmodel->surfmesh.num_triangles = meshtriangles;
3526 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3527 if (r_enableshadowvolumes.integer)
3529 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3531 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3532 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3533 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3534 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3535 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3536 if (vcolor4f || vcolor4ub)
3538 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3540 if (vblendindexes && vblendweights)
3542 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3543 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3545 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3546 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3547 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3548 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3549 if (vblendindexes && vblendweights)
3551 loadmodel->surfmesh.num_blends = 0;
3552 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3554 if (meshvertices <= 65536)
3556 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3558 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3559 if (vblendindexes && vblendweights)
3560 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3562 for (i = 0;i < loadmodel->numskins;i++)
3564 loadmodel->skinscenes[i].firstframe = i;
3565 loadmodel->skinscenes[i].framecount = 1;
3566 loadmodel->skinscenes[i].loop = true;
3567 loadmodel->skinscenes[i].framerate = 10;
3570 // load the bone info
3571 if (header.version == 1)
3573 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3574 if (loadmodel->num_bones)
3575 joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3576 for (i = 0;i < loadmodel->num_bones;i++)
3578 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3579 joint1[i].name = LittleLong(injoint1[i].name);
3580 joint1[i].parent = LittleLong(injoint1[i].parent);
3581 for (j = 0;j < 3;j++)
3583 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3584 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3585 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3587 strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3588 loadmodel->data_bones[i].parent = joint1[i].parent;
3589 if (loadmodel->data_bones[i].parent >= i)
3590 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3591 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]);
3592 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3593 if (loadmodel->data_bones[i].parent >= 0)
3595 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3596 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3597 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3599 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3604 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3605 if (header.num_joints)
3606 joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3607 for (i = 0;i < loadmodel->num_bones;i++)
3609 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3610 joint[i].name = LittleLong(injoint[i].name);
3611 joint[i].parent = LittleLong(injoint[i].parent);
3612 for (j = 0;j < 3;j++)
3614 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3615 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3616 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3618 joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3619 strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3620 loadmodel->data_bones[i].parent = joint[i].parent;
3621 if (loadmodel->data_bones[i].parent >= i)
3622 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3623 if (joint[i].rotation[3] > 0)
3624 Vector4Negate(joint[i].rotation, joint[i].rotation);
3625 Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3626 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]);
3627 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3628 if (loadmodel->data_bones[i].parent >= 0)
3630 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3631 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3632 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3634 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3638 // set up the animscenes based on the anims
3639 for (i = 0;i < (int)header.num_anims;i++)
3642 anim.name = LittleLong(anims[i].name);
3643 anim.first_frame = LittleLong(anims[i].first_frame);
3644 anim.num_frames = LittleLong(anims[i].num_frames);
3645 anim.framerate = LittleFloat(anims[i].framerate);
3646 anim.flags = LittleLong(anims[i].flags);
3647 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3648 loadmodel->animscenes[i].firstframe = anim.first_frame;
3649 loadmodel->animscenes[i].framecount = anim.num_frames;
3650 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3651 loadmodel->animscenes[i].framerate = anim.framerate;
3653 if (header.num_anims <= 0)
3655 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3656 loadmodel->animscenes[0].firstframe = 0;
3657 loadmodel->animscenes[0].framecount = 1;
3658 loadmodel->animscenes[0].loop = true;
3659 loadmodel->animscenes[0].framerate = 10;
3662 loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3663 if(mod_alias_force_animated.string[0])
3664 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3667 if (header.version == 1)
3669 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3670 if (header.num_poses)
3671 pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3672 for (i = 0;i < (int)header.num_poses;i++)
3675 pose1[i].parent = LittleLong(inpose1[i].parent);
3676 pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3677 for (j = 0;j < 9;j++)
3679 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3680 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3682 f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3683 f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3684 f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3685 f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3686 f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3687 f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3689 if (header.num_frames <= 0)
3691 for (i = 0;i < loadmodel->num_bones;i++)
3694 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3695 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3696 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3702 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3703 if (header.num_poses)
3704 pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3705 for (i = 0;i < (int)header.num_poses;i++)
3708 pose[i].parent = LittleLong(inpose[i].parent);
3709 pose[i].channelmask = LittleLong(inpose[i].channelmask);
3710 for (j = 0;j < 10;j++)
3712 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3713 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3715 f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3716 f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3717 f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3718 f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3719 f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3720 f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3722 if (header.num_frames <= 0)
3724 for (i = 0;i < loadmodel->num_bones;i++)
3727 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3728 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3729 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3733 loadmodel->num_posescale = biggestorigin / 32767.0f;
3734 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3736 // load the pose data
3737 // this unaligned memory access is safe (LittleShort reads as bytes)
3738 framedata = (const unsigned short *)(pbase + header.ofs_frames);
3739 if (header.version == 1)
3741 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3743 for (j = 0;j < (int)header.num_poses;j++, k++)
3745 float qx, qy, qz, qw;
3746 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));
3747 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));
3748 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));
3749 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3750 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3751 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3752 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3753 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3754 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3755 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3756 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3757 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3758 // skip scale data for now
3759 if(pose1[j].channelmask&64) framedata++;
3760 if(pose1[j].channelmask&128) framedata++;
3761 if(pose1[j].channelmask&256) framedata++;
3764 if (header.num_frames <= 0)
3766 for (i = 0;i < loadmodel->num_bones;i++)
3768 float qx, qy, qz, qw;
3769 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3770 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3771 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3772 qx = joint1[i].rotation[0];
3773 qy = joint1[i].rotation[1];
3774 qz = joint1[i].rotation[2];
3775 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3776 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3777 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3778 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3779 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3780 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3786 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3788 for (j = 0;j < (int)header.num_poses;j++, k++)
3791 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));
3792 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));
3793 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));
3794 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3795 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3796 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3797 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3799 Vector4Negate(rot, rot);
3800 Vector4Normalize2(rot, rot);
3801 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3802 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3803 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3804 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3805 // skip scale data for now
3806 if(pose[j].channelmask&128) framedata++;
3807 if(pose[j].channelmask&256) framedata++;
3808 if(pose[j].channelmask&512) framedata++;
3811 if (header.num_frames <= 0)
3813 for (i = 0;i < loadmodel->num_bones;i++)
3815 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3816 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3817 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3818 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3819 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3820 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3821 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3826 // load bounding box data
3827 if (header.ofs_bounds)
3829 float xyradius = 0, radius = 0;
3830 VectorClear(loadmodel->normalmins);
3831 VectorClear(loadmodel->normalmaxs);
3832 for (i = 0; i < (int)header.num_frames;i++)
3835 bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3836 bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3837 bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3838 bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);
3839 bound.maxs[1] = LittleFloat(bounds[i].maxs[1]);
3840 bound.maxs[2] = LittleFloat(bounds[i].maxs[2]);
3841 bound.xyradius = LittleFloat(bounds[i].xyradius);
3842 bound.radius = LittleFloat(bounds[i].radius);
3845 VectorCopy(bound.mins, loadmodel->normalmins);
3846 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3850 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3851 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3852 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3853 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3854 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3855 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3857 if (bound.xyradius > xyradius)
3858 xyradius = bound.xyradius;
3859 if (bound.radius > radius)
3860 radius = bound.radius;
3862 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3863 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3864 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3865 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3866 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3867 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3868 loadmodel->radius = radius;
3869 loadmodel->radius2 = radius * radius;
3872 // load triangle data
3873 // this unaligned memory access is safe (LittleLong reads as bytes)
3874 inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3875 outelements = loadmodel->surfmesh.data_element3i;
3876 for (i = 0;i < (int)header.num_triangles;i++)
3878 outelements[0] = LittleLong(inelements[0]);
3879 outelements[1] = LittleLong(inelements[1]);
3880 outelements[2] = LittleLong(inelements[2]);
3884 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3886 if (header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
3888 // this unaligned memory access is safe (LittleLong reads as bytes)
3889 inneighbors = (const int *)(pbase + header.ofs_neighbors);
3890 outneighbors = loadmodel->surfmesh.data_neighbor3i;
3891 for (i = 0;i < (int)header.num_triangles;i++)
3893 outneighbors[0] = LittleLong(inneighbors[0]);
3894 outneighbors[1] = LittleLong(inneighbors[1]);
3895 outneighbors[2] = LittleLong(inneighbors[2]);
3902 // this unaligned memory access is safe (LittleFloat reads as bytes)
3903 outvertex = loadmodel->surfmesh.data_vertex3f;
3904 for (i = 0;i < (int)header.num_vertexes;i++)
3906 outvertex[0] = LittleFloat(vposition[0]);
3907 outvertex[1] = LittleFloat(vposition[1]);
3908 outvertex[2] = LittleFloat(vposition[2]);
3913 outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3914 // this unaligned memory access is safe (LittleFloat reads as bytes)
3915 for (i = 0;i < (int)header.num_vertexes;i++)
3917 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3918 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3923 // this unaligned memory access is safe (LittleFloat reads as bytes)
3926 outnormal = loadmodel->surfmesh.data_normal3f;
3927 for (i = 0;i < (int)header.num_vertexes;i++)
3929 outnormal[0] = LittleFloat(vnormal[0]);
3930 outnormal[1] = LittleFloat(vnormal[1]);
3931 outnormal[2] = LittleFloat(vnormal[2]);
3937 // this unaligned memory access is safe (LittleFloat reads as bytes)
3938 if(vnormal && vtangent)
3940 outnormal = loadmodel->surfmesh.data_normal3f;
3941 outsvector = loadmodel->surfmesh.data_svector3f;
3942 outtvector = loadmodel->surfmesh.data_tvector3f;
3943 for (i = 0;i < (int)header.num_vertexes;i++)
3945 outsvector[0] = LittleFloat(vtangent[0]);
3946 outsvector[1] = LittleFloat(vtangent[1]);
3947 outsvector[2] = LittleFloat(vtangent[2]);
3948 if(LittleFloat(vtangent[3]) < 0)
3949 CrossProduct(outsvector, outnormal, outtvector);
3951 CrossProduct(outnormal, outsvector, outtvector);
3959 // this unaligned memory access is safe (all bytes)
3960 if (vblendindexes && vblendweights)
3962 for (i = 0; i < (int)header.num_vertexes;i++)
3964 blendweights_t weights;
3965 memcpy(weights.index, vblendindexes + i*4, 4);
3966 memcpy(weights.influence, vblendweights + i*4, 4);
3967 loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3968 loadmodel->surfmesh.data_skeletalindex4ub[i*4 ] = weights.index[0];
3969 loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3970 loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3971 loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3972 loadmodel->surfmesh.data_skeletalweight4ub[i*4 ] = weights.influence[0];
3973 loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3974 loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3975 loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3981 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3982 // this unaligned memory access is safe (LittleFloat reads as bytes)
3983 for (i = 0;i < (int)header.num_vertexes;i++)
3985 outcolor[0] = LittleFloat(vcolor4f[0]);
3986 outcolor[1] = LittleFloat(vcolor4f[1]);
3987 outcolor[2] = LittleFloat(vcolor4f[2]);
3988 outcolor[3] = LittleFloat(vcolor4f[3]);
3995 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3996 // this unaligned memory access is safe (all bytes)
3997 for (i = 0;i < (int)header.num_vertexes;i++)
3999 outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
4000 outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
4001 outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
4002 outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
4009 for (i = 0;i < (int)header.num_meshes;i++)
4012 msurface_t *surface;
4014 mesh.name = LittleLong(meshes[i].name);
4015 mesh.material = LittleLong(meshes[i].material);
4016 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
4017 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
4018 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
4019 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
4021 loadmodel->sortedmodelsurfaces[i] = i;
4022 surface = loadmodel->data_surfaces + i;
4023 surface->texture = loadmodel->data_textures + i;
4024 surface->num_firsttriangle = mesh.first_triangle;
4025 surface->num_triangles = mesh.num_triangles;
4026 surface->num_firstvertex = mesh.first_vertex;
4027 surface->num_vertices = mesh.num_vertexes;
4029 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
4032 Mod_FreeSkinFiles(skinfiles);
4033 Mod_MakeSortedSurfaces(loadmodel);
4035 // compute all the mesh information that was not loaded from the file
4036 if (loadmodel->surfmesh.data_element3s)
4037 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
4038 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
4040 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);
4041 if (!vnormal || !vtangent)
4042 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);
4043 if (!header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
4044 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
4045 if (!header.ofs_bounds)
4046 Mod_Alias_CalculateBoundingBox();
4048 // Always make a BIH for the first frame, we can use it where possible.
4049 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
4050 if (!loadmodel->surfmesh.isanimated)
4052 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
4053 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
4054 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
4055 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
4056 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
4059 if (joint ) Mem_Free(joint );joint = NULL;
4060 if (joint1 ) Mem_Free(joint1 );joint1 = NULL;
4061 if (pose ) Mem_Free(pose );pose = NULL;
4062 if (pose1 ) Mem_Free(pose1 );pose1 = NULL;
4064 // because shaders can do somewhat unexpected things, check for unusual features now
4065 for (i = 0;i < loadmodel->num_textures;i++)
4067 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
4068 mod->DrawSky = R_Q1BSP_DrawSky;
4069 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
4070 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;