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 pose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i);
98 float lerp = frameblend[0].lerp,
99 tx = pose7s[0], ty = pose7s[1], tz = pose7s[2],
100 rx = pose7s[3] * lerp,
101 ry = pose7s[4] * lerp,
102 rz = pose7s[5] * lerp,
103 rw = pose7s[6] * lerp,
104 dx = tx*rw + ty*rz - tz*ry,
105 dy = -tx*rz + ty*rw + tz*rx,
106 dz = tx*ry - ty*rx + tz*rw,
107 dw = -tx*rx - ty*ry - tz*rz,
108 scale, sx, sy, sz, sw;
109 for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
111 const short * RESTRICT pose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i);
112 float lerp = frameblend[blends].lerp,
113 tx = pose7s[0], ty = pose7s[1], tz = pose7s[2],
114 qx = pose7s[3], qy = pose7s[4], qz = pose7s[5], qw = pose7s[6];
115 if(rx*qx + ry*qy + rz*qz + rw*qw < 0) lerp = -lerp;
124 dx += tx*qw + ty*qz - tz*qy;
125 dy += -tx*qz + ty*qw + tz*qx;
126 dz += tx*qy - ty*qx + tz*qw;
127 dw += -tx*qx - ty*qy - tz*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)
758 float segmentmins[3], segmentmaxs[3];
760 float vertex3fbuf[1024*3];
761 float *vertex3f = vertex3fbuf;
762 memset(trace, 0, sizeof(*trace));
764 trace->hitsupercontentsmask = hitsupercontentsmask;
765 if (model->surfmesh.num_vertices > 1024)
766 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
767 segmentmins[0] = min(start[0], end[0]) - 1;
768 segmentmins[1] = min(start[1], end[1]) - 1;
769 segmentmins[2] = min(start[2], end[2]) - 1;
770 segmentmaxs[0] = max(start[0], end[0]) + 1;
771 segmentmaxs[1] = max(start[1], end[1]) + 1;
772 segmentmaxs[2] = max(start[2], end[2]) + 1;
773 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
774 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
775 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);
776 if (vertex3f != vertex3fbuf)
780 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)
783 vec3_t shiftstart, shiftend;
784 float segmentmins[3], segmentmaxs[3];
786 float vertex3fbuf[1024*3];
787 float *vertex3f = vertex3fbuf;
788 colboxbrushf_t thisbrush_start, thisbrush_end;
789 vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
791 if (VectorCompare(boxmins, boxmaxs))
793 VectorAdd(start, boxmins, shiftstart);
794 VectorAdd(end, boxmins, shiftend);
795 Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask);
796 VectorSubtract(trace->endpos, boxmins, trace->endpos);
800 // box trace, performed as brush trace
801 memset(trace, 0, sizeof(*trace));
803 trace->hitsupercontentsmask = hitsupercontentsmask;
804 if (model->surfmesh.num_vertices > 1024)
805 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
806 segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
807 segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
808 segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
809 segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
810 segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
811 segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
812 VectorAdd(start, boxmins, boxstartmins);
813 VectorAdd(start, boxmaxs, boxstartmaxs);
814 VectorAdd(end, boxmins, boxendmins);
815 VectorAdd(end, boxmaxs, boxendmaxs);
816 Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL);
817 Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL);
818 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
819 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
820 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);
821 if (vertex3f != vertex3fbuf)
825 static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
828 for (i = 0;i < inverts;i++)
830 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
832 j = vertremap[i]; // not onseam
835 j = vertremap[i+inverts]; // onseam
841 static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
843 int i, f, pose, groupframes;
845 daliasframetype_t *pframetype;
846 daliasframe_t *pinframe;
847 daliasgroup_t *group;
848 daliasinterval_t *intervals;
851 scene = loadmodel->animscenes;
852 for (f = 0;f < loadmodel->numframes;f++)
854 pframetype = (daliasframetype_t *)datapointer;
855 datapointer += sizeof(daliasframetype_t);
856 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
858 // a single frame is still treated as a group
865 group = (daliasgroup_t *)datapointer;
866 datapointer += sizeof(daliasgroup_t);
867 groupframes = LittleLong (group->numframes);
869 // intervals (time per frame)
870 intervals = (daliasinterval_t *)datapointer;
871 datapointer += sizeof(daliasinterval_t) * groupframes;
873 interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
874 if (interval < 0.01f)
876 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
881 // get scene name from first frame
882 pinframe = (daliasframe_t *)datapointer;
884 strlcpy(scene->name, pinframe->name, sizeof(scene->name));
885 scene->firstframe = pose;
886 scene->framecount = groupframes;
887 scene->framerate = 1.0f / interval;
892 for (i = 0;i < groupframes;i++)
894 datapointer += sizeof(daliasframe_t);
895 Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
896 datapointer += sizeof(trivertx_t) * inverts;
902 static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *skinframe)
904 if (cls.state == ca_dedicated)
908 skinframe = R_SkinFrame_LoadMissing();
909 memset(texture, 0, sizeof(*texture));
910 texture->currentframe = texture;
911 //texture->animated = false;
912 texture->numskinframes = 1;
913 texture->skinframerate = 1;
914 texture->skinframes[0] = skinframe;
915 texture->currentskinframe = skinframe;
916 //texture->backgroundnumskinframes = 0;
917 //texture->customblendfunc[0] = 0;
918 //texture->customblendfunc[1] = 0;
919 //texture->surfaceflags = 0;
920 //texture->supercontents = 0;
921 //texture->surfaceparms = 0;
922 //texture->textureflags = 0;
924 texture->basematerialflags = MATERIALFLAG_WALL;
925 if (texture->currentskinframe->hasalpha)
926 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
927 texture->currentmaterialflags = texture->basematerialflags;
928 texture->offsetmapping = OFFSETMAPPING_DEFAULT;
929 texture->offsetscale = 1;
930 texture->offsetbias = 0;
931 texture->specularscalemod = 1;
932 texture->specularpowermod = 1;
933 texture->surfaceflags = 0;
934 texture->supercontents = SUPERCONTENTS_SOLID;
935 if (!(texture->basematerialflags & MATERIALFLAG_BLENDED))
936 texture->supercontents |= SUPERCONTENTS_OPAQUE;
937 texture->transparentsort = TRANSPARENTSORT_DISTANCE;
938 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
939 // JUST GREP FOR "specularscalemod = 1".
942 void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
945 char stripbuf[MAX_QPATH];
946 skinfileitem_t *skinfileitem;
947 if(developer_extra.integer)
948 Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername);
951 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
952 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
954 memset(skin, 0, sizeof(*skin));
956 for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
958 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
959 if (!strcmp(skinfileitem->name, meshname))
961 Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
962 if(developer_extra.integer)
963 Con_DPrintf("--> got %s from skin file\n", stripbuf);
964 Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
970 // don't render unmentioned meshes
971 Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
972 if(developer_extra.integer)
973 Con_DPrintf("--> skipping\n");
974 skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
980 if(developer_extra.integer)
981 Con_DPrintf("--> using default\n");
982 Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
983 Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
987 #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);
988 #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);
989 void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
991 int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
992 float scales, scalet, interval;
996 stvert_t *pinstverts;
997 dtriangle_t *pintriangles;
998 daliasskintype_t *pinskintype;
999 daliasskingroup_t *pinskingroup;
1000 daliasskininterval_t *pinskinintervals;
1001 daliasframetype_t *pinframetype;
1002 daliasgroup_t *pinframegroup;
1003 unsigned char *datapointer, *startframes, *startskins;
1004 char name[MAX_QPATH];
1005 skinframe_t *tempskinframe;
1006 animscene_t *tempskinscenes;
1007 texture_t *tempaliasskins;
1009 int *vertonseam, *vertremap;
1010 skinfile_t *skinfiles;
1013 datapointer = (unsigned char *)buffer;
1014 pinmodel = (mdl_t *)datapointer;
1015 datapointer += sizeof(mdl_t);
1017 version = LittleLong (pinmodel->version);
1018 if (version != ALIAS_VERSION)
1019 Host_Error ("%s has wrong version number (%i should be %i)",
1020 loadmodel->name, version, ALIAS_VERSION);
1022 loadmodel->modeldatatypestring = "MDL";
1024 loadmodel->type = mod_alias;
1025 loadmodel->DrawSky = NULL;
1026 loadmodel->DrawAddWaterPlanes = NULL;
1027 loadmodel->Draw = R_Q1BSP_Draw;
1028 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1029 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1030 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1031 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1032 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1033 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1034 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1035 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1036 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1037 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1038 // FIXME add TraceBrush!
1039 loadmodel->PointSuperContents = NULL;
1040 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1042 loadmodel->num_surfaces = 1;
1043 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1044 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1045 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1046 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1047 loadmodel->sortedmodelsurfaces[0] = 0;
1049 loadmodel->numskins = LittleLong(pinmodel->numskins);
1050 BOUNDI(loadmodel->numskins,0,65536);
1051 skinwidth = LittleLong (pinmodel->skinwidth);
1052 BOUNDI(skinwidth,0,65536);
1053 skinheight = LittleLong (pinmodel->skinheight);
1054 BOUNDI(skinheight,0,65536);
1055 numverts = LittleLong(pinmodel->numverts);
1056 BOUNDI(numverts,0,65536);
1057 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1058 BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1059 loadmodel->numframes = LittleLong(pinmodel->numframes);
1060 BOUNDI(loadmodel->numframes,0,65536);
1061 loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1062 BOUNDI((int)loadmodel->synctype,0,2);
1063 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1064 i = LittleLong (pinmodel->flags);
1065 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1067 for (i = 0;i < 3;i++)
1069 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1070 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1073 startskins = datapointer;
1075 for (i = 0;i < loadmodel->numskins;i++)
1077 pinskintype = (daliasskintype_t *)datapointer;
1078 datapointer += sizeof(daliasskintype_t);
1079 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1083 pinskingroup = (daliasskingroup_t *)datapointer;
1084 datapointer += sizeof(daliasskingroup_t);
1085 groupskins = LittleLong(pinskingroup->numskins);
1086 datapointer += sizeof(daliasskininterval_t) * groupskins;
1089 for (j = 0;j < groupskins;j++)
1091 datapointer += skinwidth * skinheight;
1096 pinstverts = (stvert_t *)datapointer;
1097 datapointer += sizeof(stvert_t) * numverts;
1099 pintriangles = (dtriangle_t *)datapointer;
1100 datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1102 startframes = datapointer;
1103 loadmodel->surfmesh.num_morphframes = 0;
1104 for (i = 0;i < loadmodel->numframes;i++)
1106 pinframetype = (daliasframetype_t *)datapointer;
1107 datapointer += sizeof(daliasframetype_t);
1108 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1112 pinframegroup = (daliasgroup_t *)datapointer;
1113 datapointer += sizeof(daliasgroup_t);
1114 groupframes = LittleLong(pinframegroup->numframes);
1115 datapointer += sizeof(daliasinterval_t) * groupframes;
1118 for (j = 0;j < groupframes;j++)
1120 datapointer += sizeof(daliasframe_t);
1121 datapointer += sizeof(trivertx_t) * numverts;
1122 loadmodel->surfmesh.num_morphframes++;
1125 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1127 // store texture coordinates into temporary array, they will be stored
1128 // after usage is determined (triangle data)
1129 vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1130 vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1131 vertonseam = vertremap + numverts * 2;
1133 scales = 1.0 / skinwidth;
1134 scalet = 1.0 / skinheight;
1135 for (i = 0;i < numverts;i++)
1137 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1138 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1139 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1140 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1141 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1144 // load triangle data
1145 loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1147 // read the triangle elements
1148 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1149 for (j = 0;j < 3;j++)
1150 loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1151 // validate (note numverts is used because this is the original data)
1152 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1153 // now butcher the elements according to vertonseam and tri->facesfront
1154 // and then compact the vertex set to remove duplicates
1155 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1156 if (!LittleLong(pintriangles[i].facesfront)) // backface
1157 for (j = 0;j < 3;j++)
1158 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1159 loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1161 // (this uses vertremap to count usage to save some memory)
1162 for (i = 0;i < numverts*2;i++)
1164 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1165 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1166 // build remapping table and compact array
1167 loadmodel->surfmesh.num_vertices = 0;
1168 for (i = 0;i < numverts*2;i++)
1172 vertremap[i] = loadmodel->surfmesh.num_vertices;
1173 vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1174 vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1175 loadmodel->surfmesh.num_vertices++;
1178 vertremap[i] = -1; // not used at all
1180 // remap the elements to the new vertex set
1181 for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1182 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1183 // store the texture coordinates
1184 loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1185 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1187 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1188 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1191 // generate ushort elements array if possible
1192 if (loadmodel->surfmesh.num_vertices <= 65536)
1193 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1194 if (loadmodel->surfmesh.data_element3s)
1195 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1196 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1199 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1200 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1201 if (r_enableshadowvolumes.integer)
1203 loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1205 Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1206 if (loadmodel->surfmesh.data_neighbor3i)
1207 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1208 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1209 Mod_Alias_MorphMesh_CompileFrames();
1212 Mem_Free(vertremap);
1215 skinfiles = Mod_LoadSkinFiles();
1218 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1219 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1220 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1221 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1222 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1223 Mod_FreeSkinFiles(skinfiles);
1224 for (i = 0;i < loadmodel->numskins;i++)
1226 loadmodel->skinscenes[i].firstframe = i;
1227 loadmodel->skinscenes[i].framecount = 1;
1228 loadmodel->skinscenes[i].loop = true;
1229 loadmodel->skinscenes[i].framerate = 10;
1234 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1235 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1236 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1237 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1239 datapointer = startskins;
1240 for (i = 0;i < loadmodel->numskins;i++)
1242 pinskintype = (daliasskintype_t *)datapointer;
1243 datapointer += sizeof(daliasskintype_t);
1245 if (pinskintype->type == ALIAS_SKIN_SINGLE)
1252 pinskingroup = (daliasskingroup_t *)datapointer;
1253 datapointer += sizeof(daliasskingroup_t);
1255 groupskins = LittleLong (pinskingroup->numskins);
1257 pinskinintervals = (daliasskininterval_t *)datapointer;
1258 datapointer += sizeof(daliasskininterval_t) * groupskins;
1260 interval = LittleFloat(pinskinintervals[0].interval);
1261 if (interval < 0.01f)
1263 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1268 dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1269 loadmodel->skinscenes[i].firstframe = totalskins;
1270 loadmodel->skinscenes[i].framecount = groupskins;
1271 loadmodel->skinscenes[i].framerate = 1.0f / interval;
1272 loadmodel->skinscenes[i].loop = true;
1274 for (j = 0;j < groupskins;j++)
1277 dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1279 dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1280 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))
1281 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));
1282 datapointer += skinwidth * skinheight;
1286 // check for skins that don't exist in the model, but do exist as external images
1287 // (this was added because yummyluv kept pestering me about support for it)
1288 // TODO: support shaders here?
1289 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)))
1291 // expand the arrays to make room
1292 tempskinscenes = loadmodel->skinscenes;
1293 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1294 memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1295 Mem_Free(tempskinscenes);
1297 tempaliasskins = loadmodel->data_textures;
1298 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1299 memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1300 Mem_Free(tempaliasskins);
1302 // store the info about the new skin
1303 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
1304 strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1305 loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1306 loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1307 loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1308 loadmodel->skinscenes[loadmodel->numskins].loop = true;
1310 //increase skin counts
1311 loadmodel->numskins++;
1314 // fix up the pointers since they are pointing at the old textures array
1315 // FIXME: this is a hack!
1316 for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1317 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1321 surface = loadmodel->data_surfaces;
1322 surface->texture = loadmodel->data_textures;
1323 surface->num_firsttriangle = 0;
1324 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1325 surface->num_firstvertex = 0;
1326 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1328 if(mod_alias_force_animated.string[0])
1329 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1331 if (!loadmodel->surfmesh.isanimated)
1333 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1334 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1335 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1336 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1337 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1338 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1341 // because shaders can do somewhat unexpected things, check for unusual features now
1342 for (i = 0;i < loadmodel->num_textures;i++)
1344 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1345 mod->DrawSky = R_Q1BSP_DrawSky;
1346 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1347 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1351 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1353 int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1354 float iskinwidth, iskinheight;
1355 unsigned char *data;
1356 msurface_t *surface;
1358 unsigned char *base, *datapointer;
1359 md2frame_t *pinframe;
1361 md2triangle_t *intri;
1362 unsigned short *inst;
1363 struct md2verthash_s
1365 struct md2verthash_s *next;
1369 *hash, **md2verthash, *md2verthashdata;
1370 skinfile_t *skinfiles;
1372 pinmodel = (md2_t *)buffer;
1373 base = (unsigned char *)buffer;
1375 version = LittleLong (pinmodel->version);
1376 if (version != MD2ALIAS_VERSION)
1377 Host_Error ("%s has wrong version number (%i should be %i)",
1378 loadmodel->name, version, MD2ALIAS_VERSION);
1380 loadmodel->modeldatatypestring = "MD2";
1382 loadmodel->type = mod_alias;
1383 loadmodel->DrawSky = NULL;
1384 loadmodel->DrawAddWaterPlanes = NULL;
1385 loadmodel->Draw = R_Q1BSP_Draw;
1386 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1387 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1388 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1389 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1390 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1391 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1392 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1393 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1394 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1395 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1396 loadmodel->PointSuperContents = NULL;
1397 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1399 if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1400 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1401 if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1402 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1403 if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1404 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1405 if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1406 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1408 end = LittleLong(pinmodel->ofs_end);
1409 if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1410 Host_Error ("%s is not a valid model", loadmodel->name);
1411 if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1412 Host_Error ("%s is not a valid model", loadmodel->name);
1413 if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1414 Host_Error ("%s is not a valid model", loadmodel->name);
1415 if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1416 Host_Error ("%s is not a valid model", loadmodel->name);
1417 if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1418 Host_Error ("%s is not a valid model", loadmodel->name);
1420 loadmodel->numskins = LittleLong(pinmodel->num_skins);
1421 numxyz = LittleLong(pinmodel->num_xyz);
1422 numst = LittleLong(pinmodel->num_st);
1423 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1424 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1425 loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1426 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1427 skinwidth = LittleLong(pinmodel->skinwidth);
1428 skinheight = LittleLong(pinmodel->skinheight);
1429 iskinwidth = 1.0f / skinwidth;
1430 iskinheight = 1.0f / skinheight;
1432 loadmodel->num_surfaces = 1;
1433 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1434 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));
1435 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1436 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1437 loadmodel->sortedmodelsurfaces[0] = 0;
1438 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1439 loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1440 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1441 if (r_enableshadowvolumes.integer)
1443 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1446 loadmodel->synctype = ST_RAND;
1449 inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1450 skinfiles = Mod_LoadSkinFiles();
1453 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1454 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1455 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1456 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1457 Mod_FreeSkinFiles(skinfiles);
1459 else if (loadmodel->numskins)
1461 // skins found (most likely not a player model)
1462 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1463 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1464 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1465 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1466 Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
1470 // no skins (most likely a player model)
1471 loadmodel->numskins = 1;
1472 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1473 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1474 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1475 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL);
1478 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1479 for (i = 0;i < loadmodel->numskins;i++)
1481 loadmodel->skinscenes[i].firstframe = i;
1482 loadmodel->skinscenes[i].framecount = 1;
1483 loadmodel->skinscenes[i].loop = true;
1484 loadmodel->skinscenes[i].framerate = 10;
1487 // load the triangles and stvert data
1488 inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1489 intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1490 md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1491 md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1492 // swap the triangle list
1493 loadmodel->surfmesh.num_vertices = 0;
1494 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1496 for (j = 0;j < 3;j++)
1498 xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1499 st = (unsigned short) LittleShort (intri[i].index_st[j]);
1502 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1507 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1510 hashindex = (xyz * 256 + st) & 65535;
1511 for (hash = md2verthash[hashindex];hash;hash = hash->next)
1512 if (hash->xyz == xyz && hash->st == st)
1516 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1519 hash->next = md2verthash[hashindex];
1520 md2verthash[hashindex] = hash;
1522 loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1526 vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1527 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));
1528 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1529 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1530 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1533 hash = md2verthashdata + i;
1534 vertremap[i] = hash->xyz;
1535 sts = LittleShort(inst[hash->st*2+0]);
1536 stt = LittleShort(inst[hash->st*2+1]);
1537 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1539 Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1543 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1544 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1547 Mem_Free(md2verthash);
1548 Mem_Free(md2verthashdata);
1550 // generate ushort elements array if possible
1551 if (loadmodel->surfmesh.num_vertices <= 65536)
1552 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1553 if (loadmodel->surfmesh.data_element3s)
1554 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1555 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1558 datapointer = (base + LittleLong(pinmodel->ofs_frames));
1559 for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1564 pinframe = (md2frame_t *)datapointer;
1565 datapointer += sizeof(md2frame_t);
1566 // store the frame scale/translate into the appropriate array
1567 for (j = 0;j < 3;j++)
1569 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1570 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1572 // convert the vertices
1573 v = (trivertx_t *)datapointer;
1574 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1575 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1576 out[k] = v[vertremap[k]];
1577 datapointer += numxyz * sizeof(trivertx_t);
1579 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1580 loadmodel->animscenes[i].firstframe = i;
1581 loadmodel->animscenes[i].framecount = 1;
1582 loadmodel->animscenes[i].framerate = 10;
1583 loadmodel->animscenes[i].loop = true;
1586 Mem_Free(vertremap);
1588 if (loadmodel->surfmesh.data_neighbor3i)
1589 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1590 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1591 Mod_Alias_MorphMesh_CompileFrames();
1592 if(mod_alias_force_animated.string[0])
1593 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1595 surface = loadmodel->data_surfaces;
1596 surface->texture = loadmodel->data_textures;
1597 surface->num_firsttriangle = 0;
1598 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1599 surface->num_firstvertex = 0;
1600 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1602 if (!loadmodel->surfmesh.isanimated)
1604 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1605 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1606 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1607 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1608 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1609 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1612 // because shaders can do somewhat unexpected things, check for unusual features now
1613 for (i = 0;i < loadmodel->num_textures;i++)
1615 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1616 mod->DrawSky = R_Q1BSP_DrawSky;
1617 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1618 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1622 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1624 int i, j, k, version, meshvertices, meshtriangles;
1625 unsigned char *data;
1626 msurface_t *surface;
1627 md3modelheader_t *pinmodel;
1628 md3frameinfo_t *pinframe;
1631 skinfile_t *skinfiles;
1633 pinmodel = (md3modelheader_t *)buffer;
1635 if (memcmp(pinmodel->identifier, "IDP3", 4))
1636 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1637 version = LittleLong (pinmodel->version);
1638 if (version != MD3VERSION)
1639 Host_Error ("%s has wrong version number (%i should be %i)",
1640 loadmodel->name, version, MD3VERSION);
1642 skinfiles = Mod_LoadSkinFiles();
1643 if (loadmodel->numskins < 1)
1644 loadmodel->numskins = 1;
1646 loadmodel->modeldatatypestring = "MD3";
1648 loadmodel->type = mod_alias;
1649 loadmodel->DrawSky = NULL;
1650 loadmodel->DrawAddWaterPlanes = NULL;
1651 loadmodel->Draw = R_Q1BSP_Draw;
1652 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1653 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1654 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1655 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1656 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1657 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1658 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1659 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1660 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1661 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1662 loadmodel->PointSuperContents = NULL;
1663 loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1664 loadmodel->synctype = ST_RAND;
1665 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1666 i = LittleLong (pinmodel->flags);
1667 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1669 // set up some global info about the model
1670 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1671 loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1673 // make skinscenes for the skins (no groups)
1674 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1675 for (i = 0;i < loadmodel->numskins;i++)
1677 loadmodel->skinscenes[i].firstframe = i;
1678 loadmodel->skinscenes[i].framecount = 1;
1679 loadmodel->skinscenes[i].loop = true;
1680 loadmodel->skinscenes[i].framerate = 10;
1684 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1685 for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1687 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1688 loadmodel->animscenes[i].firstframe = i;
1689 loadmodel->animscenes[i].framecount = 1;
1690 loadmodel->animscenes[i].framerate = 10;
1691 loadmodel->animscenes[i].loop = true;
1695 loadmodel->num_tagframes = loadmodel->numframes;
1696 loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1697 loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1698 for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1700 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1701 for (j = 0;j < 9;j++)
1702 loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1703 for (j = 0;j < 3;j++)
1704 loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1705 //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);
1711 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)))
1713 if (memcmp(pinmesh->identifier, "IDP3", 4))
1714 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1715 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1716 Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1717 meshvertices += LittleLong(pinmesh->num_vertices);
1718 meshtriangles += LittleLong(pinmesh->num_triangles);
1721 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1722 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1723 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1724 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));
1725 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1726 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1727 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1728 loadmodel->surfmesh.num_vertices = meshvertices;
1729 loadmodel->surfmesh.num_triangles = meshtriangles;
1730 loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1731 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1732 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1733 if (r_enableshadowvolumes.integer)
1735 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1737 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1738 loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1739 if (meshvertices <= 65536)
1741 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1746 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)))
1748 if (memcmp(pinmesh->identifier, "IDP3", 4))
1749 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1750 loadmodel->sortedmodelsurfaces[i] = i;
1751 surface = loadmodel->data_surfaces + i;
1752 surface->texture = loadmodel->data_textures + i;
1753 surface->num_firsttriangle = meshtriangles;
1754 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1755 surface->num_firstvertex = meshvertices;
1756 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1757 meshvertices += surface->num_vertices;
1758 meshtriangles += surface->num_triangles;
1760 for (j = 0;j < surface->num_triangles * 3;j++)
1761 loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1762 for (j = 0;j < surface->num_vertices;j++)
1764 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1765 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1767 for (j = 0;j < loadmodel->numframes;j++)
1769 const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1770 md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1771 for (k = 0;k < surface->num_vertices;k++, in++, out++)
1773 out->origin[0] = LittleShort(in->origin[0]);
1774 out->origin[1] = LittleShort(in->origin[1]);
1775 out->origin[2] = LittleShort(in->origin[2]);
1776 out->pitch = in->pitch;
1781 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1783 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1785 if (loadmodel->surfmesh.data_element3s)
1786 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1787 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1788 if (loadmodel->surfmesh.data_neighbor3i)
1789 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1790 Mod_Alias_MorphMesh_CompileFrames();
1791 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1792 Mod_FreeSkinFiles(skinfiles);
1793 Mod_MakeSortedSurfaces(loadmodel);
1794 if(mod_alias_force_animated.string[0])
1795 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1797 if (!loadmodel->surfmesh.isanimated)
1799 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1800 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1801 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1802 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1803 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1804 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1807 // because shaders can do somewhat unexpected things, check for unusual features now
1808 for (i = 0;i < loadmodel->num_textures;i++)
1810 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1811 mod->DrawSky = R_Q1BSP_DrawSky;
1812 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1813 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1817 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1819 zymtype1header_t *pinmodel, *pheader;
1820 unsigned char *pbase;
1821 int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1822 float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1823 zymvertex_t *verts, *vertdata;
1827 skinfile_t *skinfiles;
1828 unsigned char *data;
1829 msurface_t *surface;
1831 pinmodel = (zymtype1header_t *)buffer;
1832 pbase = (unsigned char *)buffer;
1833 if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1834 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1835 if (BigLong(pinmodel->type) != 1)
1836 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1838 loadmodel->modeldatatypestring = "ZYM";
1840 loadmodel->type = mod_alias;
1841 loadmodel->synctype = ST_RAND;
1845 pheader->type = BigLong(pinmodel->type);
1846 pheader->filesize = BigLong(pinmodel->filesize);
1847 pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1848 pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1849 pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1850 pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1851 pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1852 pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1853 pheader->radius = BigFloat(pinmodel->radius);
1854 pheader->numverts = BigLong(pinmodel->numverts);
1855 pheader->numtris = BigLong(pinmodel->numtris);
1856 pheader->numshaders = BigLong(pinmodel->numshaders);
1857 pheader->numbones = BigLong(pinmodel->numbones);
1858 pheader->numscenes = BigLong(pinmodel->numscenes);
1859 pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1860 pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1861 pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1862 pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1863 pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1864 pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1865 pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1866 pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1867 pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1868 pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1869 pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1870 pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1871 pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1872 pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1873 pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1874 pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1875 pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1876 pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1878 if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1880 Con_Printf("%s has no geometry\n", loadmodel->name);
1883 if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1885 Con_Printf("%s has no animations\n", loadmodel->name);
1889 loadmodel->DrawSky = NULL;
1890 loadmodel->DrawAddWaterPlanes = NULL;
1891 loadmodel->Draw = R_Q1BSP_Draw;
1892 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1893 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1894 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1895 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1896 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1897 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1898 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1899 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1900 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1901 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1902 loadmodel->PointSuperContents = NULL;
1903 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1905 loadmodel->numframes = pheader->numscenes;
1906 loadmodel->num_surfaces = pheader->numshaders;
1908 skinfiles = Mod_LoadSkinFiles();
1909 if (loadmodel->numskins < 1)
1910 loadmodel->numskins = 1;
1912 // make skinscenes for the skins (no groups)
1913 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1914 for (i = 0;i < loadmodel->numskins;i++)
1916 loadmodel->skinscenes[i].firstframe = i;
1917 loadmodel->skinscenes[i].framecount = 1;
1918 loadmodel->skinscenes[i].loop = true;
1919 loadmodel->skinscenes[i].framerate = 10;
1923 // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1924 modelradius = pheader->radius;
1925 for (i = 0;i < 3;i++)
1927 loadmodel->normalmins[i] = pheader->mins[i];
1928 loadmodel->normalmaxs[i] = pheader->maxs[i];
1929 loadmodel->rotatedmins[i] = -modelradius;
1930 loadmodel->rotatedmaxs[i] = modelradius;
1932 corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1933 corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1934 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1935 if (loadmodel->yawmaxs[0] > modelradius)
1936 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1937 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1938 loadmodel->yawmins[2] = loadmodel->normalmins[2];
1939 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1940 loadmodel->radius = modelradius;
1941 loadmodel->radius2 = modelradius * modelradius;
1943 // go through the lumps, swapping things
1945 //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1946 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1947 scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1948 numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1949 for (i = 0;i < pheader->numscenes;i++)
1951 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1952 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1953 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1954 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1955 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1956 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1957 Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1958 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1959 Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1960 if (loadmodel->animscenes[i].framerate < 0)
1961 Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1965 //zymlump_t lump_bones; // zymbone_t bone[numbones];
1966 loadmodel->num_bones = pheader->numbones;
1967 loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1968 bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1969 for (i = 0;i < pheader->numbones;i++)
1971 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1972 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1973 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1974 if (loadmodel->data_bones[i].parent >= i)
1975 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1978 //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1979 vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1980 bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1981 for (i = 0;i < pheader->numverts;i++)
1983 vertbonecounts[i] = BigLong(bonecount[i]);
1984 if (vertbonecounts[i] != 1)
1985 Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1988 loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1990 meshvertices = pheader->numverts;
1991 meshtriangles = pheader->numtris;
1993 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1994 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1995 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1996 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]));
1997 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1998 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1999 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2000 loadmodel->surfmesh.num_vertices = meshvertices;
2001 loadmodel->surfmesh.num_triangles = meshtriangles;
2002 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2003 if (r_enableshadowvolumes.integer)
2005 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2007 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2008 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2009 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2010 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2011 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2012 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2013 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2014 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2015 loadmodel->surfmesh.num_blends = 0;
2016 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2017 if (loadmodel->surfmesh.num_vertices <= 65536)
2019 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2021 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2022 loadmodel->surfmesh.data_blendweights = NULL;
2024 //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
2025 poses = (float *) (pheader->lump_poses.start + pbase);
2026 // figure out scale of model from root bone, for compatibility with old zmodel versions
2027 tempvec[0] = BigFloat(poses[0]);
2028 tempvec[1] = BigFloat(poses[1]);
2029 tempvec[2] = BigFloat(poses[2]);
2030 modelscale = VectorLength(tempvec);
2032 for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
2034 f = fabs(BigFloat(poses[i]));
2035 biggestorigin = max(biggestorigin, f);
2037 loadmodel->num_posescale = biggestorigin / 32767.0f;
2038 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2039 for (i = 0;i < numposes;i++)
2041 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
2042 for (j = 0;j < loadmodel->num_bones;j++)
2045 matrix4x4_t posematrix;
2046 for (k = 0;k < 12;k++)
2047 pose[k] = BigFloat(frameposes[j*12+k]);
2048 //if (j < loadmodel->num_bones)
2049 // 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));
2050 // scale child bones to match the root scale
2051 if (loadmodel->data_bones[j].parent >= 0)
2053 pose[3] *= modelscale;
2054 pose[7] *= modelscale;
2055 pose[11] *= modelscale;
2057 // normalize rotation matrix
2058 VectorNormalize(pose + 0);
2059 VectorNormalize(pose + 4);
2060 VectorNormalize(pose + 8);
2061 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2062 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2066 //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2067 verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2068 vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2069 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2070 // (converting from weight-blending skeletal animation to
2071 // deformation-based skeletal animation)
2072 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2073 for (i = 0;i < loadmodel->num_bones;i++)
2076 for (k = 0;k < 12;k++)
2077 m[k] = BigFloat(poses[i*12+k]);
2078 if (loadmodel->data_bones[i].parent >= 0)
2079 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2081 for (k = 0;k < 12;k++)
2082 bonepose[12*i+k] = m[k];
2084 for (j = 0;j < pheader->numverts;j++)
2086 // this format really should have had a per vertexweight weight value...
2087 // but since it does not, the weighting is completely ignored and
2088 // only one weight is allowed per vertex
2089 int boneindex = BigLong(vertdata[j].bonenum);
2090 const float *m = bonepose + 12 * boneindex;
2091 float relativeorigin[3];
2092 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2093 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2094 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2095 // transform the vertex bone weight into the base mesh
2096 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2097 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2098 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2099 // store the weight as the primary weight on this vertex
2100 loadmodel->surfmesh.blends[j] = boneindex;
2101 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = boneindex;
2102 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2103 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2104 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2105 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = 255;
2106 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2107 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2108 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2111 // normals and tangents are calculated after elements are loaded
2113 //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2114 outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2115 intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2116 for (i = 0;i < pheader->numverts;i++)
2118 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2119 // flip T coordinate for OpenGL
2120 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2123 //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2124 //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2125 //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2127 //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2128 //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)
2129 // byteswap, validate, and swap winding order of tris
2130 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2131 if (pheader->lump_render.length != count)
2132 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2133 renderlist = (int *) (pheader->lump_render.start + pbase);
2134 renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2136 for (i = 0;i < loadmodel->num_surfaces;i++)
2138 int firstvertex, lastvertex;
2139 if (renderlist >= renderlistend)
2140 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2141 count = BigLong(*renderlist);renderlist++;
2142 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2143 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2145 loadmodel->sortedmodelsurfaces[i] = i;
2146 surface = loadmodel->data_surfaces + i;
2147 surface->texture = loadmodel->data_textures + i;
2148 surface->num_firsttriangle = meshtriangles;
2149 surface->num_triangles = count;
2150 meshtriangles += surface->num_triangles;
2152 // load the elements
2153 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2154 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2156 outelements[j*3+2] = BigLong(renderlist[0]);
2157 outelements[j*3+1] = BigLong(renderlist[1]);
2158 outelements[j*3+0] = BigLong(renderlist[2]);
2160 // validate the elements and find the used vertex range
2161 firstvertex = meshvertices;
2163 for (j = 0;j < surface->num_triangles * 3;j++)
2165 if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2166 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2167 firstvertex = min(firstvertex, outelements[j]);
2168 lastvertex = max(lastvertex, outelements[j]);
2170 surface->num_firstvertex = firstvertex;
2171 surface->num_vertices = lastvertex + 1 - firstvertex;
2173 // since zym models do not have named sections, reuse their shader
2174 // name as the section name
2175 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2176 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2178 Mod_FreeSkinFiles(skinfiles);
2179 Mem_Free(vertbonecounts);
2181 Mod_MakeSortedSurfaces(loadmodel);
2183 // compute all the mesh information that was not loaded from the file
2184 if (loadmodel->surfmesh.data_element3s)
2185 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2186 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2187 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2188 Mod_BuildBaseBonePoses();
2189 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);
2190 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);
2191 if (loadmodel->surfmesh.data_neighbor3i)
2192 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2193 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2194 if(mod_alias_force_animated.string[0])
2195 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2197 if (!loadmodel->surfmesh.isanimated)
2199 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2200 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2201 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2202 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2203 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2204 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2207 // because shaders can do somewhat unexpected things, check for unusual features now
2208 for (i = 0;i < loadmodel->num_textures;i++)
2210 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2211 mod->DrawSky = R_Q1BSP_DrawSky;
2212 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2213 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2217 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2219 dpmheader_t *pheader;
2223 unsigned char *pbase;
2224 int i, j, k, meshvertices, meshtriangles;
2225 skinfile_t *skinfiles;
2226 unsigned char *data;
2228 float biggestorigin, tempvec[3], modelscale;
2232 pheader = (dpmheader_t *)buffer;
2233 pbase = (unsigned char *)buffer;
2234 if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2235 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2236 if (BigLong(pheader->type) != 2)
2237 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2239 loadmodel->modeldatatypestring = "DPM";
2241 loadmodel->type = mod_alias;
2242 loadmodel->synctype = ST_RAND;
2245 pheader->type = BigLong(pheader->type);
2246 pheader->filesize = BigLong(pheader->filesize);
2247 pheader->mins[0] = BigFloat(pheader->mins[0]);
2248 pheader->mins[1] = BigFloat(pheader->mins[1]);
2249 pheader->mins[2] = BigFloat(pheader->mins[2]);
2250 pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2251 pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2252 pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2253 pheader->yawradius = BigFloat(pheader->yawradius);
2254 pheader->allradius = BigFloat(pheader->allradius);
2255 pheader->num_bones = BigLong(pheader->num_bones);
2256 pheader->num_meshs = BigLong(pheader->num_meshs);
2257 pheader->num_frames = BigLong(pheader->num_frames);
2258 pheader->ofs_bones = BigLong(pheader->ofs_bones);
2259 pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2260 pheader->ofs_frames = BigLong(pheader->ofs_frames);
2262 if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2264 Con_Printf("%s has no geometry\n", loadmodel->name);
2267 if (pheader->num_frames < 1)
2269 Con_Printf("%s has no frames\n", loadmodel->name);
2273 loadmodel->DrawSky = NULL;
2274 loadmodel->DrawAddWaterPlanes = NULL;
2275 loadmodel->Draw = R_Q1BSP_Draw;
2276 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2277 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2278 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2279 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2280 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2281 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2282 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2283 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2284 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2285 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2286 loadmodel->PointSuperContents = NULL;
2287 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2290 // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2291 for (i = 0;i < 3;i++)
2293 loadmodel->normalmins[i] = pheader->mins[i];
2294 loadmodel->normalmaxs[i] = pheader->maxs[i];
2295 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2296 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2297 loadmodel->rotatedmins[i] = -pheader->allradius;
2298 loadmodel->rotatedmaxs[i] = pheader->allradius;
2300 loadmodel->radius = pheader->allradius;
2301 loadmodel->radius2 = pheader->allradius * pheader->allradius;
2303 // load external .skin files if present
2304 skinfiles = Mod_LoadSkinFiles();
2305 if (loadmodel->numskins < 1)
2306 loadmodel->numskins = 1;
2311 // gather combined statistics from the meshes
2312 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2313 for (i = 0;i < (int)pheader->num_meshs;i++)
2315 int numverts = BigLong(dpmmesh->num_verts);
2316 meshvertices += numverts;
2317 meshtriangles += BigLong(dpmmesh->num_tris);
2321 loadmodel->numframes = pheader->num_frames;
2322 loadmodel->num_bones = pheader->num_bones;
2323 loadmodel->num_poses = loadmodel->numframes;
2324 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2325 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2326 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2327 // do most allocations as one merged chunk
2328 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));
2329 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2330 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2331 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2332 loadmodel->surfmesh.num_vertices = meshvertices;
2333 loadmodel->surfmesh.num_triangles = meshtriangles;
2334 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2335 if (r_enableshadowvolumes.integer)
2337 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2339 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2340 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2341 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2342 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2343 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2344 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2345 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2346 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2347 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2348 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2349 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2350 loadmodel->surfmesh.num_blends = 0;
2351 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2352 if (meshvertices <= 65536)
2354 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2356 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2357 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2359 for (i = 0;i < loadmodel->numskins;i++)
2361 loadmodel->skinscenes[i].firstframe = i;
2362 loadmodel->skinscenes[i].framecount = 1;
2363 loadmodel->skinscenes[i].loop = true;
2364 loadmodel->skinscenes[i].framerate = 10;
2367 // load the bone info
2368 bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2369 for (i = 0;i < loadmodel->num_bones;i++)
2371 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2372 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2373 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2374 if (loadmodel->data_bones[i].parent >= i)
2375 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2379 frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2380 // figure out scale of model from root bone, for compatibility with old dpmodel versions
2381 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2382 tempvec[0] = BigFloat(poses[0]);
2383 tempvec[1] = BigFloat(poses[1]);
2384 tempvec[2] = BigFloat(poses[2]);
2385 modelscale = VectorLength(tempvec);
2387 for (i = 0;i < loadmodel->numframes;i++)
2389 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2390 loadmodel->animscenes[i].firstframe = i;
2391 loadmodel->animscenes[i].framecount = 1;
2392 loadmodel->animscenes[i].loop = true;
2393 loadmodel->animscenes[i].framerate = 10;
2394 // load the bone poses for this frame
2395 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2396 for (j = 0;j < loadmodel->num_bones*12;j++)
2398 f = fabs(BigFloat(poses[j]));
2399 biggestorigin = max(biggestorigin, f);
2401 // stuff not processed here: mins, maxs, yawradius, allradius
2403 loadmodel->num_posescale = biggestorigin / 32767.0f;
2404 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2405 for (i = 0;i < loadmodel->numframes;i++)
2407 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2408 for (j = 0;j < loadmodel->num_bones;j++)
2411 matrix4x4_t posematrix;
2412 for (k = 0;k < 12;k++)
2413 pose[k] = BigFloat(frameposes[j*12+k]);
2414 // scale child bones to match the root scale
2415 if (loadmodel->data_bones[j].parent >= 0)
2417 pose[3] *= modelscale;
2418 pose[7] *= modelscale;
2419 pose[11] *= modelscale;
2421 // normalize rotation matrix
2422 VectorNormalize(pose + 0);
2423 VectorNormalize(pose + 4);
2424 VectorNormalize(pose + 8);
2425 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2426 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2430 // load the meshes now
2431 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2434 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2435 // (converting from weight-blending skeletal animation to
2436 // deformation-based skeletal animation)
2437 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2438 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2439 for (i = 0;i < loadmodel->num_bones;i++)
2442 for (k = 0;k < 12;k++)
2443 m[k] = BigFloat(poses[i*12+k]);
2444 if (loadmodel->data_bones[i].parent >= 0)
2445 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2447 for (k = 0;k < 12;k++)
2448 bonepose[12*i+k] = m[k];
2450 for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2452 const int *inelements;
2454 const float *intexcoord;
2455 msurface_t *surface;
2457 loadmodel->sortedmodelsurfaces[i] = i;
2458 surface = loadmodel->data_surfaces + i;
2459 surface->texture = loadmodel->data_textures + i;
2460 surface->num_firsttriangle = meshtriangles;
2461 surface->num_triangles = BigLong(dpmmesh->num_tris);
2462 surface->num_firstvertex = meshvertices;
2463 surface->num_vertices = BigLong(dpmmesh->num_verts);
2464 meshvertices += surface->num_vertices;
2465 meshtriangles += surface->num_triangles;
2467 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2468 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2469 for (j = 0;j < surface->num_triangles;j++)
2471 // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2472 outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2473 outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2474 outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2479 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2480 for (j = 0;j < surface->num_vertices*2;j++)
2481 loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2483 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2484 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2486 int weightindex[4] = { 0, 0, 0, 0 };
2487 float weightinfluence[4] = { 0, 0, 0, 0 };
2489 int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2490 data += sizeof(dpmvertex_t);
2491 for (k = 0;k < numweights;k++)
2493 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2494 int boneindex = BigLong(vert->bonenum);
2495 const float *m = bonepose + 12 * boneindex;
2496 float influence = BigFloat(vert->influence);
2497 float relativeorigin[3], relativenormal[3];
2498 relativeorigin[0] = BigFloat(vert->origin[0]);
2499 relativeorigin[1] = BigFloat(vert->origin[1]);
2500 relativeorigin[2] = BigFloat(vert->origin[2]);
2501 relativenormal[0] = BigFloat(vert->normal[0]);
2502 relativenormal[1] = BigFloat(vert->normal[1]);
2503 relativenormal[2] = BigFloat(vert->normal[2]);
2504 // blend the vertex bone weights into the base mesh
2505 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2506 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2507 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2508 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2509 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2510 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2513 // store the first (and often only) weight
2514 weightinfluence[0] = influence;
2515 weightindex[0] = boneindex;
2519 // sort the new weight into this vertex's weight table
2520 // (which only accepts up to 4 bones per vertex)
2521 for (l = 0;l < 4;l++)
2523 if (weightinfluence[l] < influence)
2525 // move weaker influence weights out of the way first
2527 for (l2 = 3;l2 > l;l2--)
2529 weightinfluence[l2] = weightinfluence[l2-1];
2530 weightindex[l2] = weightindex[l2-1];
2532 // store the new weight
2533 weightinfluence[l] = influence;
2534 weightindex[l] = boneindex;
2539 data += sizeof(dpmbonevert_t);
2541 loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2542 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = weightindex[0];
2543 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2544 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2545 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2546 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
2547 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2548 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2549 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2552 // since dpm models do not have named sections, reuse their shader name as the section name
2553 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2555 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2557 if (loadmodel->surfmesh.num_blends < meshvertices)
2558 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2560 Mod_FreeSkinFiles(skinfiles);
2561 Mod_MakeSortedSurfaces(loadmodel);
2563 // compute all the mesh information that was not loaded from the file
2564 if (loadmodel->surfmesh.data_element3s)
2565 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2566 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2567 Mod_BuildBaseBonePoses();
2568 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);
2569 if (loadmodel->surfmesh.data_neighbor3i)
2570 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2571 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2572 if(mod_alias_force_animated.string[0])
2573 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2575 if (!loadmodel->surfmesh.isanimated)
2577 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2578 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2579 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2580 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2581 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2582 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2585 // because shaders can do somewhat unexpected things, check for unusual features now
2586 for (i = 0;i < loadmodel->num_textures;i++)
2588 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2589 mod->DrawSky = R_Q1BSP_DrawSky;
2590 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2591 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2595 // no idea why PSK/PSA files contain weird quaternions but they do...
2596 #define PSKQUATNEGATIONS
2597 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2599 int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2600 int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2601 fs_offset_t filesize;
2606 pskboneinfo_t *bones;
2607 pskrawweights_t *rawweights;
2608 //pskboneinfo_t *animbones;
2609 pskaniminfo_t *anims;
2610 pskanimkeys_t *animkeys;
2611 void *animfilebuffer, *animbuffer, *animbufferend;
2612 unsigned char *data;
2614 skinfile_t *skinfiles;
2615 char animname[MAX_QPATH];
2617 float biggestorigin;
2619 pchunk = (pskchunk_t *)buffer;
2620 if (strcmp(pchunk->id, "ACTRHEAD"))
2621 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2623 loadmodel->modeldatatypestring = "PSK";
2625 loadmodel->type = mod_alias;
2626 loadmodel->DrawSky = NULL;
2627 loadmodel->DrawAddWaterPlanes = NULL;
2628 loadmodel->Draw = R_Q1BSP_Draw;
2629 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2630 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2631 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2632 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2633 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2634 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2635 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2636 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2637 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2638 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2639 loadmodel->PointSuperContents = NULL;
2640 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2641 loadmodel->synctype = ST_RAND;
2643 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2644 strlcat(animname, ".psa", sizeof(animname));
2645 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2646 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2648 animbufferend = animbuffer;
2667 while (buffer < bufferend)
2669 pchunk = (pskchunk_t *)buffer;
2670 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2671 version = LittleLong(pchunk->version);
2672 recordsize = LittleLong(pchunk->recordsize);
2673 numrecords = LittleLong(pchunk->numrecords);
2674 if (developer_extra.integer)
2675 Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2676 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2677 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);
2678 if (!strcmp(pchunk->id, "ACTRHEAD"))
2682 else if (!strcmp(pchunk->id, "PNTS0000"))
2685 if (recordsize != sizeof(*p))
2686 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2687 // byteswap in place and keep the pointer
2688 numpnts = numrecords;
2689 pnts = (pskpnts_t *)buffer;
2690 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2692 p->origin[0] = LittleFloat(p->origin[0]);
2693 p->origin[1] = LittleFloat(p->origin[1]);
2694 p->origin[2] = LittleFloat(p->origin[2]);
2698 else if (!strcmp(pchunk->id, "VTXW0000"))
2701 if (recordsize != sizeof(*p))
2702 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2703 // byteswap in place and keep the pointer
2704 numvtxw = numrecords;
2705 vtxw = (pskvtxw_t *)buffer;
2706 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2708 p->pntsindex = LittleShort(p->pntsindex);
2709 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2710 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2711 if (p->pntsindex >= numpnts)
2713 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2719 else if (!strcmp(pchunk->id, "FACE0000"))
2722 if (recordsize != sizeof(*p))
2723 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2724 // byteswap in place and keep the pointer
2725 numfaces = numrecords;
2726 faces = (pskface_t *)buffer;
2727 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2729 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2730 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2731 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2732 p->group = LittleLong(p->group);
2733 if (p->vtxwindex[0] >= numvtxw)
2735 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2736 p->vtxwindex[0] = 0;
2738 if (p->vtxwindex[1] >= numvtxw)
2740 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2741 p->vtxwindex[1] = 0;
2743 if (p->vtxwindex[2] >= numvtxw)
2745 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2746 p->vtxwindex[2] = 0;
2751 else if (!strcmp(pchunk->id, "MATT0000"))
2754 if (recordsize != sizeof(*p))
2755 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2756 // byteswap in place and keep the pointer
2757 nummatts = numrecords;
2758 matts = (pskmatt_t *)buffer;
2759 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2765 else if (!strcmp(pchunk->id, "REFSKELT"))
2768 if (recordsize != sizeof(*p))
2769 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2770 // byteswap in place and keep the pointer
2771 numbones = numrecords;
2772 bones = (pskboneinfo_t *)buffer;
2773 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2775 p->numchildren = LittleLong(p->numchildren);
2776 p->parent = LittleLong(p->parent);
2777 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2778 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2779 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2780 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2781 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2782 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2783 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2784 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2785 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2786 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2787 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2788 #ifdef PSKQUATNEGATIONS
2791 p->basepose.quat[0] *= -1;
2792 p->basepose.quat[1] *= -1;
2793 p->basepose.quat[2] *= -1;
2797 p->basepose.quat[0] *= 1;
2798 p->basepose.quat[1] *= -1;
2799 p->basepose.quat[2] *= 1;
2802 if (p->parent < 0 || p->parent >= numbones)
2804 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2810 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2813 if (recordsize != sizeof(*p))
2814 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2815 // byteswap in place and keep the pointer
2816 numrawweights = numrecords;
2817 rawweights = (pskrawweights_t *)buffer;
2818 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2820 p->weight = LittleFloat(p->weight);
2821 p->pntsindex = LittleLong(p->pntsindex);
2822 p->boneindex = LittleLong(p->boneindex);
2823 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2825 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2828 if (p->boneindex < 0 || p->boneindex >= numbones)
2830 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2838 while (animbuffer < animbufferend)
2840 pchunk = (pskchunk_t *)animbuffer;
2841 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2842 version = LittleLong(pchunk->version);
2843 recordsize = LittleLong(pchunk->recordsize);
2844 numrecords = LittleLong(pchunk->numrecords);
2845 if (developer_extra.integer)
2846 Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2847 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2848 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);
2849 if (!strcmp(pchunk->id, "ANIMHEAD"))
2853 else if (!strcmp(pchunk->id, "BONENAMES"))
2856 if (recordsize != sizeof(*p))
2857 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2858 // byteswap in place and keep the pointer
2859 numanimbones = numrecords;
2860 //animbones = (pskboneinfo_t *)animbuffer;
2861 // NOTE: supposedly psa does not need to match the psk model, the
2862 // bones missing from the psa would simply use their base
2863 // positions from the psk, but this is hard for me to implement
2864 // and people can easily make animations that match.
2865 if (numanimbones != numbones)
2866 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2867 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2869 p->numchildren = LittleLong(p->numchildren);
2870 p->parent = LittleLong(p->parent);
2871 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2872 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2873 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2874 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2875 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2876 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2877 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2878 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2879 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2880 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2881 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2882 #ifdef PSKQUATNEGATIONS
2885 p->basepose.quat[0] *= -1;
2886 p->basepose.quat[1] *= -1;
2887 p->basepose.quat[2] *= -1;
2891 p->basepose.quat[0] *= 1;
2892 p->basepose.quat[1] *= -1;
2893 p->basepose.quat[2] *= 1;
2896 if (p->parent < 0 || p->parent >= numanimbones)
2898 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2901 // check that bones are the same as in the base
2902 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2903 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2907 else if (!strcmp(pchunk->id, "ANIMINFO"))
2910 if (recordsize != sizeof(*p))
2911 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2912 // byteswap in place and keep the pointer
2913 numanims = numrecords;
2914 anims = (pskaniminfo_t *)animbuffer;
2915 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2917 p->numbones = LittleLong(p->numbones);
2918 p->playtime = LittleFloat(p->playtime);
2919 p->fps = LittleFloat(p->fps);
2920 p->firstframe = LittleLong(p->firstframe);
2921 p->numframes = LittleLong(p->numframes);
2922 if (p->numbones != numbones)
2923 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2927 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2930 if (recordsize != sizeof(*p))
2931 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2932 numanimkeys = numrecords;
2933 animkeys = (pskanimkeys_t *)animbuffer;
2934 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2936 p->origin[0] = LittleFloat(p->origin[0]);
2937 p->origin[1] = LittleFloat(p->origin[1]);
2938 p->origin[2] = LittleFloat(p->origin[2]);
2939 p->quat[0] = LittleFloat(p->quat[0]);
2940 p->quat[1] = LittleFloat(p->quat[1]);
2941 p->quat[2] = LittleFloat(p->quat[2]);
2942 p->quat[3] = LittleFloat(p->quat[3]);
2943 p->frametime = LittleFloat(p->frametime);
2944 #ifdef PSKQUATNEGATIONS
2945 if (index % numbones)
2960 // TODO: allocate bonepose stuff
2963 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2966 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2967 Host_Error("%s: missing required chunks", loadmodel->name);
2971 loadmodel->numframes = 0;
2972 for (index = 0;index < numanims;index++)
2973 loadmodel->numframes += anims[index].numframes;
2974 if (numanimkeys != numbones * loadmodel->numframes)
2975 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2978 loadmodel->numframes = loadmodel->num_poses = 1;
2980 meshvertices = numvtxw;
2981 meshtriangles = numfaces;
2983 // load external .skin files if present
2984 skinfiles = Mod_LoadSkinFiles();
2985 if (loadmodel->numskins < 1)
2986 loadmodel->numskins = 1;
2987 loadmodel->num_bones = numbones;
2988 loadmodel->num_poses = loadmodel->numframes;
2989 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2990 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2991 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2992 loadmodel->surfmesh.num_vertices = meshvertices;
2993 loadmodel->surfmesh.num_triangles = meshtriangles;
2994 // do most allocations as one merged chunk
2995 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);
2996 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2997 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2998 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2999 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3000 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3001 if (r_enableshadowvolumes.integer)
3003 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3005 loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3006 loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3007 loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3008 loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3009 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3010 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3011 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3012 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3013 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3014 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3015 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3016 loadmodel->surfmesh.num_blends = 0;
3017 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3018 if (loadmodel->surfmesh.num_vertices <= 65536)
3020 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
3022 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3023 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
3025 for (i = 0;i < loadmodel->numskins;i++)
3027 loadmodel->skinscenes[i].firstframe = i;
3028 loadmodel->skinscenes[i].framecount = 1;
3029 loadmodel->skinscenes[i].loop = true;
3030 loadmodel->skinscenes[i].framerate = 10;
3034 for (index = 0, i = 0;index < nummatts;index++)
3036 // since psk models do not have named sections, reuse their shader name as the section name
3037 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
3038 loadmodel->sortedmodelsurfaces[index] = index;
3039 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
3040 loadmodel->data_surfaces[index].num_firstvertex = 0;
3041 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
3044 // copy over the vertex locations and texcoords
3045 for (index = 0;index < numvtxw;index++)
3047 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
3048 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
3049 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
3050 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
3051 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
3054 // loading the faces is complicated because we need to sort them into surfaces by mattindex
3055 for (index = 0;index < numfaces;index++)
3056 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
3057 for (index = 0, i = 0;index < nummatts;index++)
3059 loadmodel->data_surfaces[index].num_firsttriangle = i;
3060 i += loadmodel->data_surfaces[index].num_triangles;
3061 loadmodel->data_surfaces[index].num_triangles = 0;
3063 for (index = 0;index < numfaces;index++)
3065 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3066 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3067 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3068 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3071 // copy over the bones
3072 for (index = 0;index < numbones;index++)
3074 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3075 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3076 if (loadmodel->data_bones[index].parent >= index)
3077 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3080 // convert the basepose data
3081 if (loadmodel->num_bones)
3084 matrix4x4_t *basebonepose;
3085 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3086 matrix4x4_t bonematrix;
3087 matrix4x4_t tempbonematrix;
3088 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3089 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3091 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]);
3092 if (loadmodel->data_bones[boneindex].parent >= 0)
3094 tempbonematrix = bonematrix;
3095 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3097 basebonepose[boneindex] = bonematrix;
3098 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3099 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3101 Mem_Free(basebonepose);
3104 // sort the psk point weights into the vertex weight tables
3105 // (which only accept up to 4 bones per vertex)
3106 for (index = 0;index < numvtxw;index++)
3108 int weightindex[4] = { 0, 0, 0, 0 };
3109 float weightinfluence[4] = { 0, 0, 0, 0 };
3111 for (j = 0;j < numrawweights;j++)
3113 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3115 int boneindex = rawweights[j].boneindex;
3116 float influence = rawweights[j].weight;
3117 for (l = 0;l < 4;l++)
3119 if (weightinfluence[l] < influence)
3121 // move lower influence weights out of the way first
3123 for (l2 = 3;l2 > l;l2--)
3125 weightinfluence[l2] = weightinfluence[l2-1];
3126 weightindex[l2] = weightindex[l2-1];
3128 // store the new weight
3129 weightinfluence[l] = influence;
3130 weightindex[l] = boneindex;
3136 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3137 loadmodel->surfmesh.data_skeletalindex4ub[index*4 ] = weightindex[0];
3138 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3139 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3140 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3141 loadmodel->surfmesh.data_skeletalweight4ub[index*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
3142 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3143 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3144 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3146 if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3147 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3149 // set up the animscenes based on the anims
3152 for (index = 0, i = 0;index < numanims;index++)
3154 for (j = 0;j < anims[index].numframes;j++, i++)
3156 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3157 loadmodel->animscenes[i].firstframe = i;
3158 loadmodel->animscenes[i].framecount = 1;
3159 loadmodel->animscenes[i].loop = true;
3160 loadmodel->animscenes[i].framerate = anims[index].fps;
3163 // calculate the scaling value for bone origins so they can be compressed to short
3165 for (index = 0;index < numanimkeys;index++)
3167 pskanimkeys_t *k = animkeys + index;
3168 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3169 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3170 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3172 loadmodel->num_posescale = biggestorigin / 32767.0f;
3173 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3175 // load the poses from the animkeys
3176 for (index = 0;index < numanimkeys;index++)
3178 pskanimkeys_t *k = animkeys + index;
3180 Vector4Copy(k->quat, quat);
3182 Vector4Negate(quat, quat);
3183 Vector4Normalize2(quat, quat);
3184 // compress poses to the short[7] format for longterm storage
3185 loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3186 loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3187 loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3188 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3189 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3190 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3191 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3196 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3197 loadmodel->animscenes[0].firstframe = 0;
3198 loadmodel->animscenes[0].framecount = 1;
3199 loadmodel->animscenes[0].loop = true;
3200 loadmodel->animscenes[0].framerate = 10;
3202 // calculate the scaling value for bone origins so they can be compressed to short
3204 for (index = 0;index < numbones;index++)
3206 pskboneinfo_t *p = bones + index;
3207 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3208 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3209 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3211 loadmodel->num_posescale = biggestorigin / 32767.0f;
3212 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3214 // load the basepose as a frame
3215 for (index = 0;index < numbones;index++)
3217 pskboneinfo_t *p = bones + index;
3219 Vector4Copy(p->basepose.quat, quat);
3221 Vector4Negate(quat, quat);
3222 Vector4Normalize2(quat, quat);
3223 // compress poses to the short[7] format for longterm storage
3224 loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3225 loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3226 loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3227 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3228 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3229 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3230 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3234 Mod_FreeSkinFiles(skinfiles);
3236 Mem_Free(animfilebuffer);
3237 Mod_MakeSortedSurfaces(loadmodel);
3239 // compute all the mesh information that was not loaded from the file
3240 // TODO: honor smoothing groups somehow?
3241 if (loadmodel->surfmesh.data_element3s)
3242 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3243 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3244 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3245 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);
3246 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);
3247 if (loadmodel->surfmesh.data_neighbor3i)
3248 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
3249 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3250 if(mod_alias_force_animated.string[0])
3251 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3253 if (!loadmodel->surfmesh.isanimated)
3255 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3256 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3257 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3258 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3259 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3260 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3263 // because shaders can do somewhat unexpected things, check for unusual features now
3264 for (i = 0;i < loadmodel->num_textures;i++)
3266 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3267 mod->DrawSky = R_Q1BSP_DrawSky;
3268 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3269 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3273 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
3275 unsigned char *data;
3277 const unsigned char *pbase, *pend;
3279 skinfile_t *skinfiles;
3280 int i, j, k, meshvertices, meshtriangles;
3281 float biggestorigin;
3282 const unsigned int *inelements;
3284 const int *inneighbors;
3286 float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3287 // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3288 const float *vnormal = NULL;
3289 const float *vposition = NULL;
3290 const float *vtangent = NULL;
3291 const float *vtexcoord = NULL;
3292 const float *vcolor4f = NULL;
3293 const unsigned char *vblendindexes = NULL;
3294 const unsigned char *vblendweights = NULL;
3295 const unsigned char *vcolor4ub = NULL;
3296 const unsigned short *framedata = NULL;
3297 // temporary memory allocations (because the data in the file may be misaligned)
3298 iqmanim_t *anims = NULL;
3299 iqmbounds_t *bounds = NULL;
3300 iqmjoint1_t *joint1 = NULL;
3301 iqmjoint_t *joint = NULL;
3302 iqmmesh_t *meshes = NULL;
3303 iqmpose1_t *pose1 = NULL;
3304 iqmpose_t *pose = NULL;
3305 iqmvertexarray_t *vas = NULL;
3307 pbase = (unsigned char *)buffer;
3308 pend = (unsigned char *)bufferend;
3310 if (pbase + sizeof(iqmheader_t) > pend)
3311 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3313 // copy struct (otherwise it may be misaligned)
3314 // LordHavoc: okay it's definitely not misaligned here, but for consistency...
3315 memcpy(&header, pbase, sizeof(iqmheader_t));
3317 if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3318 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3319 if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3320 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3322 loadmodel->modeldatatypestring = "IQM";
3324 loadmodel->type = mod_alias;
3325 loadmodel->synctype = ST_RAND;
3328 header.version = LittleLong(header.version);
3329 header.filesize = LittleLong(header.filesize);
3330 header.flags = LittleLong(header.flags);
3331 header.num_text = LittleLong(header.num_text);
3332 header.ofs_text = LittleLong(header.ofs_text);
3333 header.num_meshes = LittleLong(header.num_meshes);
3334 header.ofs_meshes = LittleLong(header.ofs_meshes);
3335 header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3336 header.num_vertexes = LittleLong(header.num_vertexes);
3337 header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3338 header.num_triangles = LittleLong(header.num_triangles);
3339 header.ofs_triangles = LittleLong(header.ofs_triangles);
3340 header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3341 header.num_joints = LittleLong(header.num_joints);
3342 header.ofs_joints = LittleLong(header.ofs_joints);
3343 header.num_poses = LittleLong(header.num_poses);
3344 header.ofs_poses = LittleLong(header.ofs_poses);
3345 header.num_anims = LittleLong(header.num_anims);
3346 header.ofs_anims = LittleLong(header.ofs_anims);
3347 header.num_frames = LittleLong(header.num_frames);
3348 header.num_framechannels = LittleLong(header.num_framechannels);
3349 header.ofs_frames = LittleLong(header.ofs_frames);
3350 header.ofs_bounds = LittleLong(header.ofs_bounds);
3351 header.num_comment = LittleLong(header.num_comment);
3352 header.ofs_comment = LittleLong(header.ofs_comment);
3353 header.num_extensions = LittleLong(header.num_extensions);
3354 header.ofs_extensions = LittleLong(header.ofs_extensions);
3356 if (header.version == 1)
3358 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3359 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3361 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3367 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3368 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3370 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3374 if (pbase + header.ofs_text + header.num_text > pend ||
3375 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3376 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3377 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3378 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3379 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3380 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3381 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3382 pbase + header.ofs_comment + header.num_comment > pend)
3384 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3388 // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3389 if (header.num_vertexarrays)
3390 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3391 if (header.num_anims)
3392 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3393 if (header.ofs_bounds)
3394 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3395 if (header.num_meshes)
3396 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3398 for (i = 0;i < (int)header.num_vertexarrays;i++)
3400 iqmvertexarray_t va;
3402 va.type = LittleLong(vas[i].type);
3403 va.flags = LittleLong(vas[i].flags);
3404 va.format = LittleLong(vas[i].format);
3405 va.size = LittleLong(vas[i].size);
3406 va.offset = LittleLong(vas[i].offset);
3407 vsize = header.num_vertexes*va.size;
3410 case IQM_FLOAT: vsize *= sizeof(float); break;
3411 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3414 if (pbase + va.offset + vsize > pend)
3416 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3420 if (va.format == IQM_FLOAT && va.size == 3)
3421 vposition = (const float *)(pbase + va.offset);
3424 if (va.format == IQM_FLOAT && va.size == 2)
3425 vtexcoord = (const float *)(pbase + va.offset);
3428 if (va.format == IQM_FLOAT && va.size == 3)
3429 vnormal = (const float *)(pbase + va.offset);
3432 if (va.format == IQM_FLOAT && va.size == 4)
3433 vtangent = (const float *)(pbase + va.offset);
3435 case IQM_BLENDINDEXES:
3436 if (va.format == IQM_UBYTE && va.size == 4)
3437 vblendindexes = (const unsigned char *)(pbase + va.offset);
3439 case IQM_BLENDWEIGHTS:
3440 if (va.format == IQM_UBYTE && va.size == 4)
3441 vblendweights = (const unsigned char *)(pbase + va.offset);
3444 if (va.format == IQM_FLOAT && va.size == 4)
3445 vcolor4f = (const float *)(pbase + va.offset);
3446 if (va.format == IQM_UBYTE && va.size == 4)
3447 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3451 if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3453 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3457 text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3459 loadmodel->DrawSky = NULL;
3460 loadmodel->DrawAddWaterPlanes = NULL;
3461 loadmodel->Draw = R_Q1BSP_Draw;
3462 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
3463 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
3464 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
3465 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
3466 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
3467 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
3468 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
3469 loadmodel->DrawLight = R_Q1BSP_DrawLight;
3470 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3471 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3472 loadmodel->PointSuperContents = NULL;
3473 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3475 // load external .skin files if present
3476 skinfiles = Mod_LoadSkinFiles();
3477 if (loadmodel->numskins < 1)
3478 loadmodel->numskins = 1;
3480 loadmodel->numframes = max(header.num_anims, 1);
3481 loadmodel->num_bones = header.num_joints;
3482 loadmodel->num_poses = max(header.num_frames, 1);
3483 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
3484 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3485 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3487 meshvertices = header.num_vertexes;
3488 meshtriangles = header.num_triangles;
3490 // do most allocations as one merged chunk
3491 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));
3492 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3493 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3494 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3495 loadmodel->surfmesh.num_vertices = meshvertices;
3496 loadmodel->surfmesh.num_triangles = meshtriangles;
3497 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3498 if (r_enableshadowvolumes.integer)
3500 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3502 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3503 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3504 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3505 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3506 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3507 if (vcolor4f || vcolor4ub)
3509 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3511 if (vblendindexes && vblendweights)
3513 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3514 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3516 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3517 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3518 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3519 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3520 if (vblendindexes && vblendweights)
3522 loadmodel->surfmesh.num_blends = 0;
3523 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3525 if (meshvertices <= 65536)
3527 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3529 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3530 if (vblendindexes && vblendweights)
3531 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3533 for (i = 0;i < loadmodel->numskins;i++)
3535 loadmodel->skinscenes[i].firstframe = i;
3536 loadmodel->skinscenes[i].framecount = 1;
3537 loadmodel->skinscenes[i].loop = true;
3538 loadmodel->skinscenes[i].framerate = 10;
3541 // load the bone info
3542 if (header.version == 1)
3544 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3545 if (loadmodel->num_bones)
3546 joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3547 for (i = 0;i < loadmodel->num_bones;i++)
3549 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3550 joint1[i].name = LittleLong(injoint1[i].name);
3551 joint1[i].parent = LittleLong(injoint1[i].parent);
3552 for (j = 0;j < 3;j++)
3554 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3555 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3556 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3558 strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3559 loadmodel->data_bones[i].parent = joint1[i].parent;
3560 if (loadmodel->data_bones[i].parent >= i)
3561 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3562 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]);
3563 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3564 if (loadmodel->data_bones[i].parent >= 0)
3566 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3567 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3568 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3570 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3575 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3576 if (header.num_joints)
3577 joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3578 for (i = 0;i < loadmodel->num_bones;i++)
3580 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3581 joint[i].name = LittleLong(injoint[i].name);
3582 joint[i].parent = LittleLong(injoint[i].parent);
3583 for (j = 0;j < 3;j++)
3585 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3586 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3587 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3589 joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3590 strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3591 loadmodel->data_bones[i].parent = joint[i].parent;
3592 if (loadmodel->data_bones[i].parent >= i)
3593 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3594 if (joint[i].rotation[3] > 0)
3595 Vector4Negate(joint[i].rotation, joint[i].rotation);
3596 Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3597 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]);
3598 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3599 if (loadmodel->data_bones[i].parent >= 0)
3601 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3602 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3603 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3605 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3609 // set up the animscenes based on the anims
3610 for (i = 0;i < (int)header.num_anims;i++)
3613 anim.name = LittleLong(anims[i].name);
3614 anim.first_frame = LittleLong(anims[i].first_frame);
3615 anim.num_frames = LittleLong(anims[i].num_frames);
3616 anim.framerate = LittleFloat(anims[i].framerate);
3617 anim.flags = LittleLong(anims[i].flags);
3618 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3619 loadmodel->animscenes[i].firstframe = anim.first_frame;
3620 loadmodel->animscenes[i].framecount = anim.num_frames;
3621 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3622 loadmodel->animscenes[i].framerate = anim.framerate;
3624 if (header.num_anims <= 0)
3626 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3627 loadmodel->animscenes[0].firstframe = 0;
3628 loadmodel->animscenes[0].framecount = 1;
3629 loadmodel->animscenes[0].loop = true;
3630 loadmodel->animscenes[0].framerate = 10;
3633 loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3634 if(mod_alias_force_animated.string[0])
3635 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3638 if (header.version == 1)
3640 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3641 if (header.num_poses)
3642 pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3643 for (i = 0;i < (int)header.num_poses;i++)
3646 pose1[i].parent = LittleLong(inpose1[i].parent);
3647 pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3648 for (j = 0;j < 9;j++)
3650 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3651 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3653 f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3654 f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3655 f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3656 f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3657 f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3658 f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3660 if (header.num_frames <= 0)
3662 for (i = 0;i < loadmodel->num_bones;i++)
3665 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3666 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3667 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3673 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3674 if (header.num_poses)
3675 pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3676 for (i = 0;i < (int)header.num_poses;i++)
3679 pose[i].parent = LittleLong(inpose[i].parent);
3680 pose[i].channelmask = LittleLong(inpose[i].channelmask);
3681 for (j = 0;j < 10;j++)
3683 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3684 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3686 f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3687 f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3688 f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3689 f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3690 f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3691 f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3693 if (header.num_frames <= 0)
3695 for (i = 0;i < loadmodel->num_bones;i++)
3698 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3699 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3700 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3704 loadmodel->num_posescale = biggestorigin / 32767.0f;
3705 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3707 // load the pose data
3708 // this unaligned memory access is safe (LittleShort reads as bytes)
3709 framedata = (const unsigned short *)(pbase + header.ofs_frames);
3710 if (header.version == 1)
3712 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3714 for (j = 0;j < (int)header.num_poses;j++, k++)
3716 float qx, qy, qz, qw;
3717 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));
3718 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));
3719 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));
3720 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3721 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3722 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3723 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3724 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3725 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3726 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3727 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3728 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3729 // skip scale data for now
3730 if(pose1[j].channelmask&64) framedata++;
3731 if(pose1[j].channelmask&128) framedata++;
3732 if(pose1[j].channelmask&256) framedata++;
3735 if (header.num_frames <= 0)
3737 for (i = 0;i < loadmodel->num_bones;i++)
3739 float qx, qy, qz, qw;
3740 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3741 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3742 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3743 qx = joint1[i].rotation[0];
3744 qy = joint1[i].rotation[1];
3745 qz = joint1[i].rotation[2];
3746 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3747 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3748 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3749 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3750 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3751 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3757 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3759 for (j = 0;j < (int)header.num_poses;j++, k++)
3762 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));
3763 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));
3764 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));
3765 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3766 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3767 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3768 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3770 Vector4Negate(rot, rot);
3771 Vector4Normalize2(rot, rot);
3772 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3773 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3774 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3775 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3776 // skip scale data for now
3777 if(pose[j].channelmask&128) framedata++;
3778 if(pose[j].channelmask&256) framedata++;
3779 if(pose[j].channelmask&512) framedata++;
3782 if (header.num_frames <= 0)
3784 for (i = 0;i < loadmodel->num_bones;i++)
3786 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3787 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3788 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3789 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3790 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3791 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3792 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3797 // load bounding box data
3798 if (header.ofs_bounds)
3800 float xyradius = 0, radius = 0;
3801 VectorClear(loadmodel->normalmins);
3802 VectorClear(loadmodel->normalmaxs);
3803 for (i = 0; i < (int)header.num_frames;i++)
3806 bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3807 bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3808 bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3809 bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);
3810 bound.maxs[1] = LittleFloat(bounds[i].maxs[1]);
3811 bound.maxs[2] = LittleFloat(bounds[i].maxs[2]);
3812 bound.xyradius = LittleFloat(bounds[i].xyradius);
3813 bound.radius = LittleFloat(bounds[i].radius);
3816 VectorCopy(bound.mins, loadmodel->normalmins);
3817 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3821 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3822 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3823 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3824 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3825 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3826 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3828 if (bound.xyradius > xyradius)
3829 xyradius = bound.xyradius;
3830 if (bound.radius > radius)
3831 radius = bound.radius;
3833 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3834 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3835 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3836 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3837 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3838 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3839 loadmodel->radius = radius;
3840 loadmodel->radius2 = radius * radius;
3843 // load triangle data
3844 // this unaligned memory access is safe (LittleLong reads as bytes)
3845 inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3846 outelements = loadmodel->surfmesh.data_element3i;
3847 for (i = 0;i < (int)header.num_triangles;i++)
3849 outelements[0] = LittleLong(inelements[0]);
3850 outelements[1] = LittleLong(inelements[1]);
3851 outelements[2] = LittleLong(inelements[2]);
3855 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3857 if (header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
3859 // this unaligned memory access is safe (LittleLong reads as bytes)
3860 inneighbors = (const int *)(pbase + header.ofs_neighbors);
3861 outneighbors = loadmodel->surfmesh.data_neighbor3i;
3862 for (i = 0;i < (int)header.num_triangles;i++)
3864 outneighbors[0] = LittleLong(inneighbors[0]);
3865 outneighbors[1] = LittleLong(inneighbors[1]);
3866 outneighbors[2] = LittleLong(inneighbors[2]);
3873 // this unaligned memory access is safe (LittleFloat reads as bytes)
3874 outvertex = loadmodel->surfmesh.data_vertex3f;
3875 for (i = 0;i < (int)header.num_vertexes;i++)
3877 outvertex[0] = LittleFloat(vposition[0]);
3878 outvertex[1] = LittleFloat(vposition[1]);
3879 outvertex[2] = LittleFloat(vposition[2]);
3884 outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3885 // this unaligned memory access is safe (LittleFloat reads as bytes)
3886 for (i = 0;i < (int)header.num_vertexes;i++)
3888 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3889 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3894 // this unaligned memory access is safe (LittleFloat reads as bytes)
3897 outnormal = loadmodel->surfmesh.data_normal3f;
3898 for (i = 0;i < (int)header.num_vertexes;i++)
3900 outnormal[0] = LittleFloat(vnormal[0]);
3901 outnormal[1] = LittleFloat(vnormal[1]);
3902 outnormal[2] = LittleFloat(vnormal[2]);
3908 // this unaligned memory access is safe (LittleFloat reads as bytes)
3909 if(vnormal && vtangent)
3911 outnormal = loadmodel->surfmesh.data_normal3f;
3912 outsvector = loadmodel->surfmesh.data_svector3f;
3913 outtvector = loadmodel->surfmesh.data_tvector3f;
3914 for (i = 0;i < (int)header.num_vertexes;i++)
3916 outsvector[0] = LittleFloat(vtangent[0]);
3917 outsvector[1] = LittleFloat(vtangent[1]);
3918 outsvector[2] = LittleFloat(vtangent[2]);
3919 if(LittleFloat(vtangent[3]) < 0)
3920 CrossProduct(outsvector, outnormal, outtvector);
3922 CrossProduct(outnormal, outsvector, outtvector);
3930 // this unaligned memory access is safe (all bytes)
3931 if (vblendindexes && vblendweights)
3933 for (i = 0; i < (int)header.num_vertexes;i++)
3935 blendweights_t weights;
3936 memcpy(weights.index, vblendindexes + i*4, 4);
3937 memcpy(weights.influence, vblendweights + i*4, 4);
3938 loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3939 loadmodel->surfmesh.data_skeletalindex4ub[i*4 ] = weights.index[0];
3940 loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3941 loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3942 loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3943 loadmodel->surfmesh.data_skeletalweight4ub[i*4 ] = weights.influence[0];
3944 loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3945 loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3946 loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3952 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3953 // this unaligned memory access is safe (LittleFloat reads as bytes)
3954 for (i = 0;i < (int)header.num_vertexes;i++)
3956 outcolor[0] = LittleFloat(vcolor4f[0]);
3957 outcolor[1] = LittleFloat(vcolor4f[1]);
3958 outcolor[2] = LittleFloat(vcolor4f[2]);
3959 outcolor[3] = LittleFloat(vcolor4f[3]);
3966 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3967 // this unaligned memory access is safe (all bytes)
3968 for (i = 0;i < (int)header.num_vertexes;i++)
3970 outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3971 outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3972 outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3973 outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3980 for (i = 0;i < (int)header.num_meshes;i++)
3983 msurface_t *surface;
3985 mesh.name = LittleLong(meshes[i].name);
3986 mesh.material = LittleLong(meshes[i].material);
3987 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3988 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3989 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3990 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3992 loadmodel->sortedmodelsurfaces[i] = i;
3993 surface = loadmodel->data_surfaces + i;
3994 surface->texture = loadmodel->data_textures + i;
3995 surface->num_firsttriangle = mesh.first_triangle;
3996 surface->num_triangles = mesh.num_triangles;
3997 surface->num_firstvertex = mesh.first_vertex;
3998 surface->num_vertices = mesh.num_vertexes;
4000 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
4003 Mod_FreeSkinFiles(skinfiles);
4004 Mod_MakeSortedSurfaces(loadmodel);
4006 // compute all the mesh information that was not loaded from the file
4007 if (loadmodel->surfmesh.data_element3s)
4008 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
4009 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
4011 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);
4012 if (!vnormal || !vtangent)
4013 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);
4014 if (!header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
4015 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
4016 if (!header.ofs_bounds)
4017 Mod_Alias_CalculateBoundingBox();
4019 if (!loadmodel->surfmesh.isanimated && loadmodel->surfmesh.num_triangles >= 1)
4021 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
4022 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
4023 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
4024 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
4025 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
4026 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
4029 if (joint ) Mem_Free(joint );joint = NULL;
4030 if (joint1 ) Mem_Free(joint1 );joint1 = NULL;
4031 if (pose ) Mem_Free(pose );pose = NULL;
4032 if (pose1 ) Mem_Free(pose1 );pose1 = NULL;
4034 // because shaders can do somewhat unexpected things, check for unusual features now
4035 for (i = 0;i < loadmodel->num_textures;i++)
4037 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
4038 mod->DrawSky = R_Q1BSP_DrawSky;
4039 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
4040 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;