]> git.xonotic.org Git - xonotic/darkplaces.git/blob - model_alias.c
physics: fix and refactor unsticking
[xonotic/darkplaces.git] / model_alias.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20
21 #include "quakedef.h"
22 #include "image.h"
23 #include "r_shadow.h"
24 #include "mod_skeletal_animatevertices_generic.h"
25 #ifdef SSE_POSSIBLE
26 #include "mod_skeletal_animatevertices_sse.h"
27 #endif
28
29 #ifdef SSE_POSSIBLE
30 static qbool r_skeletal_use_sse_defined = false;
31 cvar_t r_skeletal_use_sse = {CF_CLIENT, "r_skeletal_use_sse", "1", "use SSE for skeletal model animation"};
32 #endif
33 cvar_t r_skeletal_debugbone = {CF_CLIENT, "r_skeletal_debugbone", "-1", "development cvar for testing skeletal model code"};
34 cvar_t r_skeletal_debugbonecomponent = {CF_CLIENT, "r_skeletal_debugbonecomponent", "3", "development cvar for testing skeletal model code"};
35 cvar_t r_skeletal_debugbonevalue = {CF_CLIENT, "r_skeletal_debugbonevalue", "100", "development cvar for testing skeletal model code"};
36 cvar_t r_skeletal_debugtranslatex = {CF_CLIENT, "r_skeletal_debugtranslatex", "1", "development cvar for testing skeletal model code"};
37 cvar_t r_skeletal_debugtranslatey = {CF_CLIENT, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"};
38 cvar_t r_skeletal_debugtranslatez = {CF_CLIENT, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"};
39 cvar_t mod_alias_supporttagscale = {CF_CLIENT | CF_SERVER, "mod_alias_supporttagscale", "1", "support scaling factors in bone/tag attachment matrices as supported by MD3"};
40 cvar_t mod_alias_force_animated = {CF_CLIENT | CF_SERVER, "mod_alias_force_animated", "", "if set to an non-empty string, overrides the is-animated flag of any alias models (for benchmarking)"};
41
42 float mod_md3_sin[320];
43
44 static size_t Mod_Skeletal_AnimateVertices_maxbonepose = 0;
45 static void *Mod_Skeletal_AnimateVertices_bonepose = NULL;
46 void Mod_Skeletal_FreeBuffers(void)
47 {
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;
52 }
53 void *Mod_Skeletal_AnimateVertices_AllocBuffers(size_t nbytes)
54 {
55         if(Mod_Skeletal_AnimateVertices_maxbonepose < nbytes)
56         {
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;
61         }
62         return Mod_Skeletal_AnimateVertices_bonepose;
63 }
64
65 void Mod_Skeletal_BuildTransforms(const model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT bonepose, float * RESTRICT boneposerelative)
66 {
67         int i, blends;
68         float m[12];
69
70         if (!bonepose)
71                 bonepose = (float * RESTRICT) Mod_Skeletal_AnimateVertices_AllocBuffers(sizeof(float[12]) * model->num_bones);
72                 
73         if (skeleton && !skeleton->relativetransforms)
74                 skeleton = NULL;
75
76         // interpolate matrices
77         if (skeleton)
78         {
79                 for (i = 0;i < model->num_bones;i++)
80                 {
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);
84                         else
85                                 memcpy(bonepose + i * 12, m, sizeof(m));
86
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);
90                 }
91         }
92         else
93         {
94                 for (i = 0;i < model->num_bones;i++)
95                 {
96                         // blend by transform each quaternion/translation into a dual-quaternion first, then blending
97                         const short * RESTRICT firstpose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i);
98                         float firstlerp = frameblend[0].lerp,
99                                 firsttx = firstpose7s[0], firstty = firstpose7s[1], firsttz = firstpose7s[2],
100                                 rx = firstpose7s[3] * firstlerp,
101                                 ry = firstpose7s[4] * firstlerp,
102                                 rz = firstpose7s[5] * firstlerp,
103                                 rw = firstpose7s[6] * firstlerp,
104                                 dx = firsttx*rw + firstty*rz - firsttz*ry,
105                                 dy = -firsttx*rz + firstty*rw + firsttz*rx,
106                                 dz = firsttx*ry - firstty*rx + firsttz*rw,
107                                 dw = -firsttx*rx - firstty*ry - firsttz*rz,
108                                 scale, sx, sy, sz, sw;
109                         for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
110                         {
111                                 const short * RESTRICT blendpose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i);
112                                 float blendlerp = frameblend[blends].lerp,
113                                         blendtx = blendpose7s[0], blendty = blendpose7s[1], blendtz = blendpose7s[2],
114                                         qx = blendpose7s[3], qy = blendpose7s[4], qz = blendpose7s[5], qw = blendpose7s[6];
115                                 if(rx*qx + ry*qy + rz*qz + rw*qw < 0) blendlerp = -blendlerp;
116                                 qx *= blendlerp;
117                                 qy *= blendlerp;
118                                 qz *= blendlerp;
119                                 qw *= blendlerp;
120                                 rx += qx;
121                                 ry += qy;
122                                 rz += qz;
123                                 rw += qw;
124                                 dx += blendtx*qw + blendty*qz - blendtz*qy;
125                                 dy += -blendtx*qz + blendty*qw + blendtz*qx;
126                                 dz += blendtx*qy - blendty*qx + blendtz*qw;
127                                 dw += -blendtx*qx - blendty*qy - blendtz*qz;
128                         }
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);
131                         sx = rx * scale;
132                         sy = ry * scale;
133                         sz = rz * scale;
134                         sw = rw * scale;
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);
154                         else
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);
159                 }
160         }
161 }
162
163 static void Mod_Skeletal_AnimateVertices(const 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)
164 {
165
166         if (!model->surfmesh.num_vertices)
167                 return;
168
169         if (!model->num_bones)
170         {
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]));
175                 return;
176         }
177
178 #ifdef SSE_POSSIBLE
179         if(r_skeletal_use_sse_defined)
180                 if(r_skeletal_use_sse.integer)
181                 {
182                         Mod_Skeletal_AnimateVertices_SSE(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
183                         return;
184                 }
185 #endif
186         Mod_Skeletal_AnimateVertices_Generic(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
187 }
188
189 void Mod_AliasInit (void)
190 {
191         int i;
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);
202 #ifdef SSE_POSSIBLE
203         if(Sys_HaveSSE())
204         {
205                 Con_Printf("Skeletal animation uses SSE code path\n");
206                 r_skeletal_use_sse_defined = true;
207                 Cvar_RegisterVariable(&r_skeletal_use_sse);
208         }
209         else
210                 Con_Printf("Skeletal animation uses generic code path (SSE disabled or not detected)\n");
211 #else
212         Con_Printf("Skeletal animation uses generic code path (SSE not compiled in)\n");
213 #endif
214 }
215
216 static int Mod_Skeletal_AddBlend(model_t *model, const blendweights_t *newweights)
217 {
218         int i;
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++)
224         {
225                 if (!memcmp(weights, newweights, sizeof(blendweights_t)))
226                         return model->num_bones + i;
227         }
228         model->surfmesh.num_blends++;
229         memcpy(weights, newweights, sizeof(blendweights_t));
230         return model->num_bones + i;
231 }
232
233 static int Mod_Skeletal_CompressBlend(model_t *model, const int *newindex, const float *newinfluence)
234 {
235         int i, total;
236         float scale;
237         blendweights_t newweights;
238         if(!newinfluence[1])
239                 return newindex[0];
240         scale = 0;
241         for (i = 0;i < 4;i++)
242                 scale += newinfluence[i];
243         scale = 255.0f / scale;
244         total = 0;
245         for (i = 0;i < 4;i++)
246         {
247                 newweights.index[i] = newindex[i];
248                 newweights.influence[i] = (unsigned char)(newinfluence[i] * scale);
249                 total += newweights.influence[i];
250         }       
251         while (total > 255)
252         {
253                 for (i = 0;i < 4;i++)
254                 {
255                         if(newweights.influence[i] > 0 && total > 255) 
256                         { 
257                                 newweights.influence[i]--;
258                                 total--; 
259                         }
260                 }
261         }
262         while (total < 255)
263         {
264                 for (i = 0; i < 4;i++)
265                 {
266                         if(newweights.influence[i] < 255 && total < 255) 
267                         { 
268                                 newweights.influence[i]++; 
269                                 total++; 
270                         }
271                 }
272         }
273         return Mod_Skeletal_AddBlend(model, &newweights);
274 }
275
276 static void Mod_MD3_AnimateVertices(const 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)
277 {
278         // vertex morph
279         int i, numblends, blendnum;
280         int numverts = model->surfmesh.num_vertices;
281         numblends = 0;
282         for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
283         {
284                 //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate);
285                 if (frameblend[blendnum].lerp > 0)
286                         numblends = blendnum + 1;
287         }
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++)
290         {
291                 const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].subframe;
292                 if (vertex3f)
293                 {
294                         float scale = frameblend[blendnum].lerp * (1.0f / 64.0f);
295                         if (blendnum == 0)
296                         {
297                                 for (i = 0;i < numverts;i++)
298                                 {
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;
302                                 }
303                         }
304                         else
305                         {
306                                 for (i = 0;i < numverts;i++)
307                                 {
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;
311                                 }
312                         }
313                 }
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.
319                 if (normal3f)
320                 {
321                         float lerp = frameblend[blendnum].lerp;
322                         if (blendnum == 0)
323                         {
324                                 for (i = 0;i < numverts;i++)
325                                 {
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;
329                                 }
330                         }
331                         else
332                         {
333                                 for (i = 0;i < numverts;i++)
334                                 {
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;
338                                 }
339                         }
340                 }
341                 if (svector3f)
342                 {
343                         const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
344                         float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
345                         if (blendnum == 0)
346                         {
347                                 for (i = 0;i < numverts;i++, texvecvert++)
348                                 {
349                                         VectorScale(texvecvert->svec, f, svector3f + i*3);
350                                         VectorScale(texvecvert->tvec, f, tvector3f + i*3);
351                                 }
352                         }
353                         else
354                         {
355                                 for (i = 0;i < numverts;i++, texvecvert++)
356                                 {
357                                         VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
358                                         VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
359                                 }
360                         }
361                 }
362         }
363 }
364 static void Mod_MDL_AnimateVertices(const 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)
365 {
366         // vertex morph
367         int i, numblends, blendnum;
368         int numverts = model->surfmesh.num_vertices;
369         float translate[3];
370         VectorClear(translate);
371         numblends = 0;
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++)
375         {
376                 if (model->surfmesh.data_morphmd2framesize6f)
377                         VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6 + 3, translate);
378                 else
379                         VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate);
380                 if (frameblend[blendnum].lerp > 0)
381                         numblends = blendnum + 1;
382         }
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++)
385         {
386                 const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].subframe;
387                 if (vertex3f)
388                 {
389                         float scale[3];
390                         if (model->surfmesh.data_morphmd2framesize6f)
391                                 VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6, frameblend[blendnum].lerp, scale);
392                         else
393                                 VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale);
394                         if (blendnum == 0)
395                         {
396                                 for (i = 0;i < numverts;i++)
397                                 {
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];
401                                 }
402                         }
403                         else
404                         {
405                                 for (i = 0;i < numverts;i++)
406                                 {
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];
410                                 }
411                         }
412                 }
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
417                 if (normal3f)
418                 {
419                         float lerp = frameblend[blendnum].lerp;
420                         if (blendnum == 0)
421                         {
422                                 for (i = 0;i < numverts;i++)
423                                 {
424                                         const float *vn = m_bytenormals[verts[i].lightnormalindex];
425                                         VectorScale(vn, lerp, normal3f + i*3);
426                                 }
427                         }
428                         else
429                         {
430                                 for (i = 0;i < numverts;i++)
431                                 {
432                                         const float *vn = m_bytenormals[verts[i].lightnormalindex];
433                                         VectorMA(normal3f + i*3, lerp, vn, normal3f + i*3);
434                                 }
435                         }
436                 }
437                 if (svector3f)
438                 {
439                         const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
440                         float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
441                         if (blendnum == 0)
442                         {
443                                 for (i = 0;i < numverts;i++, texvecvert++)
444                                 {
445                                         VectorScale(texvecvert->svec, f, svector3f + i*3);
446                                         VectorScale(texvecvert->tvec, f, tvector3f + i*3);
447                                 }
448                         }
449                         else
450                         {
451                                 for (i = 0;i < numverts;i++, texvecvert++)
452                                 {
453                                         VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
454                                         VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
455                                 }
456                         }
457                 }
458         }
459 }
460
461 int Mod_Alias_GetTagMatrix(const model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, matrix4x4_t *outmatrix)
462 {
463         matrix4x4_t temp;
464         matrix4x4_t parentbonematrix;
465         matrix4x4_t tempbonematrix;
466         matrix4x4_t bonematrix;
467         matrix4x4_t blendmatrix;
468         int blendindex;
469         int parenttagindex;
470         int k;
471         float lerp;
472         const float *input;
473         float blendtag[12];
474         *outmatrix = identitymatrix;
475         if (skeleton && skeleton->relativetransforms)
476         {
477                 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
478                         return 4;
479                 *outmatrix = skeleton->relativetransforms[tagindex];
480                 while ((tagindex = model->data_bones[tagindex].parent) >= 0)
481                 {
482                         temp = *outmatrix;
483                         Matrix4x4_Concat(outmatrix, &skeleton->relativetransforms[tagindex], &temp);
484                 }
485         }
486         else if (model->num_bones)
487         {
488                 if (tagindex < 0 || tagindex >= model->num_bones)
489                         return 4;
490                 Matrix4x4_Clear(&blendmatrix);
491                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
492                 {
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)
497                         {
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);
501                         }
502                         Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
503                 }
504                 *outmatrix = blendmatrix;
505         }
506         else if (model->num_tags)
507         {
508                 if (tagindex < 0 || tagindex >= model->num_tags)
509                         return 4;
510                 for (k = 0;k < 12;k++)
511                         blendtag[k] = 0;
512                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
513                 {
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;
518                 }
519                 Matrix4x4_FromArray12FloatGL(outmatrix, blendtag);
520         }
521
522         if(!mod_alias_supporttagscale.integer)
523                 Matrix4x4_Normalize3(outmatrix, outmatrix);
524
525         return 0;
526 }
527
528 int Mod_Alias_GetExtendedTagInfoForIndex(const 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)
529 {
530         int blendindex;
531         int k;
532         float lerp;
533         matrix4x4_t bonematrix;
534         matrix4x4_t blendmatrix;
535         const float *input;
536         float blendtag[12];
537
538         if (skeleton && skeleton->relativetransforms)
539         {
540                 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
541                         return 1;
542                 *parentindex = skeleton->model->data_bones[tagindex].parent;
543                 *tagname = skeleton->model->data_bones[tagindex].name;
544                 *tag_localmatrix = skeleton->relativetransforms[tagindex];
545                 return 0;
546         }
547         else if (model->num_bones)
548         {
549                 if (tagindex < 0 || tagindex >= model->num_bones)
550                         return 1;
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++)
555                 {
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);
559                 }
560                 *tag_localmatrix = blendmatrix;
561                 return 0;
562         }
563         else if (model->num_tags)
564         {
565                 if (tagindex < 0 || tagindex >= model->num_tags)
566                         return 1;
567                 *parentindex = -1;
568                 *tagname = model->data_tags[tagindex].name;
569                 for (k = 0;k < 12;k++)
570                         blendtag[k] = 0;
571                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
572                 {
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;
577                 }
578                 Matrix4x4_FromArray12FloatGL(tag_localmatrix, blendtag);
579                 return 0;
580         }
581
582         return 2;
583 }
584
585 int Mod_Alias_GetTagIndexForName(const model_t *model, unsigned int skin, const char *tagname)
586 {
587         int i;
588         if(skin >= (unsigned int)model->numskins)
589                 skin = 0;
590         if (model->num_bones)
591                 for (i = 0;i < model->num_bones;i++)
592                         if (!strcasecmp(tagname, model->data_bones[i].name))
593                                 return i + 1;
594         if (model->num_tags)
595                 for (i = 0;i < model->num_tags;i++)
596                         if (!strcasecmp(tagname, model->data_tags[i].name))
597                                 return i + 1;
598         return 0;
599 }
600
601 static void Mod_BuildBaseBonePoses(void)
602 {
603         int boneindex;
604         matrix4x4_t *basebonepose;
605         float *outinvmatrix = loadmodel->data_baseboneposeinverse;
606         matrix4x4_t bonematrix;
607         matrix4x4_t tempbonematrix;
608         if (!loadmodel->num_bones)
609                 return;
610         basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
611         for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
612         {
613                 Matrix4x4_FromBonePose7s(&bonematrix, loadmodel->num_posescale, loadmodel->data_poses7s + 7 * boneindex);
614                 if (loadmodel->data_bones[boneindex].parent >= 0)
615                 {
616                         tempbonematrix = bonematrix;
617                         Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
618                 }
619                 basebonepose[boneindex] = bonematrix;
620                 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
621                 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
622         }
623         Mem_Free(basebonepose);
624 }
625
626 static qbool Mod_Alias_CalculateBoundingBox(void)
627 {
628         int vnum;
629         qbool firstvertex = true;
630         float dist, yawradius, radius;
631         float *v;
632         qbool isanimated = false;
633         VectorClear(loadmodel->normalmins);
634         VectorClear(loadmodel->normalmaxs);
635         yawradius = 0;
636         radius = 0;
637         if (loadmodel->AnimateVertices)
638         {
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);
644                 refvertex3f = NULL;
645                 for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
646                 {
647                         loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL);
648                         if (!refvertex3f)
649                         {
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]));
653                         }
654                         else
655                         {
656                                 if (!isanimated && memcmp(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3])))
657                                         isanimated = true;
658                         }
659                         for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
660                         {
661                                 if (firstvertex)
662                                 {
663                                         firstvertex = false;
664                                         VectorCopy(v, loadmodel->normalmins);
665                                         VectorCopy(v, loadmodel->normalmaxs);
666                                 }
667                                 else
668                                 {
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];
675                                 }
676                                 dist = v[0] * v[0] + v[1] * v[1];
677                                 if (yawradius < dist)
678                                         yawradius = dist;
679                                 dist += v[2] * v[2];
680                                 if (radius < dist)
681                                         radius = dist;
682                         }
683                 }
684                 if (vertex3f)
685                         Mem_Free(vertex3f);
686         }
687         else
688         {
689                 for (vnum = 0, v = loadmodel->surfmesh.data_vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
690                 {
691                         if (firstvertex)
692                         {
693                                 firstvertex = false;
694                                 VectorCopy(v, loadmodel->normalmins);
695                                 VectorCopy(v, loadmodel->normalmaxs);
696                         }
697                         else
698                         {
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];
705                         }
706                         dist = v[0] * v[0] + v[1] * v[1];
707                         if (yawradius < dist)
708                                 yawradius = dist;
709                         dist += v[2] * v[2];
710                         if (radius < dist)
711                                 radius = dist;
712                 }
713         }
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;
724         return isanimated;
725 }
726
727 static void Mod_Alias_MorphMesh_CompileFrames(void)
728 {
729         int i, j;
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--)
742         {
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++)
748                 {
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);
751                 }
752         }
753 }
754
755 static void Mod_MDLMD2MD3_TraceLine(model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
756 {
757         int i;
758         float segmentmins[3], segmentmaxs[3];
759         msurface_t *surface;
760         float vertex3fbuf[1024 * 3];
761         float *vertex3f = vertex3fbuf;
762         float *freevertex3f = NULL;
763         // for static cases we can just call CollisionBIH which is much faster
764         if ((frameblend == NULL || (frameblend[0].subframe == 0 && frameblend[1].lerp == 0)) && (skeleton == NULL || skeleton->relativetransforms == NULL))
765         {
766                 Mod_CollisionBIH_TraceLine(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
767                 return;
768         }
769         memset(trace, 0, sizeof(*trace));
770         trace->fraction = 1;
771         trace->hitsupercontentsmask = hitsupercontentsmask;
772         trace->skipsupercontentsmask = skipsupercontentsmask;
773         trace->skipmaterialflagsmask = skipmaterialflagsmask;
774         segmentmins[0] = min(start[0], end[0]) - 1;
775         segmentmins[1] = min(start[1], end[1]) - 1;
776         segmentmins[2] = min(start[2], end[2]) - 1;
777         segmentmaxs[0] = max(start[0], end[0]) + 1;
778         segmentmaxs[1] = max(start[1], end[1]) + 1;
779         segmentmaxs[2] = max(start[2], end[2]) + 1;
780         if (frameblend == NULL || frameblend[0].subframe != 0 || frameblend[0].lerp != 0 || skeleton != NULL)
781         {
782                 if (model->surfmesh.num_vertices > 1024)
783                         vertex3f = freevertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
784                 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
785         }
786         else
787                 vertex3f = model->surfmesh.data_vertex3f;
788         for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
789                 Collision_TraceLineTriangleMeshFloat(trace, start, end, surface->num_triangles, model->surfmesh.data_element3i + 3 * surface->num_firsttriangle, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
790         if (freevertex3f)
791                 Mem_Free(freevertex3f);
792 }
793
794 static void Mod_MDLMD2MD3_TraceBox(model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
795 {
796         int i;
797         vec3_t shiftstart, shiftend;
798         float segmentmins[3], segmentmaxs[3];
799         msurface_t *surface;
800         float vertex3fbuf[1024*3];
801         float *vertex3f = vertex3fbuf;
802         colboxbrushf_t thisbrush_start, thisbrush_end;
803         vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
804
805         if (VectorCompare(boxmins, boxmaxs))
806         {
807                 VectorAdd(start, boxmins, shiftstart);
808                 VectorAdd(end, boxmins, shiftend);
809                 Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
810                 VectorSubtract(trace->endpos, boxmins, trace->endpos);
811                 return;
812         }
813
814         // for static cases we can just call CollisionBIH which is much faster
815         if ((frameblend == NULL || (frameblend[0].subframe == 0 && frameblend[1].lerp == 0)) && (skeleton == NULL || skeleton->relativetransforms == NULL))
816         {
817                 Mod_CollisionBIH_TraceBox(model, frameblend, skeleton, trace, start, boxmins, boxmaxs, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
818                 return;
819         }
820
821         // box trace, performed as brush trace
822         memset(trace, 0, sizeof(*trace));
823         trace->fraction = 1;
824         trace->hitsupercontentsmask = hitsupercontentsmask;
825         trace->skipsupercontentsmask = skipsupercontentsmask;
826         trace->skipmaterialflagsmask = skipmaterialflagsmask;
827         if (model->surfmesh.num_vertices > 1024)
828                 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
829         segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
830         segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
831         segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
832         segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
833         segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
834         segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
835         VectorAdd(start, boxmins, boxstartmins);
836         VectorAdd(start, boxmaxs, boxstartmaxs);
837         VectorAdd(end, boxmins, boxendmins);
838         VectorAdd(end, boxmaxs, boxendmaxs);
839         Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL);
840         Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL);
841         model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
842         for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
843                 Collision_TraceBrushTriangleMeshFloat(trace, &thisbrush_start.brush, &thisbrush_end.brush, surface->num_triangles, model->surfmesh.data_element3i + 3 * surface->num_firsttriangle, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
844         if (vertex3f != vertex3fbuf)
845                 Mem_Free(vertex3f);
846 }
847
848 static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
849 {
850         int i, j;
851         for (i = 0;i < inverts;i++)
852         {
853                 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
854                         continue;
855                 j = vertremap[i]; // not onseam
856                 if (j >= 0)
857                         out[j] = v[i];
858                 j = vertremap[i+inverts]; // onseam
859                 if (j >= 0)
860                         out[j] = v[i];
861         }
862 }
863
864 static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
865 {
866         int i, f, pose, groupframes;
867         float interval;
868         daliasframetype_t *pframetype;
869         daliasframe_t *pinframe;
870         daliasgroup_t *group;
871         daliasinterval_t *intervals;
872         animscene_t *scene;
873         pose = 0;
874         scene = loadmodel->animscenes;
875         for (f = 0;f < loadmodel->numframes;f++)
876         {
877                 pframetype = (daliasframetype_t *)datapointer;
878                 datapointer += sizeof(daliasframetype_t);
879                 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
880                 {
881                         // a single frame is still treated as a group
882                         interval = 0.1f;
883                         groupframes = 1;
884                 }
885                 else
886                 {
887                         // read group header
888                         group = (daliasgroup_t *)datapointer;
889                         datapointer += sizeof(daliasgroup_t);
890                         groupframes = LittleLong (group->numframes);
891
892                         // intervals (time per frame)
893                         intervals = (daliasinterval_t *)datapointer;
894                         datapointer += sizeof(daliasinterval_t) * groupframes;
895
896                         interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
897                         if (interval < 0.01f)
898                         {
899                                 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
900                                 interval = 0.1f;
901                         }
902                 }
903
904                 // get scene name from first frame
905                 pinframe = (daliasframe_t *)datapointer;
906
907                 dp_strlcpy(scene->name, pinframe->name, sizeof(scene->name));
908                 scene->firstframe = pose;
909                 scene->framecount = groupframes;
910                 scene->framerate = 1.0f / interval;
911                 scene->loop = true;
912                 scene++;
913
914                 // read frames
915                 for (i = 0;i < groupframes;i++)
916                 {
917                         datapointer += sizeof(daliasframe_t);
918                         Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
919                         datapointer += sizeof(trivertx_t) * inverts;
920                         pose++;
921                 }
922         }
923 }
924
925 void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
926 {
927         int i;
928         char stripbuf[MAX_QPATH];
929         skinfileitem_t *skinfileitem;
930         if(developer_extra.integer)
931                 Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername);
932         if (skinfile)
933         {
934                 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
935                 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
936                 {
937                         memset(skin, 0, sizeof(*skin));
938                         // see if a mesh
939                         for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
940                         {
941                                 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
942                                 if (!strcmp(skinfileitem->name, meshname))
943                                 {
944                                         Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
945                                         if(developer_extra.integer)
946                                                 Con_DPrintf("--> got %s from skin file\n", stripbuf);
947                                         Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
948                                         break;
949                                 }
950                         }
951                         if (!skinfileitem)
952                         {
953                                 // don't render unmentioned meshes
954                                 Mod_LoadCustomMaterial(loadmodel->mempool, skin, meshname, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
955                                 if(developer_extra.integer)
956                                         Con_DPrintf("--> skipping\n");
957                                 skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
958                         }
959                 }
960         }
961         else
962         {
963                 if(developer_extra.integer)
964                         Con_DPrintf("--> using default\n");
965                 Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
966                 Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
967         }
968 }
969 extern cvar_t r_nolerp_list;
970 #define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)", loadmodel->name, VALUE, MIN, MAX);
971 #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)", loadmodel->name, VALUE, MIN, MAX);
972 void Mod_IDP0_Load(model_t *mod, void *buffer, void *bufferend)
973 {
974         int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
975         float scales, scalet, interval;
976         msurface_t *surface;
977         unsigned char *data;
978         mdl_t *pinmodel;
979         stvert_t *pinstverts;
980         dtriangle_t *pintriangles;
981         daliasskintype_t *pinskintype;
982         daliasskingroup_t *pinskingroup;
983         daliasskininterval_t *pinskinintervals;
984         daliasframetype_t *pinframetype;
985         daliasgroup_t *pinframegroup;
986         unsigned char *datapointer, *startframes, *startskins;
987         char name[MAX_QPATH];
988         skinframe_t *tempskinframe;
989         animscene_t *tempskinscenes;
990         texture_t *tempaliasskins;
991         float *vertst;
992         int *vertonseam, *vertremap;
993         skinfile_t *skinfiles;
994
995         datapointer = (unsigned char *)buffer;
996         pinmodel = (mdl_t *)datapointer;
997         datapointer += sizeof(mdl_t);
998
999         version = LittleLong (pinmodel->version);
1000         if (version != ALIAS_VERSION)
1001                 Host_Error ("%s has wrong version number (%i should be %i)",
1002                                  loadmodel->name, version, ALIAS_VERSION);
1003
1004         loadmodel->modeldatatypestring = "MDL";
1005
1006         loadmodel->type = mod_alias;
1007         loadmodel->Draw = R_Mod_Draw;
1008         loadmodel->DrawDepth = R_Mod_DrawDepth;
1009         loadmodel->DrawDebug = R_Mod_DrawDebug;
1010         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1011         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1012         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1013         loadmodel->DrawLight = R_Mod_DrawLight;
1014         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1015         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1016         // FIXME add TraceBrush!
1017         loadmodel->PointSuperContents = NULL;
1018         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1019
1020         loadmodel->num_surfaces = 1;
1021         loadmodel->submodelsurfaces_start = 0;
1022         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1023         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1024         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1025         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1026         loadmodel->modelsurfaces_sorted[0] = 0;
1027
1028         loadmodel->numskins = LittleLong(pinmodel->numskins);
1029         BOUNDI(loadmodel->numskins,0,65536);
1030         skinwidth = LittleLong (pinmodel->skinwidth);
1031         BOUNDI(skinwidth,0,65536);
1032         skinheight = LittleLong (pinmodel->skinheight);
1033         BOUNDI(skinheight,0,65536);
1034         numverts = LittleLong(pinmodel->numverts);
1035         BOUNDI(numverts,0,65536);
1036         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1037         BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1038         loadmodel->numframes = LittleLong(pinmodel->numframes);
1039         BOUNDI(loadmodel->numframes,0,65536);
1040         loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1041         BOUNDI((int)loadmodel->synctype,0,2);
1042         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1043         i = LittleLong (pinmodel->flags);
1044         loadmodel->effects = (((unsigned)i & 255) << 24) | (i & 0x00FFFF00);
1045
1046         if (strstr(r_nolerp_list.string, loadmodel->name))
1047                 loadmodel->nolerp = true;
1048
1049         for (i = 0;i < 3;i++)
1050         {
1051                 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1052                 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1053         }
1054
1055         startskins = datapointer;
1056         totalskins = 0;
1057         for (i = 0;i < loadmodel->numskins;i++)
1058         {
1059                 pinskintype = (daliasskintype_t *)datapointer;
1060                 datapointer += sizeof(daliasskintype_t);
1061                 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1062                         groupskins = 1;
1063                 else
1064                 {
1065                         pinskingroup = (daliasskingroup_t *)datapointer;
1066                         datapointer += sizeof(daliasskingroup_t);
1067                         groupskins = LittleLong(pinskingroup->numskins);
1068                         datapointer += sizeof(daliasskininterval_t) * groupskins;
1069                 }
1070
1071                 for (j = 0;j < groupskins;j++)
1072                 {
1073                         datapointer += skinwidth * skinheight;
1074                         totalskins++;
1075                 }
1076         }
1077
1078         pinstverts = (stvert_t *)datapointer;
1079         datapointer += sizeof(stvert_t) * numverts;
1080
1081         pintriangles = (dtriangle_t *)datapointer;
1082         datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1083
1084         startframes = datapointer;
1085         loadmodel->surfmesh.num_morphframes = 0;
1086         for (i = 0;i < loadmodel->numframes;i++)
1087         {
1088                 pinframetype = (daliasframetype_t *)datapointer;
1089                 datapointer += sizeof(daliasframetype_t);
1090                 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1091                         groupframes = 1;
1092                 else
1093                 {
1094                         pinframegroup = (daliasgroup_t *)datapointer;
1095                         datapointer += sizeof(daliasgroup_t);
1096                         groupframes = LittleLong(pinframegroup->numframes);
1097                         datapointer += sizeof(daliasinterval_t) * groupframes;
1098                 }
1099
1100                 for (j = 0;j < groupframes;j++)
1101                 {
1102                         datapointer += sizeof(daliasframe_t);
1103                         datapointer += sizeof(trivertx_t) * numverts;
1104                         loadmodel->surfmesh.num_morphframes++;
1105                 }
1106         }
1107         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1108
1109         // store texture coordinates into temporary array, they will be stored
1110         // after usage is determined (triangle data)
1111         vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1112         vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1113         vertonseam = vertremap + numverts * 2;
1114
1115         scales = 1.0 / skinwidth;
1116         scalet = 1.0 / skinheight;
1117         for (i = 0;i < numverts;i++)
1118         {
1119                 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1120                 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1121                 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1122                 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1123                 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1124         }
1125
1126 // load triangle data
1127         loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1128
1129         // read the triangle elements
1130         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1131                 for (j = 0;j < 3;j++)
1132                         loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1133         // validate (note numverts is used because this is the original data)
1134         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, NULL, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1135         // now butcher the elements according to vertonseam and tri->facesfront
1136         // and then compact the vertex set to remove duplicates
1137         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1138                 if (!LittleLong(pintriangles[i].facesfront)) // backface
1139                         for (j = 0;j < 3;j++)
1140                                 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1141                                         loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1142         // count the usage
1143         // (this uses vertremap to count usage to save some memory)
1144         for (i = 0;i < numverts*2;i++)
1145                 vertremap[i] = 0;
1146         for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1147                 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1148         // build remapping table and compact array
1149         loadmodel->surfmesh.num_vertices = 0;
1150         for (i = 0;i < numverts*2;i++)
1151         {
1152                 if (vertremap[i])
1153                 {
1154                         vertremap[i] = loadmodel->surfmesh.num_vertices;
1155                         vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1156                         vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1157                         loadmodel->surfmesh.num_vertices++;
1158                 }
1159                 else
1160                         vertremap[i] = -1; // not used at all
1161         }
1162         // remap the elements to the new vertex set
1163         for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1164                 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1165         // store the texture coordinates
1166         loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1167         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1168         {
1169                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1170                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1171         }
1172
1173         // generate ushort elements array if possible
1174         if (loadmodel->surfmesh.num_vertices <= 65536)
1175                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1176         if (loadmodel->surfmesh.data_element3s)
1177                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1178                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1179
1180 // load the frames
1181         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1182         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1183         Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1184         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1185         Mod_Alias_MorphMesh_CompileFrames();
1186
1187         Mem_Free(vertst);
1188         Mem_Free(vertremap);
1189
1190         // load the skins
1191         skinfiles = Mod_LoadSkinFiles();
1192         if (skinfiles)
1193         {
1194                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1195                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1196                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1197                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1198                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1199                 Mod_FreeSkinFiles(skinfiles);
1200                 for (i = 0;i < loadmodel->numskins;i++)
1201                 {
1202                         loadmodel->skinscenes[i].firstframe = i;
1203                         loadmodel->skinscenes[i].framecount = 1;
1204                         loadmodel->skinscenes[i].loop = true;
1205                         loadmodel->skinscenes[i].framerate = 10;
1206                 }
1207         }
1208         else
1209         {
1210                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1211                 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1212                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1213                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1214                 totalskins = 0;
1215                 datapointer = startskins;
1216                 for (i = 0;i < loadmodel->numskins;i++)
1217                 {
1218                         pinskintype = (daliasskintype_t *)datapointer;
1219                         datapointer += sizeof(daliasskintype_t);
1220
1221                         if (pinskintype->type == ALIAS_SKIN_SINGLE)
1222                         {
1223                                 groupskins = 1;
1224                                 interval = 0.1f;
1225                         }
1226                         else
1227                         {
1228                                 pinskingroup = (daliasskingroup_t *)datapointer;
1229                                 datapointer += sizeof(daliasskingroup_t);
1230
1231                                 groupskins = LittleLong (pinskingroup->numskins);
1232
1233                                 pinskinintervals = (daliasskininterval_t *)datapointer;
1234                                 datapointer += sizeof(daliasskininterval_t) * groupskins;
1235
1236                                 interval = LittleFloat(pinskinintervals[0].interval);
1237                                 if (interval < 0.01f)
1238                                 {
1239                                         Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1240                                         interval = 0.1f;
1241                                 }
1242                         }
1243
1244                         dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1245                         loadmodel->skinscenes[i].firstframe = totalskins;
1246                         loadmodel->skinscenes[i].framecount = groupskins;
1247                         loadmodel->skinscenes[i].framerate = 1.0f / interval;
1248                         loadmodel->skinscenes[i].loop = true;
1249
1250                         for (j = 0;j < groupskins;j++)
1251                         {
1252                                 if (groupskins > 1)
1253                                         dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1254                                 else
1255                                         dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1256                                 if (!Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, false, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL))
1257                                         Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight));
1258                                 datapointer += skinwidth * skinheight;
1259                                 totalskins++;
1260                         }
1261                 }
1262                 // check for skins that don't exist in the model, but do exist as external images
1263                 // (this was added because yummyluv kept pestering me about support for it)
1264                 // TODO: support shaders here?
1265                 for (;;)
1266                 {
1267                         dpsnprintf(name, sizeof(name), "%s_%i", loadmodel->name, loadmodel->numskins);
1268                         tempskinframe = R_SkinFrame_LoadExternal(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false, false);
1269                         if (!tempskinframe)
1270                                 break;
1271                         // expand the arrays to make room
1272                         tempskinscenes = loadmodel->skinscenes;
1273                         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1274                         memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1275                         Mem_Free(tempskinscenes);
1276
1277                         tempaliasskins = loadmodel->data_textures;
1278                         loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1279                         memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1280                         Mem_Free(tempaliasskins);
1281
1282                         // store the info about the new skin
1283                         Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, tempskinframe);
1284                         dp_strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1285                         loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1286                         loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1287                         loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1288                         loadmodel->skinscenes[loadmodel->numskins].loop = true;
1289
1290                         //increase skin counts
1291                         loadmodel->num_textures++;
1292                         loadmodel->numskins++;
1293                         totalskins++;
1294
1295                         // fix up the pointers since they are pointing at the old textures array
1296                         // FIXME: this is a hack!
1297                         for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1298                                 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1299                 }
1300         }
1301
1302         surface = loadmodel->data_surfaces;
1303         surface->texture = loadmodel->data_textures;
1304         surface->num_firsttriangle = 0;
1305         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1306         surface->num_firstvertex = 0;
1307         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1308
1309         if(mod_alias_force_animated.string[0])
1310                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1311
1312         // Always make a BIH for the first frame, we can use it where possible.
1313         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1314         if (!loadmodel->surfmesh.isanimated)
1315         {
1316                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1317                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1318                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1319                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1320                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1321         }
1322 }
1323
1324 void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend)
1325 {
1326         int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1327         float iskinwidth, iskinheight;
1328         unsigned char *data;
1329         msurface_t *surface;
1330         md2_t *pinmodel;
1331         unsigned char *base, *datapointer;
1332         md2frame_t *pinframe;
1333         char *inskin;
1334         md2triangle_t *intri;
1335         unsigned short *inst;
1336         struct md2verthash_s
1337         {
1338                 struct md2verthash_s *next;
1339                 unsigned short xyz;
1340                 unsigned short st;
1341         }
1342         *hash, **md2verthash, *md2verthashdata;
1343         skinfile_t *skinfiles;
1344
1345         pinmodel = (md2_t *)buffer;
1346         base = (unsigned char *)buffer;
1347
1348         version = LittleLong (pinmodel->version);
1349         if (version != MD2ALIAS_VERSION)
1350                 Host_Error ("%s has wrong version number (%i should be %i)",
1351                         loadmodel->name, version, MD2ALIAS_VERSION);
1352
1353         loadmodel->modeldatatypestring = "MD2";
1354
1355         loadmodel->type = mod_alias;
1356         loadmodel->Draw = R_Mod_Draw;
1357         loadmodel->DrawDepth = R_Mod_DrawDepth;
1358         loadmodel->DrawDebug = R_Mod_DrawDebug;
1359         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1360         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1361         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1362         loadmodel->DrawLight = R_Mod_DrawLight;
1363         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1364         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1365         loadmodel->PointSuperContents = NULL;
1366         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1367
1368         if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1369                 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1370         if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1371                 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1372         if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1373                 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1374         if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1375                 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1376
1377         end = LittleLong(pinmodel->ofs_end);
1378         if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1379                 Host_Error ("%s is not a valid model", loadmodel->name);
1380         if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1381                 Host_Error ("%s is not a valid model", loadmodel->name);
1382         if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1383                 Host_Error ("%s is not a valid model", loadmodel->name);
1384         if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1385                 Host_Error ("%s is not a valid model", loadmodel->name);
1386         if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1387                 Host_Error ("%s is not a valid model", loadmodel->name);
1388
1389         loadmodel->numskins = LittleLong(pinmodel->num_skins);
1390         numxyz = LittleLong(pinmodel->num_xyz);
1391         numst = LittleLong(pinmodel->num_st);
1392         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1393         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1394         loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1395         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1396         skinwidth = LittleLong(pinmodel->skinwidth);
1397         skinheight = LittleLong(pinmodel->skinheight);
1398         iskinwidth = 1.0f / skinwidth;
1399         iskinheight = 1.0f / skinheight;
1400
1401         loadmodel->num_surfaces = 1;
1402         loadmodel->submodelsurfaces_start = 0;
1403         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1404         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]));
1405         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1406         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1407         loadmodel->modelsurfaces_sorted[0] = 0;
1408         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1409         loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1410         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1411
1412         loadmodel->synctype = ST_RAND;
1413
1414         // load the skins
1415         inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1416         skinfiles = Mod_LoadSkinFiles();
1417         if (skinfiles)
1418         {
1419                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1420                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1421                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1422                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1423                 Mod_FreeSkinFiles(skinfiles);
1424         }
1425         else if (loadmodel->numskins)
1426         {
1427                 // skins found (most likely not a player model)
1428                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1429                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1430                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1431                 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1432                         Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
1433         }
1434         else
1435         {
1436                 // no skins (most likely a player model)
1437                 loadmodel->numskins = 1;
1438                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1439                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1440                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1441                 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures, loadmodel->name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
1442         }
1443
1444         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1445         for (i = 0;i < loadmodel->numskins;i++)
1446         {
1447                 loadmodel->skinscenes[i].firstframe = i;
1448                 loadmodel->skinscenes[i].framecount = 1;
1449                 loadmodel->skinscenes[i].loop = true;
1450                 loadmodel->skinscenes[i].framerate = 10;
1451         }
1452
1453         // load the triangles and stvert data
1454         inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1455         intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1456         md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1457         md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1458         // swap the triangle list
1459         loadmodel->surfmesh.num_vertices = 0;
1460         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1461         {
1462                 for (j = 0;j < 3;j++)
1463                 {
1464                         xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1465                         st = (unsigned short) LittleShort (intri[i].index_st[j]);
1466                         if (xyz >= numxyz)
1467                         {
1468                                 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1469                                 xyz = 0;
1470                         }
1471                         if (st >= numst)
1472                         {
1473                                 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1474                                 st = 0;
1475                         }
1476                         hashindex = (xyz * 256 + st) & 65535;
1477                         for (hash = md2verthash[hashindex];hash;hash = hash->next)
1478                                 if (hash->xyz == xyz && hash->st == st)
1479                                         break;
1480                         if (hash == NULL)
1481                         {
1482                                 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1483                                 hash->xyz = xyz;
1484                                 hash->st = st;
1485                                 hash->next = md2verthash[hashindex];
1486                                 md2verthash[hashindex] = hash;
1487                         }
1488                         loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1489                 }
1490         }
1491
1492         vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1493         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));
1494         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1495         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1496         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1497         {
1498                 int sts, stt;
1499                 hash = md2verthashdata + i;
1500                 vertremap[i] = hash->xyz;
1501                 sts = LittleShort(inst[hash->st*2+0]);
1502                 stt = LittleShort(inst[hash->st*2+1]);
1503                 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1504                 {
1505                         Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1506                         sts = 0;
1507                         stt = 0;
1508                 }
1509                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1510                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1511         }
1512
1513         Mem_Free(md2verthash);
1514         Mem_Free(md2verthashdata);
1515
1516         // generate ushort elements array if possible
1517         if (loadmodel->surfmesh.num_vertices <= 65536)
1518                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1519         if (loadmodel->surfmesh.data_element3s)
1520                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1521                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1522
1523         // load the frames
1524         datapointer = (base + LittleLong(pinmodel->ofs_frames));
1525         for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1526         {
1527                 int k;
1528                 trivertx_t *v;
1529                 trivertx_t *out;
1530                 pinframe = (md2frame_t *)datapointer;
1531                 datapointer += sizeof(md2frame_t);
1532                 // store the frame scale/translate into the appropriate array
1533                 for (j = 0;j < 3;j++)
1534                 {
1535                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1536                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1537                 }
1538                 // convert the vertices
1539                 v = (trivertx_t *)datapointer;
1540                 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1541                 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1542                         out[k] = v[vertremap[k]];
1543                 datapointer += numxyz * sizeof(trivertx_t);
1544
1545                 dp_strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1546                 loadmodel->animscenes[i].firstframe = i;
1547                 loadmodel->animscenes[i].framecount = 1;
1548                 loadmodel->animscenes[i].framerate = 10;
1549                 loadmodel->animscenes[i].loop = true;
1550         }
1551
1552         Mem_Free(vertremap);
1553
1554         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1555         Mod_Alias_MorphMesh_CompileFrames();
1556         if(mod_alias_force_animated.string[0])
1557                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1558
1559         surface = loadmodel->data_surfaces;
1560         surface->texture = loadmodel->data_textures;
1561         surface->num_firsttriangle = 0;
1562         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1563         surface->num_firstvertex = 0;
1564         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1565
1566         // Always make a BIH for the first frame, we can use it where possible.
1567         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1568         if (!loadmodel->surfmesh.isanimated)
1569         {
1570                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1571                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1572                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1573                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1574                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1575         }
1576 }
1577
1578 void Mod_IDP3_Load(model_t *mod, void *buffer, void *bufferend)
1579 {
1580         int i, j, k, version, meshvertices, meshtriangles;
1581         unsigned char *data;
1582         msurface_t *surface;
1583         md3modelheader_t *pinmodel;
1584         md3frameinfo_t *pinframe;
1585         md3mesh_t *pinmesh;
1586         md3tag_t *pintag;
1587         skinfile_t *skinfiles;
1588
1589         pinmodel = (md3modelheader_t *)buffer;
1590
1591         if (memcmp(pinmodel->identifier, "IDP3", 4))
1592                 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1593         version = LittleLong (pinmodel->version);
1594         if (version != MD3VERSION)
1595                 Host_Error ("%s has wrong version number (%i should be %i)",
1596                         loadmodel->name, version, MD3VERSION);
1597
1598         skinfiles = Mod_LoadSkinFiles();
1599         if (loadmodel->numskins < 1)
1600                 loadmodel->numskins = 1;
1601
1602         loadmodel->modeldatatypestring = "MD3";
1603
1604         loadmodel->type = mod_alias;
1605         loadmodel->Draw = R_Mod_Draw;
1606         loadmodel->DrawDepth = R_Mod_DrawDepth;
1607         loadmodel->DrawDebug = R_Mod_DrawDebug;
1608         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1609         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1610         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1611         loadmodel->DrawLight = R_Mod_DrawLight;
1612         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1613         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1614         loadmodel->PointSuperContents = NULL;
1615         loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1616         loadmodel->synctype = ST_RAND;
1617         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1618         i = LittleLong (pinmodel->flags);
1619         loadmodel->effects = (((unsigned)i & 255) << 24) | (i & 0x00FFFF00);
1620
1621         // set up some global info about the model
1622         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1623         loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1624
1625         // make skinscenes for the skins (no groups)
1626         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1627         for (i = 0;i < loadmodel->numskins;i++)
1628         {
1629                 loadmodel->skinscenes[i].firstframe = i;
1630                 loadmodel->skinscenes[i].framecount = 1;
1631                 loadmodel->skinscenes[i].loop = true;
1632                 loadmodel->skinscenes[i].framerate = 10;
1633         }
1634
1635         // load frameinfo
1636         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1637         for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1638         {
1639                 dp_strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1640                 loadmodel->animscenes[i].firstframe = i;
1641                 loadmodel->animscenes[i].framecount = 1;
1642                 loadmodel->animscenes[i].framerate = 10;
1643                 loadmodel->animscenes[i].loop = true;
1644         }
1645
1646         // load tags
1647         loadmodel->num_tagframes = loadmodel->numframes;
1648         loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1649         loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1650         for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1651         {
1652                 dp_strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1653                 for (j = 0;j < 9;j++)
1654                         loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1655                 for (j = 0;j < 3;j++)
1656                         loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1657                 //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);
1658         }
1659
1660         // load meshes
1661         meshvertices = 0;
1662         meshtriangles = 0;
1663         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)))
1664         {
1665                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1666                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1667                 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1668                         Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1669                 meshvertices += LittleLong(pinmesh->num_vertices);
1670                 meshtriangles += LittleLong(pinmesh->num_triangles);
1671         }
1672
1673         loadmodel->submodelsurfaces_start = 0;
1674         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1675         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1676         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1677         loadmodel->surfmesh.num_vertices = meshvertices;
1678         loadmodel->surfmesh.num_triangles = meshtriangles;
1679         loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1680         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1681
1682         // do most allocations as one merged chunk
1683         // This is only robust for C standard types!
1684         data = (unsigned char *)Mem_Alloc(loadmodel->mempool,
1685                 meshvertices * sizeof(float[2])
1686                 + loadmodel->num_surfaces * sizeof(int)
1687                 + meshtriangles * sizeof(int[3])
1688                 + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0));
1689         // Pointers must be taken in descending order of alignment requirement!
1690         loadmodel->surfmesh.data_texcoordtexture2f        = (float *)data; data += meshvertices * sizeof(float[2]);
1691         loadmodel->modelsurfaces_sorted                     = (int *)data; data += loadmodel->num_surfaces * sizeof(int);
1692         loadmodel->surfmesh.data_element3i                  = (int *)data; data += meshtriangles * sizeof(int[3]);
1693         if (meshvertices <= 65536)
1694         {
1695                 loadmodel->surfmesh.data_element3s = (unsigned short *)data; data += meshtriangles * sizeof(unsigned short[3]);
1696         }
1697         // Struct alignment requirements could change so we can't assume them here
1698         // otherwise a safe-looking commit could introduce undefined behaviour!
1699         loadmodel->data_surfaces = Mem_AllocType(loadmodel->mempool, msurface_t, loadmodel->num_surfaces * sizeof(msurface_t));
1700         loadmodel->data_textures = Mem_AllocType(loadmodel->mempool, texture_t, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1701         loadmodel->surfmesh.data_morphmd3vertex = Mem_AllocType(loadmodel->mempool, md3vertex_t, meshvertices * loadmodel->numframes * sizeof(md3vertex_t));
1702
1703         meshvertices = 0;
1704         meshtriangles = 0;
1705         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)))
1706         {
1707                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1708                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1709                 loadmodel->modelsurfaces_sorted[i] = i;
1710                 surface = loadmodel->data_surfaces + i;
1711                 surface->texture = loadmodel->data_textures + i;
1712                 surface->num_firsttriangle = meshtriangles;
1713                 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1714                 surface->num_firstvertex = meshvertices;
1715                 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1716                 meshvertices += surface->num_vertices;
1717                 meshtriangles += surface->num_triangles;
1718
1719                 for (j = 0;j < surface->num_triangles * 3;j++)
1720                 {
1721                         int e = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1722                         loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = e;
1723                         if (loadmodel->surfmesh.data_element3s)
1724                                 loadmodel->surfmesh.data_element3s[j + surface->num_firsttriangle * 3] = e;
1725                 }
1726                 for (j = 0;j < surface->num_vertices;j++)
1727                 {
1728                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1729                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1730                 }
1731                 for (j = 0;j < loadmodel->numframes;j++)
1732                 {
1733                         const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1734                         md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1735                         for (k = 0;k < surface->num_vertices;k++, in++, out++)
1736                         {
1737                                 out->origin[0] = LittleShort(in->origin[0]);
1738                                 out->origin[1] = LittleShort(in->origin[1]);
1739                                 out->origin[2] = LittleShort(in->origin[2]);
1740                                 out->pitch = in->pitch;
1741                                 out->yaw = in->yaw;
1742                         }
1743                 }
1744
1745                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1746
1747                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1748         }
1749         Mod_Alias_MorphMesh_CompileFrames();
1750         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1751         Mod_FreeSkinFiles(skinfiles);
1752         Mod_MakeSortedSurfaces(loadmodel);
1753         if(mod_alias_force_animated.string[0])
1754                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1755
1756         // Always make a BIH for the first frame, we can use it where possible.
1757         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1758         if (!loadmodel->surfmesh.isanimated)
1759         {
1760                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1761                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1762                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1763                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1764                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1765         }
1766 }
1767
1768 void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend)
1769 {
1770         zymtype1header_t *pinmodel, *pheader;
1771         unsigned char *pbase;
1772         int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1773         float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1774         zymvertex_t *verts, *vertdata;
1775         zymscene_t *scene;
1776         zymbone_t *bone;
1777         char *shadername;
1778         skinfile_t *skinfiles;
1779         unsigned char *data;
1780         msurface_t *surface;
1781
1782         pinmodel = (zymtype1header_t *)buffer;
1783         pbase = (unsigned char *)buffer;
1784         if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1785                 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1786         if (BigLong(pinmodel->type) != 1)
1787                 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1788
1789         loadmodel->modeldatatypestring = "ZYM";
1790
1791         loadmodel->type = mod_alias;
1792         loadmodel->synctype = ST_RAND;
1793
1794         // byteswap header
1795         pheader = pinmodel;
1796         pheader->type = BigLong(pinmodel->type);
1797         pheader->filesize = BigLong(pinmodel->filesize);
1798         pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1799         pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1800         pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1801         pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1802         pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1803         pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1804         pheader->radius = BigFloat(pinmodel->radius);
1805         pheader->numverts = BigLong(pinmodel->numverts);
1806         pheader->numtris = BigLong(pinmodel->numtris);
1807         pheader->numshaders = BigLong(pinmodel->numshaders);
1808         pheader->numbones = BigLong(pinmodel->numbones);
1809         pheader->numscenes = BigLong(pinmodel->numscenes);
1810         pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1811         pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1812         pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1813         pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1814         pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1815         pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1816         pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1817         pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1818         pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1819         pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1820         pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1821         pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1822         pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1823         pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1824         pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1825         pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1826         pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1827         pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1828
1829         if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1830         {
1831                 Con_Printf("%s has no geometry\n", loadmodel->name);
1832                 return;
1833         }
1834         if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1835         {
1836                 Con_Printf("%s has no animations\n", loadmodel->name);
1837                 return;
1838         }
1839
1840         loadmodel->Draw = R_Mod_Draw;
1841         loadmodel->DrawDepth = R_Mod_DrawDepth;
1842         loadmodel->DrawDebug = R_Mod_DrawDebug;
1843         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1844         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1845         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1846         loadmodel->DrawLight = R_Mod_DrawLight;
1847         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1848         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1849         loadmodel->PointSuperContents = NULL;
1850         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1851
1852         loadmodel->numframes = pheader->numscenes;
1853         loadmodel->num_surfaces = pheader->numshaders;
1854
1855         skinfiles = Mod_LoadSkinFiles();
1856         if (loadmodel->numskins < 1)
1857                 loadmodel->numskins = 1;
1858
1859         // make skinscenes for the skins (no groups)
1860         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1861         for (i = 0;i < loadmodel->numskins;i++)
1862         {
1863                 loadmodel->skinscenes[i].firstframe = i;
1864                 loadmodel->skinscenes[i].framecount = 1;
1865                 loadmodel->skinscenes[i].loop = true;
1866                 loadmodel->skinscenes[i].framerate = 10;
1867         }
1868
1869         // model bbox
1870         // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1871         modelradius = pheader->radius;
1872         for (i = 0;i < 3;i++)
1873         {
1874                 loadmodel->normalmins[i] = pheader->mins[i];
1875                 loadmodel->normalmaxs[i] = pheader->maxs[i];
1876                 loadmodel->rotatedmins[i] = -modelradius;
1877                 loadmodel->rotatedmaxs[i] = modelradius;
1878         }
1879         corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1880         corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1881         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1882         if (loadmodel->yawmaxs[0] > modelradius)
1883                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1884         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1885         loadmodel->yawmins[2] = loadmodel->normalmins[2];
1886         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1887         loadmodel->radius = modelradius;
1888         loadmodel->radius2 = modelradius * modelradius;
1889
1890         // go through the lumps, swapping things
1891
1892         //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1893         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1894         scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1895         numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1896         for (i = 0;i < pheader->numscenes;i++)
1897         {
1898                 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1899                 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1900                 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1901                 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1902                 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1903                 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1904                         Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1905                 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1906                         Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1907                 if (loadmodel->animscenes[i].framerate < 0)
1908                         Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1909                 scene++;
1910         }
1911
1912         //zymlump_t lump_bones; // zymbone_t bone[numbones];
1913         loadmodel->num_bones = pheader->numbones;
1914         loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1915         bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1916         for (i = 0;i < pheader->numbones;i++)
1917         {
1918                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1919                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1920                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1921                 if (loadmodel->data_bones[i].parent >= i)
1922                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1923         }
1924
1925         //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1926         vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1927         bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1928         for (i = 0;i < pheader->numverts;i++)
1929         {
1930                 vertbonecounts[i] = BigLong(bonecount[i]);
1931                 if (vertbonecounts[i] != 1)
1932                         Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1933         }
1934
1935         loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1936
1937         meshvertices = pheader->numverts;
1938         meshtriangles = pheader->numtris;
1939
1940         loadmodel->submodelsurfaces_start = 0;
1941         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1942         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1943         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1944         loadmodel->surfmesh.num_vertices = meshvertices;
1945         loadmodel->surfmesh.num_triangles = meshtriangles;
1946         loadmodel->surfmesh.num_blends = 0;
1947         loadmodel->surfmesh.data_blendweights = NULL;
1948
1949         // do most allocations as one merged chunk
1950         // This is only robust for C standard types!
1951         data = (unsigned char *)Mem_Alloc(loadmodel->mempool,
1952                 loadmodel->num_surfaces * sizeof(int)
1953                 + meshtriangles * sizeof(int[3])
1954                 + (meshvertices <= 65536 ? loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]) : 0)
1955                 + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4]))
1956                 + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7])
1957                 + loadmodel->num_bones * sizeof(float[12]));
1958         // Pointers must be taken in descending order of alignment requirement!
1959         loadmodel->surfmesh.data_vertex3f          = (float *)data; data += meshvertices * sizeof(float[3]);
1960         loadmodel->surfmesh.data_svector3f         = (float *)data; data += meshvertices * sizeof(float[3]);
1961         loadmodel->surfmesh.data_tvector3f         = (float *)data; data += meshvertices * sizeof(float[3]);
1962         loadmodel->surfmesh.data_normal3f          = (float *)data; data += meshvertices * sizeof(float[3]);
1963         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data; data += meshvertices * sizeof(float[2]);
1964         loadmodel->data_baseboneposeinverse        = (float *)data; data += loadmodel->num_bones * sizeof(float[12]);
1965         loadmodel->modelsurfaces_sorted              = (int *)data; data += loadmodel->num_surfaces * sizeof(int);
1966         loadmodel->surfmesh.data_element3i           = (int *)data; data += meshtriangles * sizeof(int[3]);
1967         loadmodel->surfmesh.blends        = (unsigned short *)data; data += meshvertices * sizeof(unsigned short);
1968         if (loadmodel->surfmesh.num_vertices <= 65536)
1969         {
1970                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1971         }
1972         loadmodel->data_poses7s                            = (short *)data; data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
1973         loadmodel->surfmesh.data_skeletalindex4ub  = (unsigned char *)data; data += meshvertices * sizeof(unsigned char[4]);
1974         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data; data += meshvertices * sizeof(unsigned char[4]);
1975         // Struct alignment requirements could change so we can't assume them here
1976         // otherwise a safe-looking commit could introduce undefined behaviour!
1977         loadmodel->data_surfaces = Mem_AllocType(loadmodel->mempool, msurface_t, loadmodel->num_surfaces * sizeof(msurface_t));
1978         loadmodel->data_textures = Mem_AllocType(loadmodel->mempool, texture_t, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1979
1980         //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1981         poses = (float *) (pheader->lump_poses.start + pbase);
1982         // figure out scale of model from root bone, for compatibility with old zmodel versions
1983         tempvec[0] = BigFloat(poses[0]);
1984         tempvec[1] = BigFloat(poses[1]);
1985         tempvec[2] = BigFloat(poses[2]);
1986         modelscale = VectorLength(tempvec);
1987         biggestorigin = 0;
1988         for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
1989         {
1990                 f = fabs(BigFloat(poses[i]));
1991                 biggestorigin = max(biggestorigin, f);
1992         }
1993         loadmodel->num_posescale = biggestorigin / 32767.0f;
1994         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
1995         for (i = 0;i < numposes;i++)
1996         {
1997                 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
1998                 for (j = 0;j < loadmodel->num_bones;j++)
1999                 {
2000                         float pose[12];
2001                         matrix4x4_t posematrix;
2002                         for (k = 0;k < 12;k++)
2003                                 pose[k] = BigFloat(frameposes[j*12+k]);
2004                         //if (j < loadmodel->num_bones)
2005                         //      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));
2006                         // scale child bones to match the root scale
2007                         if (loadmodel->data_bones[j].parent >= 0)
2008                         {
2009                                 pose[3] *= modelscale;
2010                                 pose[7] *= modelscale;
2011                                 pose[11] *= modelscale;
2012                         }
2013                         // normalize rotation matrix
2014                         VectorNormalize(pose + 0);
2015                         VectorNormalize(pose + 4);
2016                         VectorNormalize(pose + 8);
2017                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2018                         Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2019                 }
2020         }
2021
2022         //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2023         verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2024         vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2025         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2026         // (converting from weight-blending skeletal animation to
2027         //  deformation-based skeletal animation)
2028         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2029         for (i = 0;i < loadmodel->num_bones;i++)
2030         {
2031                 float m[12];
2032                 for (k = 0;k < 12;k++)
2033                         m[k] = BigFloat(poses[i*12+k]);
2034                 if (loadmodel->data_bones[i].parent >= 0)
2035                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2036                 else
2037                         for (k = 0;k < 12;k++)
2038                                 bonepose[12*i+k] = m[k];
2039         }
2040         for (j = 0;j < pheader->numverts;j++)
2041         {
2042                 // this format really should have had a per vertexweight weight value...
2043                 // but since it does not, the weighting is completely ignored and
2044                 // only one weight is allowed per vertex
2045                 int boneindex = BigLong(vertdata[j].bonenum);
2046                 const float *m = bonepose + 12 * boneindex;
2047                 float relativeorigin[3];
2048                 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2049                 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2050                 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2051                 // transform the vertex bone weight into the base mesh
2052                 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2053                 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2054                 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2055                 // store the weight as the primary weight on this vertex
2056                 loadmodel->surfmesh.blends[j] = boneindex;
2057                 loadmodel->surfmesh.data_skeletalindex4ub[j*4  ] = boneindex;
2058                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2059                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2060                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2061                 loadmodel->surfmesh.data_skeletalweight4ub[j*4  ] = 255;
2062                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2063                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2064                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2065         }
2066         Z_Free(bonepose);
2067         // normals and tangents are calculated after elements are loaded
2068
2069         //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2070         outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2071         intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2072         for (i = 0;i < pheader->numverts;i++)
2073         {
2074                 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2075                 // flip T coordinate for OpenGL
2076                 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2077         }
2078
2079         //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2080         //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2081         //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2082
2083         //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2084         //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)
2085         // byteswap, validate, and swap winding order of tris
2086         count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2087         if (pheader->lump_render.length != count)
2088                 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2089         renderlist = (int *) (pheader->lump_render.start + pbase);
2090         renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2091         meshtriangles = 0;
2092         for (i = 0;i < loadmodel->num_surfaces;i++)
2093         {
2094                 int firstvertex, lastvertex;
2095                 if (renderlist >= renderlistend)
2096                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2097                 count = BigLong(*renderlist);renderlist++;
2098                 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2099                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2100
2101                 loadmodel->modelsurfaces_sorted[i] = i;
2102                 surface = loadmodel->data_surfaces + i;
2103                 surface->texture = loadmodel->data_textures + i;
2104                 surface->num_firsttriangle = meshtriangles;
2105                 surface->num_triangles = count;
2106                 meshtriangles += surface->num_triangles;
2107
2108                 // load the elements
2109                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2110                 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2111                 {
2112                         outelements[j*3+2] = BigLong(renderlist[0]);
2113                         outelements[j*3+1] = BigLong(renderlist[1]);
2114                         outelements[j*3+0] = BigLong(renderlist[2]);
2115                 }
2116                 // validate the elements and find the used vertex range
2117                 firstvertex = meshvertices;
2118                 lastvertex = 0;
2119                 for (j = 0;j < surface->num_triangles * 3;j++)
2120                 {
2121                         if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2122                                 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2123                         firstvertex = min(firstvertex, outelements[j]);
2124                         lastvertex = max(lastvertex, outelements[j]);
2125                 }
2126                 surface->num_firstvertex = firstvertex;
2127                 surface->num_vertices = lastvertex + 1 - firstvertex;
2128
2129                 // since zym models do not have named sections, reuse their shader
2130                 // name as the section name
2131                 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2132                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2133         }
2134         Mod_FreeSkinFiles(skinfiles);
2135         Mem_Free(vertbonecounts);
2136         Mem_Free(verts);
2137         Mod_MakeSortedSurfaces(loadmodel);
2138
2139         // compute all the mesh information that was not loaded from the file
2140         if (loadmodel->surfmesh.data_element3s)
2141                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2142                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2143         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2144         Mod_BuildBaseBonePoses();
2145         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);
2146         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);
2147         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2148         if(mod_alias_force_animated.string[0])
2149                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2150
2151         // Always make a BIH for the first frame, we can use it where possible.
2152         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2153         if (!loadmodel->surfmesh.isanimated)
2154         {
2155                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2156                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2157                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2158                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2159                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2160         }
2161 }
2162
2163 void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend)
2164 {
2165         dpmheader_t *pheader;
2166         dpmframe_t *frames;
2167         dpmbone_t *bone;
2168         dpmmesh_t *dpmmesh;
2169         unsigned char *pbase;
2170         int i, j, k, meshvertices, meshtriangles;
2171         skinfile_t *skinfiles;
2172         unsigned char *data;
2173         float *bonepose;
2174         float biggestorigin, tempvec[3], modelscale;
2175         float f;
2176         float *poses;
2177
2178         pheader = (dpmheader_t *)buffer;
2179         pbase = (unsigned char *)buffer;
2180         if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2181                 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2182         if (BigLong(pheader->type) != 2)
2183                 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2184
2185         loadmodel->modeldatatypestring = "DPM";
2186
2187         loadmodel->type = mod_alias;
2188         loadmodel->synctype = ST_RAND;
2189
2190         // byteswap header
2191         pheader->type = BigLong(pheader->type);
2192         pheader->filesize = BigLong(pheader->filesize);
2193         pheader->mins[0] = BigFloat(pheader->mins[0]);
2194         pheader->mins[1] = BigFloat(pheader->mins[1]);
2195         pheader->mins[2] = BigFloat(pheader->mins[2]);
2196         pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2197         pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2198         pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2199         pheader->yawradius = BigFloat(pheader->yawradius);
2200         pheader->allradius = BigFloat(pheader->allradius);
2201         pheader->num_bones = BigLong(pheader->num_bones);
2202         pheader->num_meshs = BigLong(pheader->num_meshs);
2203         pheader->num_frames = BigLong(pheader->num_frames);
2204         pheader->ofs_bones = BigLong(pheader->ofs_bones);
2205         pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2206         pheader->ofs_frames = BigLong(pheader->ofs_frames);
2207
2208         if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2209         {
2210                 Con_Printf("%s has no geometry\n", loadmodel->name);
2211                 return;
2212         }
2213         if (pheader->num_frames < 1)
2214         {
2215                 Con_Printf("%s has no frames\n", loadmodel->name);
2216                 return;
2217         }
2218
2219         loadmodel->Draw = R_Mod_Draw;
2220         loadmodel->DrawDepth = R_Mod_DrawDepth;
2221         loadmodel->DrawDebug = R_Mod_DrawDebug;
2222         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2223         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2224         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2225         loadmodel->DrawLight = R_Mod_DrawLight;
2226         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2227         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2228         loadmodel->PointSuperContents = NULL;
2229         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2230
2231         // model bbox
2232         // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2233         for (i = 0;i < 3;i++)
2234         {
2235                 loadmodel->normalmins[i] = pheader->mins[i];
2236                 loadmodel->normalmaxs[i] = pheader->maxs[i];
2237                 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2238                 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2239                 loadmodel->rotatedmins[i] = -pheader->allradius;
2240                 loadmodel->rotatedmaxs[i] = pheader->allradius;
2241         }
2242         loadmodel->radius = pheader->allradius;
2243         loadmodel->radius2 = pheader->allradius * pheader->allradius;
2244
2245         // load external .skin files if present
2246         skinfiles = Mod_LoadSkinFiles();
2247         if (loadmodel->numskins < 1)
2248                 loadmodel->numskins = 1;
2249
2250         meshvertices = 0;
2251         meshtriangles = 0;
2252
2253         // gather combined statistics from the meshes
2254         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2255         for (i = 0;i < (int)pheader->num_meshs;i++)
2256         {
2257                 int numverts = BigLong(dpmmesh->num_verts);
2258                 meshvertices += numverts;
2259                 meshtriangles += BigLong(dpmmesh->num_tris);
2260                 dpmmesh++;
2261         }
2262
2263         loadmodel->numframes = pheader->num_frames;
2264         loadmodel->num_bones = pheader->num_bones;
2265         loadmodel->num_poses = loadmodel->numframes;
2266         loadmodel->submodelsurfaces_start = 0;
2267         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = pheader->num_meshs;
2268         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2269         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2270         loadmodel->surfmesh.num_vertices = meshvertices;
2271         loadmodel->surfmesh.num_triangles = meshtriangles;
2272         loadmodel->surfmesh.num_blends = 0;
2273
2274         // do most allocations as one merged chunk
2275         // This is only robust for C standard types!
2276         data = (unsigned char *)Mem_Alloc(loadmodel->mempool,
2277                 loadmodel->num_surfaces * sizeof(int)
2278                 + meshtriangles * sizeof(int[3])
2279                 + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0)
2280                 + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4]))
2281                 + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7])
2282                 + loadmodel->num_bones * sizeof(float[12]));
2283         // Pointers must be taken in descending order of alignment requirement!
2284         loadmodel->surfmesh.data_vertex3f                  = (float *)data; data += meshvertices * sizeof(float[3]);
2285         loadmodel->surfmesh.data_svector3f                 = (float *)data; data += meshvertices * sizeof(float[3]);
2286         loadmodel->surfmesh.data_tvector3f                 = (float *)data; data += meshvertices * sizeof(float[3]);
2287         loadmodel->surfmesh.data_normal3f                  = (float *)data; data += meshvertices * sizeof(float[3]);
2288         loadmodel->surfmesh.data_texcoordtexture2f         = (float *)data; data += meshvertices * sizeof(float[2]);
2289         loadmodel->data_baseboneposeinverse                = (float *)data; data += loadmodel->num_bones * sizeof(float[12]);
2290         loadmodel->modelsurfaces_sorted                      = (int *)data; data += loadmodel->num_surfaces * sizeof(int);
2291         loadmodel->surfmesh.data_element3i                   = (int *)data; data += meshtriangles * sizeof(int[3]);
2292         loadmodel->surfmesh.blends                = (unsigned short *)data; data += meshvertices * sizeof(unsigned short);
2293         if (meshvertices <= 65536)
2294         {
2295                 loadmodel->surfmesh.data_element3s = (unsigned short *)data; data += meshtriangles * sizeof(unsigned short[3]);
2296         }
2297         loadmodel->data_poses7s                            = (short *)data; data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2298         loadmodel->surfmesh.data_skeletalindex4ub  = (unsigned char *)data; data += meshvertices * sizeof(unsigned char[4]);
2299         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data; data += meshvertices * sizeof(unsigned char[4]);
2300         // Struct alignment requirements could change so we can't assume them here
2301         // otherwise a safe-looking commit could introduce undefined behaviour!
2302         loadmodel->data_surfaces = Mem_AllocType(loadmodel->mempool, msurface_t, loadmodel->num_surfaces * sizeof(msurface_t));
2303         loadmodel->data_textures = Mem_AllocType(loadmodel->mempool, texture_t, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
2304         loadmodel->skinscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numskins * sizeof(animscene_t));
2305         loadmodel->data_bones = Mem_AllocType(loadmodel->mempool, aliasbone_t, loadmodel->num_bones * sizeof(aliasbone_t));
2306         loadmodel->animscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numframes * sizeof(animscene_t));
2307         loadmodel->surfmesh.data_blendweights = Mem_AllocType(loadmodel->mempool, blendweights_t, meshvertices * sizeof(blendweights_t));
2308
2309         for (i = 0;i < loadmodel->numskins;i++)
2310         {
2311                 loadmodel->skinscenes[i].firstframe = i;
2312                 loadmodel->skinscenes[i].framecount = 1;
2313                 loadmodel->skinscenes[i].loop = true;
2314                 loadmodel->skinscenes[i].framerate = 10;
2315         }
2316
2317         // load the bone info
2318         bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2319         for (i = 0;i < loadmodel->num_bones;i++)
2320         {
2321                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2322                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2323                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2324                 if (loadmodel->data_bones[i].parent >= i)
2325                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2326         }
2327
2328         // load the frames
2329         frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2330         // figure out scale of model from root bone, for compatibility with old dpmodel versions
2331         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2332         tempvec[0] = BigFloat(poses[0]);
2333         tempvec[1] = BigFloat(poses[1]);
2334         tempvec[2] = BigFloat(poses[2]);
2335         modelscale = VectorLength(tempvec);
2336         biggestorigin = 0;
2337         for (i = 0;i < loadmodel->numframes;i++)
2338         {
2339                 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2340                 loadmodel->animscenes[i].firstframe = i;
2341                 loadmodel->animscenes[i].framecount = 1;
2342                 loadmodel->animscenes[i].loop = true;
2343                 loadmodel->animscenes[i].framerate = 10;
2344                 // load the bone poses for this frame
2345                 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2346                 for (j = 0;j < loadmodel->num_bones*12;j++)
2347                 {
2348                         f = fabs(BigFloat(poses[j]));
2349                         biggestorigin = max(biggestorigin, f);
2350                 }
2351                 // stuff not processed here: mins, maxs, yawradius, allradius
2352         }
2353         loadmodel->num_posescale = biggestorigin / 32767.0f;
2354         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2355         for (i = 0;i < loadmodel->numframes;i++)
2356         {
2357                 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2358                 for (j = 0;j < loadmodel->num_bones;j++)
2359                 {
2360                         float pose[12];
2361                         matrix4x4_t posematrix;
2362                         for (k = 0;k < 12;k++)
2363                                 pose[k] = BigFloat(frameposes[j*12+k]);
2364                         // scale child bones to match the root scale
2365                         if (loadmodel->data_bones[j].parent >= 0)
2366                         {
2367                                 pose[3] *= modelscale;
2368                                 pose[7] *= modelscale;
2369                                 pose[11] *= modelscale;
2370                         }
2371                         // normalize rotation matrix
2372                         VectorNormalize(pose + 0);
2373                         VectorNormalize(pose + 4);
2374                         VectorNormalize(pose + 8);
2375                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2376                         Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2377                 }
2378         }
2379
2380         // load the meshes now
2381         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2382         meshvertices = 0;
2383         meshtriangles = 0;
2384         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2385         // (converting from weight-blending skeletal animation to
2386         //  deformation-based skeletal animation)
2387         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2388         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2389         for (i = 0;i < loadmodel->num_bones;i++)
2390         {
2391                 float m[12];
2392                 for (k = 0;k < 12;k++)
2393                         m[k] = BigFloat(poses[i*12+k]);
2394                 if (loadmodel->data_bones[i].parent >= 0)
2395                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2396                 else
2397                         for (k = 0;k < 12;k++)
2398                                 bonepose[12*i+k] = m[k];
2399         }
2400         for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2401         {
2402                 const int *inelements;
2403                 int *outelement3i;
2404                 unsigned short *outelement3s;
2405                 const float *intexcoord;
2406                 msurface_t *surface;
2407
2408                 loadmodel->modelsurfaces_sorted[i] = i;
2409                 surface = loadmodel->data_surfaces + i;
2410                 surface->texture = loadmodel->data_textures + i;
2411                 surface->num_firsttriangle = meshtriangles;
2412                 surface->num_triangles = BigLong(dpmmesh->num_tris);
2413                 surface->num_firstvertex = meshvertices;
2414                 surface->num_vertices = BigLong(dpmmesh->num_verts);
2415                 meshvertices += surface->num_vertices;
2416                 meshtriangles += surface->num_triangles;
2417
2418                 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2419                 outelement3i = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2420                 outelement3s = loadmodel->surfmesh.data_element3s ? loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3 : NULL;
2421                 for (j = 0;j < surface->num_triangles;j++)
2422                 {
2423                         // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2424                         outelement3i[j * 3 + 0] = surface->num_firstvertex + BigLong(inelements[j * 3 + 2]);
2425                         outelement3i[j * 3 + 1] = surface->num_firstvertex + BigLong(inelements[j * 3 + 1]);
2426                         outelement3i[j * 3 + 2] = surface->num_firstvertex + BigLong(inelements[j * 3 + 0]);
2427                         if (outelement3s)
2428                         {
2429                                 outelement3s[j * 3 + 0] = outelement3i[j * 3 + 0];
2430                                 outelement3s[j * 3 + 1] = outelement3i[j * 3 + 1];
2431                                 outelement3s[j * 3 + 2] = outelement3i[j * 3 + 2];
2432                         }
2433                 }
2434
2435                 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2436                 for (j = 0;j < surface->num_vertices*2;j++)
2437                         loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2438
2439                 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2440                 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2441                 {
2442                         int weightindex[4] = { 0, 0, 0, 0 };
2443                         float weightinfluence[4] = { 0, 0, 0, 0 };
2444                         int l;
2445                         int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2446                         data += sizeof(dpmvertex_t);
2447                         for (k = 0;k < numweights;k++)
2448                         {
2449                                 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2450                                 int boneindex = BigLong(vert->bonenum);
2451                                 const float *m = bonepose + 12 * boneindex;
2452                                 float influence = BigFloat(vert->influence);
2453                                 float relativeorigin[3], relativenormal[3];
2454                                 relativeorigin[0] = BigFloat(vert->origin[0]);
2455                                 relativeorigin[1] = BigFloat(vert->origin[1]);
2456                                 relativeorigin[2] = BigFloat(vert->origin[2]);
2457                                 relativenormal[0] = BigFloat(vert->normal[0]);
2458                                 relativenormal[1] = BigFloat(vert->normal[1]);
2459                                 relativenormal[2] = BigFloat(vert->normal[2]);
2460                                 // blend the vertex bone weights into the base mesh
2461                                 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2462                                 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2463                                 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2464                                 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2465                                 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2466                                 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2467                                 if (!k)
2468                                 {
2469                                         // store the first (and often only) weight
2470                                         weightinfluence[0] = influence;
2471                                         weightindex[0] = boneindex;
2472                                 }
2473                                 else
2474                                 {
2475                                         // sort the new weight into this vertex's weight table
2476                                         // (which only accepts up to 4 bones per vertex)
2477                                         for (l = 0;l < 4;l++)
2478                                         {
2479                                                 if (weightinfluence[l] < influence)
2480                                                 {
2481                                                         // move weaker influence weights out of the way first
2482                                                         int l2;
2483                                                         for (l2 = 3;l2 > l;l2--)
2484                                                         {
2485                                                                 weightinfluence[l2] = weightinfluence[l2-1];
2486                                                                 weightindex[l2] = weightindex[l2-1];
2487                                                         }
2488                                                         // store the new weight
2489                                                         weightinfluence[l] = influence;
2490                                                         weightindex[l] = boneindex;
2491                                                         break;
2492                                                 }
2493                                         }
2494                                 }
2495                                 data += sizeof(dpmbonevert_t);
2496                         }
2497                         loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2498                         loadmodel->surfmesh.data_skeletalindex4ub[j*4  ] = weightindex[0];
2499                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2500                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2501                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2502                         loadmodel->surfmesh.data_skeletalweight4ub[j*4  ] = (unsigned char)(weightinfluence[0]*255.0f);
2503                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2504                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2505                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2506                 }
2507
2508                 // since dpm models do not have named sections, reuse their shader name as the section name
2509                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2510
2511                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2512         }
2513         if (loadmodel->surfmesh.num_blends < meshvertices)
2514                 loadmodel->surfmesh.data_blendweights = Mem_ReallocType(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, blendweights_t, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2515         Z_Free(bonepose);
2516         Mod_FreeSkinFiles(skinfiles);
2517         Mod_MakeSortedSurfaces(loadmodel);
2518
2519         // compute all the mesh information that was not loaded from the file
2520         Mod_BuildBaseBonePoses();
2521         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);
2522         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2523         if(mod_alias_force_animated.string[0])
2524                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2525
2526         // Always make a BIH for the first frame, we can use it where possible.
2527         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2528         if (!loadmodel->surfmesh.isanimated)
2529         {
2530                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2531                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2532                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2533                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2534                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2535         }
2536 }
2537
2538 // no idea why PSK/PSA files contain weird quaternions but they do...
2539 #define PSKQUATNEGATIONS
2540 void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
2541 {
2542         int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2543         int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2544         fs_offset_t filesize;
2545         pskpnts_t *pnts;
2546         pskvtxw_t *vtxw;
2547         pskface_t *faces;
2548         pskmatt_t *matts;
2549         pskboneinfo_t *bones;
2550         pskrawweights_t *rawweights;
2551         //pskboneinfo_t *animbones;
2552         pskaniminfo_t *anims;
2553         pskanimkeys_t *animkeys;
2554         void *animfilebuffer, *animbuffer, *animbufferend;
2555         unsigned char *data;
2556         pskchunk_t *pchunk;
2557         skinfile_t *skinfiles;
2558         char animname[MAX_QPATH];
2559         float biggestorigin;
2560
2561         pchunk = (pskchunk_t *)buffer;
2562         if (strcmp(pchunk->id, "ACTRHEAD"))
2563                 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2564
2565         loadmodel->modeldatatypestring = "PSK";
2566
2567         loadmodel->type = mod_alias;
2568         loadmodel->Draw = R_Mod_Draw;
2569         loadmodel->DrawDepth = R_Mod_DrawDepth;
2570         loadmodel->DrawDebug = R_Mod_DrawDebug;
2571         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2572         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2573         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2574         loadmodel->DrawLight = R_Mod_DrawLight;
2575         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2576         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2577         loadmodel->PointSuperContents = NULL;
2578         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2579         loadmodel->synctype = ST_RAND;
2580
2581         FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2582         dp_strlcat(animname, ".psa", sizeof(animname));
2583         animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2584         animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2585         if (!animbuffer)
2586                 animbufferend = animbuffer;
2587
2588         numpnts = 0;
2589         pnts = NULL;
2590         numvtxw = 0;
2591         vtxw = NULL;
2592         numfaces = 0;
2593         faces = NULL;
2594         nummatts = 0;
2595         matts = NULL;
2596         numbones = 0;
2597         bones = NULL;
2598         numrawweights = 0;
2599         rawweights = NULL;
2600         numanims = 0;
2601         anims = NULL;
2602         numanimkeys = 0;
2603         animkeys = NULL;
2604
2605         while (buffer < bufferend)
2606         {
2607                 pchunk = (pskchunk_t *)buffer;
2608                 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2609                 version = LittleLong(pchunk->version);
2610                 recordsize = LittleLong(pchunk->recordsize);
2611                 numrecords = LittleLong(pchunk->numrecords);
2612                 if (developer_extra.integer)
2613                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2614                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2615                         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);
2616                 if (!strcmp(pchunk->id, "ACTRHEAD"))
2617                 {
2618                         // nothing to do
2619                 }
2620                 else if (!strcmp(pchunk->id, "PNTS0000"))
2621                 {
2622                         pskpnts_t *p;
2623                         if (recordsize != sizeof(*p))
2624                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2625                         // byteswap in place and keep the pointer
2626                         numpnts = numrecords;
2627                         pnts = (pskpnts_t *)buffer;
2628                         for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2629                         {
2630                                 p->origin[0] = LittleFloat(p->origin[0]);
2631                                 p->origin[1] = LittleFloat(p->origin[1]);
2632                                 p->origin[2] = LittleFloat(p->origin[2]);
2633                         }
2634                         buffer = p;
2635                 }
2636                 else if (!strcmp(pchunk->id, "VTXW0000"))
2637                 {
2638                         pskvtxw_t *p;
2639                         if (recordsize != sizeof(*p))
2640                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2641                         // byteswap in place and keep the pointer
2642                         numvtxw = numrecords;
2643                         vtxw = (pskvtxw_t *)buffer;
2644                         for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2645                         {
2646                                 p->pntsindex = LittleShort(p->pntsindex);
2647                                 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2648                                 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2649                                 if (p->pntsindex >= numpnts)
2650                                 {
2651                                         Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2652                                         p->pntsindex = 0;
2653                                 }
2654                         }
2655                         buffer = p;
2656                 }
2657                 else if (!strcmp(pchunk->id, "FACE0000"))
2658                 {
2659                         pskface_t *p;
2660                         if (recordsize != sizeof(*p))
2661                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2662                         // byteswap in place and keep the pointer
2663                         numfaces = numrecords;
2664                         faces = (pskface_t *)buffer;
2665                         for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2666                         {
2667                                 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2668                                 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2669                                 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2670                                 p->group = LittleLong(p->group);
2671                                 if (p->vtxwindex[0] >= numvtxw)
2672                                 {
2673                                         Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2674                                         p->vtxwindex[0] = 0;
2675                                 }
2676                                 if (p->vtxwindex[1] >= numvtxw)
2677                                 {
2678                                         Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2679                                         p->vtxwindex[1] = 0;
2680                                 }
2681                                 if (p->vtxwindex[2] >= numvtxw)
2682                                 {
2683                                         Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2684                                         p->vtxwindex[2] = 0;
2685                                 }
2686                         }
2687                         buffer = p;
2688                 }
2689                 else if (!strcmp(pchunk->id, "MATT0000"))
2690                 {
2691                         pskmatt_t *p;
2692                         if (recordsize != sizeof(*p))
2693                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2694                         // byteswap in place and keep the pointer
2695                         nummatts = numrecords;
2696                         matts = (pskmatt_t *)buffer;
2697                         for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2698                         {
2699                                 // nothing to do
2700                         }
2701                         buffer = p;
2702                 }
2703                 else if (!strcmp(pchunk->id, "REFSKELT"))
2704                 {
2705                         pskboneinfo_t *p;
2706                         if (recordsize != sizeof(*p))
2707                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2708                         // byteswap in place and keep the pointer
2709                         numbones = numrecords;
2710                         bones = (pskboneinfo_t *)buffer;
2711                         for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2712                         {
2713                                 p->numchildren = LittleLong(p->numchildren);
2714                                 p->parent = LittleLong(p->parent);
2715                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2716                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2717                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2718                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2719                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2720                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2721                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2722                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2723                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2724                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2725                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2726 #ifdef PSKQUATNEGATIONS
2727                                 if (index)
2728                                 {
2729                                         p->basepose.quat[0] *= -1;
2730                                         p->basepose.quat[1] *= -1;
2731                                         p->basepose.quat[2] *= -1;
2732                                 }
2733                                 else
2734                                 {
2735                                         p->basepose.quat[0] *=  1;
2736                                         p->basepose.quat[1] *= -1;
2737                                         p->basepose.quat[2] *=  1;
2738                                 }
2739 #endif
2740                                 if (p->parent < 0 || p->parent >= numbones)
2741                                 {
2742                                         Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2743                                         p->parent = 0;
2744                                 }
2745                         }
2746                         buffer = p;
2747                 }
2748                 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2749                 {
2750                         pskrawweights_t *p;
2751                         if (recordsize != sizeof(*p))
2752                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2753                         // byteswap in place and keep the pointer
2754                         numrawweights = numrecords;
2755                         rawweights = (pskrawweights_t *)buffer;
2756                         for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2757                         {
2758                                 p->weight = LittleFloat(p->weight);
2759                                 p->pntsindex = LittleLong(p->pntsindex);
2760                                 p->boneindex = LittleLong(p->boneindex);
2761                                 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2762                                 {
2763                                         Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2764                                         p->pntsindex = 0;
2765                                 }
2766                                 if (p->boneindex < 0 || p->boneindex >= numbones)
2767                                 {
2768                                         Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2769                                         p->boneindex = 0;
2770                                 }
2771                         }
2772                         buffer = p;
2773                 }
2774         }
2775
2776         while (animbuffer < animbufferend)
2777         {
2778                 pchunk = (pskchunk_t *)animbuffer;
2779                 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2780                 version = LittleLong(pchunk->version);
2781                 recordsize = LittleLong(pchunk->recordsize);
2782                 numrecords = LittleLong(pchunk->numrecords);
2783                 if (developer_extra.integer)
2784                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2785                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2786                         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);
2787                 if (!strcmp(pchunk->id, "ANIMHEAD"))
2788                 {
2789                         // nothing to do
2790                 }
2791                 else if (!strcmp(pchunk->id, "BONENAMES"))
2792                 {
2793                         pskboneinfo_t *p;
2794                         if (recordsize != sizeof(*p))
2795                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2796                         // byteswap in place and keep the pointer
2797                         numanimbones = numrecords;
2798                         //animbones = (pskboneinfo_t *)animbuffer;
2799                         // NOTE: supposedly psa does not need to match the psk model, the
2800                         // bones missing from the psa would simply use their base
2801                         // positions from the psk, but this is hard for me to implement
2802                         // and people can easily make animations that match.
2803                         if (numanimbones != numbones)
2804                                 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2805                         for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2806                         {
2807                                 p->numchildren = LittleLong(p->numchildren);
2808                                 p->parent = LittleLong(p->parent);
2809                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2810                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2811                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2812                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2813                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2814                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2815                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2816                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2817                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2818                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2819                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2820 #ifdef PSKQUATNEGATIONS
2821                                 if (index)
2822                                 {
2823                                         p->basepose.quat[0] *= -1;
2824                                         p->basepose.quat[1] *= -1;
2825                                         p->basepose.quat[2] *= -1;
2826                                 }
2827                                 else
2828                                 {
2829                                         p->basepose.quat[0] *=  1;
2830                                         p->basepose.quat[1] *= -1;
2831                                         p->basepose.quat[2] *=  1;
2832                                 }
2833 #endif
2834                                 if (p->parent < 0 || p->parent >= numanimbones)
2835                                 {
2836                                         Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2837                                         p->parent = 0;
2838                                 }
2839                                 // check that bones are the same as in the base
2840                                 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2841                                         Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2842                         }
2843                         animbuffer = p;
2844                 }
2845                 else if (!strcmp(pchunk->id, "ANIMINFO"))
2846                 {
2847                         pskaniminfo_t *p;
2848                         if (recordsize != sizeof(*p))
2849                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2850                         // byteswap in place and keep the pointer
2851                         numanims = numrecords;
2852                         anims = (pskaniminfo_t *)animbuffer;
2853                         for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2854                         {
2855                                 p->numbones = LittleLong(p->numbones);
2856                                 p->playtime = LittleFloat(p->playtime);
2857                                 p->fps = LittleFloat(p->fps);
2858                                 p->firstframe = LittleLong(p->firstframe);
2859                                 p->numframes = LittleLong(p->numframes);
2860                                 if (p->numbones != numbones)
2861                                         Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2862                         }
2863                         animbuffer = p;
2864                 }
2865                 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2866                 {
2867                         pskanimkeys_t *p;
2868                         if (recordsize != sizeof(*p))
2869                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2870                         numanimkeys = numrecords;
2871                         animkeys = (pskanimkeys_t *)animbuffer;
2872                         for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2873                         {
2874                                 p->origin[0] = LittleFloat(p->origin[0]);
2875                                 p->origin[1] = LittleFloat(p->origin[1]);
2876                                 p->origin[2] = LittleFloat(p->origin[2]);
2877                                 p->quat[0] = LittleFloat(p->quat[0]);
2878                                 p->quat[1] = LittleFloat(p->quat[1]);
2879                                 p->quat[2] = LittleFloat(p->quat[2]);
2880                                 p->quat[3] = LittleFloat(p->quat[3]);
2881                                 p->frametime = LittleFloat(p->frametime);
2882 #ifdef PSKQUATNEGATIONS
2883                                 if (index % numbones)
2884                                 {
2885                                         p->quat[0] *= -1;
2886                                         p->quat[1] *= -1;
2887                                         p->quat[2] *= -1;
2888                                 }
2889                                 else
2890                                 {
2891                                         p->quat[0] *=  1;
2892                                         p->quat[1] *= -1;
2893                                         p->quat[2] *=  1;
2894                                 }
2895 #endif
2896                         }
2897                         animbuffer = p;
2898                         // TODO: allocate bonepose stuff
2899                 }
2900                 else
2901                         Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2902         }
2903
2904         if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2905                 Host_Error("%s: missing required chunks", loadmodel->name);
2906
2907         if (numanims)
2908         {
2909                 loadmodel->numframes = 0;
2910                 for (index = 0;index < numanims;index++)
2911                         loadmodel->numframes += anims[index].numframes;
2912                 if (numanimkeys != numbones * loadmodel->numframes)
2913                         Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2914         }
2915         else
2916                 loadmodel->numframes = loadmodel->num_poses = 1;
2917
2918         meshvertices = numvtxw;
2919         meshtriangles = numfaces;
2920
2921         // load external .skin files if present
2922         skinfiles = Mod_LoadSkinFiles();
2923         if (loadmodel->numskins < 1)
2924                 loadmodel->numskins = 1;
2925         loadmodel->num_bones = numbones;
2926         loadmodel->num_poses = loadmodel->numframes;
2927         loadmodel->submodelsurfaces_start = 0;
2928         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = nummatts;
2929         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2930         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2931         loadmodel->surfmesh.num_vertices = meshvertices;
2932         loadmodel->surfmesh.num_triangles = meshtriangles;
2933
2934         // do most allocations as one merged chunk
2935         // This is only robust for C standard types!
2936         data = (unsigned char *)Mem_Alloc(loadmodel->mempool,
2937                 loadmodel->surfmesh.num_vertices * sizeof(float[3])
2938                 + loadmodel->surfmesh.num_vertices * sizeof(float[3])
2939                 + loadmodel->surfmesh.num_vertices * sizeof(float[3])
2940                 + loadmodel->surfmesh.num_vertices * sizeof(float[3])
2941                 + loadmodel->surfmesh.num_vertices * sizeof(float[2])
2942                 + loadmodel->num_bones * sizeof(float[12])
2943                 + loadmodel->num_surfaces * sizeof(int)
2944                 + loadmodel->surfmesh.num_triangles * sizeof(int[3])
2945                 + loadmodel->surfmesh.num_vertices * sizeof(unsigned short)
2946                 + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0)
2947                 + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7])
2948                 + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4])
2949                 + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
2950         // Pointers must be taken in descending order of alignment requirement!
2951         loadmodel->surfmesh.data_vertex3f          = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2952         loadmodel->surfmesh.data_svector3f         = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2953         loadmodel->surfmesh.data_tvector3f         = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2954         loadmodel->surfmesh.data_normal3f          = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2955         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2956         loadmodel->data_baseboneposeinverse        = (float *)data; data += loadmodel->num_bones * sizeof(float[12]);
2957         loadmodel->modelsurfaces_sorted              = (int *)data; data += loadmodel->num_surfaces * sizeof(int);
2958         loadmodel->surfmesh.data_element3i           = (int *)data; data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2959         loadmodel->surfmesh.num_blends = 0;
2960         loadmodel->surfmesh.blends        = (unsigned short *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned short);
2961         if (loadmodel->surfmesh.num_vertices <= 65536)
2962         {
2963                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2964         }
2965         loadmodel->data_poses7s                            = (short *)data; data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2966         loadmodel->surfmesh.data_skeletalindex4ub  = (unsigned char *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2967         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2968         // Struct alignment requirements could change so we can't assume them here
2969         // otherwise a safe-looking commit could introduce undefined behaviour!
2970         loadmodel->data_surfaces = Mem_AllocType(loadmodel->mempool, msurface_t, loadmodel->num_surfaces * sizeof(msurface_t));
2971         loadmodel->data_textures = Mem_AllocType(loadmodel->mempool, texture_t, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
2972         loadmodel->skinscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numskins * sizeof(animscene_t));
2973         loadmodel->data_bones = Mem_AllocType(loadmodel->mempool, aliasbone_t, loadmodel->num_bones * sizeof(aliasbone_t));
2974         loadmodel->animscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numframes * sizeof(animscene_t));
2975         loadmodel->surfmesh.data_blendweights = Mem_AllocType(loadmodel->mempool, blendweights_t, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2976
2977         for (i = 0;i < loadmodel->numskins;i++)
2978         {
2979                 loadmodel->skinscenes[i].firstframe = i;
2980                 loadmodel->skinscenes[i].framecount = 1;
2981                 loadmodel->skinscenes[i].loop = true;
2982                 loadmodel->skinscenes[i].framerate = 10;
2983         }
2984
2985         // create surfaces
2986         for (index = 0, i = 0;index < nummatts;index++)
2987         {
2988                 // since psk models do not have named sections, reuse their shader name as the section name
2989                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2990                 loadmodel->modelsurfaces_sorted[index] = index;
2991                 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2992                 loadmodel->data_surfaces[index].num_firstvertex = 0;
2993                 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2994         }
2995
2996         // copy over the vertex locations and texcoords
2997         for (index = 0;index < numvtxw;index++)
2998         {
2999                 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
3000                 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
3001                 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
3002                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
3003                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
3004         }
3005
3006         // loading the faces is complicated because we need to sort them into surfaces by mattindex
3007         for (index = 0;index < numfaces;index++)
3008                 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
3009         for (index = 0, i = 0;index < nummatts;index++)
3010         {
3011                 loadmodel->data_surfaces[index].num_firsttriangle = i;
3012                 i += loadmodel->data_surfaces[index].num_triangles;
3013                 loadmodel->data_surfaces[index].num_triangles = 0;
3014         }
3015         for (index = 0;index < numfaces;index++)
3016         {
3017                 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3018                 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3019                 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3020                 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3021         }
3022
3023         // copy over the bones
3024         for (index = 0;index < numbones;index++)
3025         {
3026                 dp_strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3027                 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3028                 if (loadmodel->data_bones[index].parent >= index)
3029                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3030         }
3031
3032         // convert the basepose data
3033         if (loadmodel->num_bones)
3034         {
3035                 int boneindex;
3036                 matrix4x4_t *basebonepose;
3037                 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3038                 matrix4x4_t bonematrix;
3039                 matrix4x4_t tempbonematrix;
3040                 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3041                 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3042                 {
3043                         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]);
3044                         if (loadmodel->data_bones[boneindex].parent >= 0)
3045                         {
3046                                 tempbonematrix = bonematrix;
3047                                 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3048                         }
3049                         basebonepose[boneindex] = bonematrix;
3050                         Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3051                         Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3052                 }
3053                 Mem_Free(basebonepose);
3054         }
3055
3056         // sort the psk point weights into the vertex weight tables
3057         // (which only accept up to 4 bones per vertex)
3058         for (index = 0;index < numvtxw;index++)
3059         {
3060                 int weightindex[4] = { 0, 0, 0, 0 };
3061                 float weightinfluence[4] = { 0, 0, 0, 0 };
3062                 int l;
3063                 for (j = 0;j < numrawweights;j++)
3064                 {
3065                         if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3066                         {
3067                                 int boneindex = rawweights[j].boneindex;
3068                                 float influence = rawweights[j].weight;
3069                                 for (l = 0;l < 4;l++)
3070                                 {
3071                                         if (weightinfluence[l] < influence)
3072                                         {
3073                                                 // move lower influence weights out of the way first
3074                                                 int l2;
3075                                                 for (l2 = 3;l2 > l;l2--)
3076                                                 {
3077                                                         weightinfluence[l2] = weightinfluence[l2-1];
3078                                                         weightindex[l2] = weightindex[l2-1];
3079                                                 }
3080                                                 // store the new weight
3081                                                 weightinfluence[l] = influence;
3082                                                 weightindex[l] = boneindex;
3083                                                 break;
3084                                         }
3085                                 }
3086                         }
3087                 }
3088                 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3089                 loadmodel->surfmesh.data_skeletalindex4ub[index*4  ] = weightindex[0];
3090                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3091                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3092                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3093                 loadmodel->surfmesh.data_skeletalweight4ub[index*4  ] = (unsigned char)(weightinfluence[0]*255.0f);
3094                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3095                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3096                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3097         }
3098         if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3099                 loadmodel->surfmesh.data_blendweights = Mem_ReallocType(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, blendweights_t, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3100
3101         // set up the animscenes based on the anims
3102         if (numanims)
3103         {
3104                 for (index = 0, i = 0;index < numanims;index++)
3105                 {
3106                         for (j = 0;j < anims[index].numframes;j++, i++)
3107                         {
3108                                 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3109                                 loadmodel->animscenes[i].firstframe = i;
3110                                 loadmodel->animscenes[i].framecount = 1;
3111                                 loadmodel->animscenes[i].loop = true;
3112                                 loadmodel->animscenes[i].framerate = anims[index].fps;
3113                         }
3114                 }
3115                 // calculate the scaling value for bone origins so they can be compressed to short
3116                 biggestorigin = 0;
3117                 for (index = 0;index < numanimkeys;index++)
3118                 {
3119                         pskanimkeys_t *k = animkeys + index;
3120                         biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3121                         biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3122                         biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3123                 }
3124                 loadmodel->num_posescale = biggestorigin / 32767.0f;
3125                 if (loadmodel->num_posescale == 0) // don't divide by zero
3126                         loadmodel->num_posescale = 1.0;
3127                 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3128         
3129                 // load the poses from the animkeys
3130                 for (index = 0;index < numanimkeys;index++)
3131                 {
3132                         pskanimkeys_t *k = animkeys + index;
3133                         float quat[4];
3134                         Vector4Copy(k->quat, quat);
3135                         if (quat[3] > 0)
3136                                 Vector4Negate(quat, quat);
3137                         Vector4Normalize2(quat, quat);
3138                         // compress poses to the short[7] format for longterm storage
3139                         loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3140                         loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3141                         loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3142                         loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3143                         loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3144                         loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3145                         loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3146                 }
3147         }
3148         else
3149         {
3150                 dp_strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3151                 loadmodel->animscenes[0].firstframe = 0;
3152                 loadmodel->animscenes[0].framecount = 1;
3153                 loadmodel->animscenes[0].loop = true;
3154                 loadmodel->animscenes[0].framerate = 10;
3155
3156                 // calculate the scaling value for bone origins so they can be compressed to short
3157                 biggestorigin = 0;
3158                 for (index = 0;index < numbones;index++)
3159                 {
3160                         pskboneinfo_t *p = bones + index;
3161                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3162                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3163                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3164                 }
3165                 loadmodel->num_posescale = biggestorigin / 32767.0f;
3166                 if (loadmodel->num_posescale == 0) // don't divide by zero
3167                         loadmodel->num_posescale = 1.0;
3168                 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3169         
3170                 // load the basepose as a frame
3171                 for (index = 0;index < numbones;index++)
3172                 {
3173                         pskboneinfo_t *p = bones + index;
3174                         float quat[4];
3175                         Vector4Copy(p->basepose.quat, quat);
3176                         if (quat[3] > 0)
3177                                 Vector4Negate(quat, quat);
3178                         Vector4Normalize2(quat, quat);
3179                         // compress poses to the short[7] format for longterm storage
3180                         loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3181                         loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3182                         loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3183                         loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3184                         loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3185                         loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3186                         loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3187                 }
3188         }
3189
3190         Mod_FreeSkinFiles(skinfiles);
3191         if (animfilebuffer)
3192                 Mem_Free(animfilebuffer);
3193         Mod_MakeSortedSurfaces(loadmodel);
3194
3195         // compute all the mesh information that was not loaded from the file
3196         // TODO: honor smoothing groups somehow?
3197         if (loadmodel->surfmesh.data_element3s)
3198                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3199                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3200         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3201         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);
3202         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);
3203         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3204         if(mod_alias_force_animated.string[0])
3205                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3206
3207         // Always make a BIH for the first frame, we can use it where possible.
3208         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3209         if (!loadmodel->surfmesh.isanimated)
3210         {
3211                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3212                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3213                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3214                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3215                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3216         }
3217 }
3218
3219 void Mod_INTERQUAKEMODEL_Load(model_t *mod, void *buffer, void *bufferend)
3220 {
3221         unsigned char *data;
3222         const char *text;
3223         const unsigned char *pbase, *pend;
3224         iqmheader_t header;
3225         skinfile_t *skinfiles;
3226         int i, j, k;
3227         float biggestorigin;
3228         const unsigned int *inelements;
3229         int *outelements;
3230         float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3231         // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3232         const float *vnormal = NULL;
3233         const float *vposition = NULL;
3234         const float *vtangent = NULL;
3235         const float *vtexcoord = NULL;
3236         const float *vcolor4f = NULL;
3237         const unsigned char *vblendindexes = NULL;
3238         const unsigned char *vblendweights = NULL;
3239         const unsigned char *vcolor4ub = NULL;
3240         const unsigned short *framedata = NULL;
3241         // temporary memory allocations (because the data in the file may be misaligned)
3242         iqmanim_t *anims = NULL;
3243         iqmbounds_t *bounds = NULL;
3244         iqmjoint1_t *joint1 = NULL;
3245         iqmjoint_t *joint = NULL;
3246         iqmmesh_t *meshes = NULL;
3247         iqmpose1_t *pose1 = NULL;
3248         iqmpose_t *pose = NULL;
3249         iqmvertexarray_t *vas = NULL;
3250
3251         pbase = (unsigned char *)buffer;
3252         pend = (unsigned char *)bufferend;
3253
3254         if (pbase + sizeof(iqmheader_t) > pend)
3255                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3256
3257         // copy struct (otherwise it may be misaligned)
3258         // LadyHavoc: okay it's definitely not misaligned here, but for consistency...
3259         memcpy(&header, pbase, sizeof(iqmheader_t));
3260
3261         if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3262                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3263         if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3264                 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3265
3266         loadmodel->modeldatatypestring = "IQM";
3267
3268         loadmodel->type = mod_alias;
3269         loadmodel->synctype = ST_RAND;
3270
3271         // byteswap header
3272         header.version = LittleLong(header.version);
3273         header.filesize = LittleLong(header.filesize);
3274         header.flags = LittleLong(header.flags);
3275         header.num_text = LittleLong(header.num_text);
3276         header.ofs_text = LittleLong(header.ofs_text);
3277         header.num_meshes = LittleLong(header.num_meshes);
3278         header.ofs_meshes = LittleLong(header.ofs_meshes);
3279         header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3280         header.num_vertexes = LittleLong(header.num_vertexes);
3281         header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3282         header.num_triangles = LittleLong(header.num_triangles);
3283         header.ofs_triangles = LittleLong(header.ofs_triangles);
3284         header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3285         header.num_joints = LittleLong(header.num_joints);
3286         header.ofs_joints = LittleLong(header.ofs_joints);
3287         header.num_poses = LittleLong(header.num_poses);
3288         header.ofs_poses = LittleLong(header.ofs_poses);
3289         header.num_anims = LittleLong(header.num_anims);
3290         header.ofs_anims = LittleLong(header.ofs_anims);
3291         header.num_frames = LittleLong(header.num_frames);
3292         header.num_framechannels = LittleLong(header.num_framechannels);
3293         header.ofs_frames = LittleLong(header.ofs_frames);
3294         header.ofs_bounds = LittleLong(header.ofs_bounds);
3295         header.num_comment = LittleLong(header.num_comment);
3296         header.ofs_comment = LittleLong(header.ofs_comment);
3297         header.num_extensions = LittleLong(header.num_extensions);
3298         header.ofs_extensions = LittleLong(header.ofs_extensions);
3299
3300         if (header.version == 1)
3301         {
3302                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3303                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3304                 {
3305                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3306                         return;
3307                 }
3308         }
3309         else
3310         {
3311                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3312                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3313                 {
3314                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3315                         return;
3316                 }
3317         }
3318         if (pbase + header.ofs_text + header.num_text > pend ||
3319                 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3320                 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3321                 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3322                 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3323                 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3324                 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3325                 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3326                 pbase + header.ofs_comment + header.num_comment > pend)
3327         {
3328                 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3329                 return;
3330         }
3331
3332         // Structs will be copied for alignment in memory, otherwise we crash on Sparc, PowerPC and others
3333         // and get big spam from UBSan, because these offsets may not be aligned.
3334         if (header.num_vertexarrays)
3335                 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3336         if (header.num_anims)
3337                 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3338         if (header.ofs_bounds)
3339                 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3340         if (header.num_meshes)
3341                 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3342
3343         for (i = 0;i < (int)header.num_vertexarrays;i++)
3344         {
3345                 iqmvertexarray_t va;
3346                 size_t vsize;
3347
3348                 memcpy(&va, &vas[i], sizeof(iqmvertexarray_t));
3349                 va.type = LittleLong(va.type);
3350                 va.flags = LittleLong(va.flags);
3351                 va.format = LittleLong(va.format);
3352                 va.size = LittleLong(va.size);
3353                 va.offset = LittleLong(va.offset);
3354                 vsize = header.num_vertexes*va.size;
3355                 switch (va.format)
3356                 { 
3357                 case IQM_FLOAT: vsize *= sizeof(float); break;
3358                 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3359                 default: continue;
3360                 }
3361                 if (pbase + va.offset + vsize > pend)
3362                         continue;
3363                 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3364                 switch (va.type)
3365                 {
3366                 case IQM_POSITION:
3367                         if (va.format == IQM_FLOAT && va.size == 3)
3368                                 vposition = (const float *)(pbase + va.offset);
3369                         break;
3370                 case IQM_TEXCOORD:
3371                         if (va.format == IQM_FLOAT && va.size == 2)
3372                                 vtexcoord = (const float *)(pbase + va.offset);
3373                         break;
3374                 case IQM_NORMAL:
3375                         if (va.format == IQM_FLOAT && va.size == 3)
3376                                 vnormal = (const float *)(pbase + va.offset);
3377                         break;
3378                 case IQM_TANGENT:
3379                         if (va.format == IQM_FLOAT && va.size == 4)
3380                                 vtangent = (const float *)(pbase + va.offset);
3381                         break;
3382                 case IQM_BLENDINDEXES:
3383                         if (va.format == IQM_UBYTE && va.size == 4)
3384                                 vblendindexes = (const unsigned char *)(pbase + va.offset);
3385                         break;
3386                 case IQM_BLENDWEIGHTS:
3387                         if (va.format == IQM_UBYTE && va.size == 4)
3388                                 vblendweights = (const unsigned char *)(pbase + va.offset);
3389                         break;
3390                 case IQM_COLOR:
3391                         if (va.format == IQM_FLOAT && va.size == 4)
3392                                 vcolor4f = (const float *)(pbase + va.offset);
3393                         if (va.format == IQM_UBYTE && va.size == 4)
3394                                 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3395                         break;
3396                 }
3397         }
3398         if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3399         {
3400                 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3401                 return;
3402         }
3403
3404         text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3405
3406         loadmodel->Draw = R_Mod_Draw;
3407         loadmodel->DrawDepth = R_Mod_DrawDepth;
3408         loadmodel->DrawDebug = R_Mod_DrawDebug;
3409         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
3410         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
3411         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
3412         loadmodel->DrawLight = R_Mod_DrawLight;
3413         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3414         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3415         loadmodel->PointSuperContents = NULL;
3416         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3417
3418         // load external .skin files if present
3419         skinfiles = Mod_LoadSkinFiles();
3420         if (loadmodel->numskins < 1)
3421                 loadmodel->numskins = 1;
3422
3423         loadmodel->numframes = max(header.num_anims, 1);
3424         loadmodel->num_bones = header.num_joints;
3425         loadmodel->num_poses = max(header.num_frames, 1);
3426         loadmodel->submodelsurfaces_start = 0;
3427         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = header.num_meshes;
3428         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3429         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3430         loadmodel->surfmesh.num_vertices = header.num_vertexes;
3431         loadmodel->surfmesh.num_triangles = header.num_triangles;
3432
3433         // do most allocations as one merged chunk
3434         // This is only robust for C standard types!
3435         data = (unsigned char *)Mem_Alloc(loadmodel->mempool,
3436                 loadmodel->surfmesh.num_vertices * (sizeof(float[14]) + (vcolor4f || vcolor4ub ? sizeof(float[4]) : 0))
3437                 + loadmodel->num_bones * sizeof(float[12])
3438                 + loadmodel->num_surfaces * sizeof(int)
3439                 + loadmodel->surfmesh.num_triangles * sizeof(int[3])
3440                 + (loadmodel->surfmesh.num_vertices <= 65536 ? loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]) : 0)
3441                 + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7])
3442                 + (vblendindexes && vblendweights ? loadmodel->surfmesh.num_vertices * (sizeof(unsigned short) + sizeof(unsigned char[2][4])) : 0));
3443         // Pointers must be taken in descending order of alignment requirement!
3444         loadmodel->surfmesh.data_vertex3f          = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3445         loadmodel->surfmesh.data_svector3f         = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3446         loadmodel->surfmesh.data_tvector3f         = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3447         loadmodel->surfmesh.data_normal3f          = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3448         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3449         if (vcolor4f || vcolor4ub)
3450         {
3451                 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
3452         }
3453         loadmodel->data_baseboneposeinverse = (float *)data; data += loadmodel->num_bones * sizeof(float[12]);
3454         loadmodel->modelsurfaces_sorted       = (int *)data; data += loadmodel->num_surfaces * sizeof(int);
3455         loadmodel->surfmesh.data_element3i    = (int *)data; data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3456         loadmodel->data_poses7s             = (short *)data; data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3457         if (loadmodel->surfmesh.num_vertices <= 65536)
3458         {
3459                 loadmodel->surfmesh.data_element3s = (unsigned short *)data; data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
3460         }
3461         if (vblendindexes && vblendweights)
3462         {
3463                 loadmodel->surfmesh.num_blends = 0;
3464                 loadmodel->surfmesh.blends                = (unsigned short *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned short);
3465                 loadmodel->surfmesh.data_skeletalindex4ub  = (unsigned char *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3466                 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3467         }
3468         // Struct alignment requirements could change so we can't assume them here
3469         // otherwise a safe-looking commit could introduce undefined behaviour!
3470         loadmodel->data_surfaces = Mem_AllocType(loadmodel->mempool, msurface_t, loadmodel->num_surfaces * sizeof(msurface_t));
3471         loadmodel->data_textures = Mem_AllocType(loadmodel->mempool, texture_t, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
3472         loadmodel->skinscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numskins * sizeof(animscene_t));
3473         loadmodel->data_bones = Mem_AllocType(loadmodel->mempool, aliasbone_t, loadmodel->num_bones * sizeof(aliasbone_t));
3474         loadmodel->animscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numframes * sizeof(animscene_t));
3475         if (vblendindexes && vblendweights)
3476                 loadmodel->surfmesh.data_blendweights = Mem_AllocType(loadmodel->mempool, blendweights_t, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
3477
3478         for (i = 0;i < loadmodel->numskins;i++)
3479         {
3480                 loadmodel->skinscenes[i].firstframe = i;
3481                 loadmodel->skinscenes[i].framecount = 1;
3482                 loadmodel->skinscenes[i].loop = true;
3483                 loadmodel->skinscenes[i].framerate = 10;
3484         }
3485
3486         // load the bone info
3487         if (header.version == 1)
3488         {
3489                 iqmjoint1_t *injoints1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3490
3491                 if (loadmodel->num_bones)
3492                         joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3493                 for (i = 0;i < loadmodel->num_bones;i++)
3494                 {
3495                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3496                         iqmjoint1_t injoint1;
3497
3498                         memcpy(&injoint1, &injoints1[i], sizeof(iqmjoint1_t));
3499                         joint1[i].name = LittleLong(injoint1.name);
3500                         joint1[i].parent = LittleLong(injoint1.parent);
3501                         for (j = 0;j < 3;j++)
3502                         {
3503                                 joint1[i].origin[j] = LittleFloat(injoint1.origin[j]);
3504                                 joint1[i].rotation[j] = LittleFloat(injoint1.rotation[j]);
3505                                 joint1[i].scale[j] = LittleFloat(injoint1.scale[j]);
3506                         }
3507                         dp_strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3508                         loadmodel->data_bones[i].parent = joint1[i].parent;
3509                         if (loadmodel->data_bones[i].parent >= i)
3510                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3511                         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]);
3512                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3513                         if (loadmodel->data_bones[i].parent >= 0)
3514                         {
3515                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3516                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3517                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3518                         }
3519                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3520                 }
3521         }
3522         else
3523         {
3524                 iqmjoint_t *injoints = (iqmjoint_t *)(pbase + header.ofs_joints);
3525
3526                 if (header.num_joints)
3527                         joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3528                 for (i = 0;i < loadmodel->num_bones;i++)
3529                 {
3530                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3531                         iqmjoint_t injoint;
3532
3533                         memcpy(&injoint, &injoints[i], sizeof(iqmjoint_t));
3534                         joint[i].name = LittleLong(injoint.name);
3535                         joint[i].parent = LittleLong(injoint.parent);
3536                         for (j = 0;j < 3;j++)
3537                         {
3538                                 joint[i].origin[j] = LittleFloat(injoint.origin[j]);
3539                                 joint[i].rotation[j] = LittleFloat(injoint.rotation[j]);
3540                                 joint[i].scale[j] = LittleFloat(injoint.scale[j]);
3541                         }
3542                         joint[i].rotation[3] = LittleFloat(injoint.rotation[3]);
3543                         dp_strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3544                         loadmodel->data_bones[i].parent = joint[i].parent;
3545                         if (loadmodel->data_bones[i].parent >= i)
3546                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3547                         if (joint[i].rotation[3] > 0)
3548                                 Vector4Negate(joint[i].rotation, joint[i].rotation);
3549                         Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3550                         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]);
3551                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3552                         if (loadmodel->data_bones[i].parent >= 0)
3553                         {
3554                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3555                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3556                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3557                         }       
3558                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3559                 }
3560         }
3561
3562         // set up the animscenes based on the anims
3563         for (i = 0;i < (int)header.num_anims;i++)
3564         {
3565                 iqmanim_t anim;
3566
3567                 memcpy(&anim, &anims[i], sizeof(iqmanim_t));
3568                 anim.name = LittleLong(anim.name);
3569                 anim.first_frame = LittleLong(anim.first_frame);
3570                 anim.num_frames = LittleLong(anim.num_frames);
3571                 anim.framerate = LittleFloat(anim.framerate);
3572                 anim.flags = LittleLong(anim.flags);
3573                 dp_strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3574                 loadmodel->animscenes[i].firstframe = anim.first_frame;
3575                 loadmodel->animscenes[i].framecount = anim.num_frames;
3576                 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3577                 loadmodel->animscenes[i].framerate = anim.framerate;
3578         }
3579         if (header.num_anims <= 0)
3580         {
3581                 dp_strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3582                 loadmodel->animscenes[0].firstframe = 0;
3583                 loadmodel->animscenes[0].framecount = 1;
3584                 loadmodel->animscenes[0].loop = true;
3585                 loadmodel->animscenes[0].framerate = 10;
3586         }
3587
3588         loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3589         if(mod_alias_force_animated.string[0])
3590                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3591
3592         biggestorigin = 0;
3593         if (header.version == 1)
3594         {
3595                 iqmpose1_t *inposes1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3596
3597                 if (header.num_poses)
3598                         pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3599                 for (i = 0;i < (int)header.num_poses;i++)
3600                 {
3601                         float f;
3602                         iqmpose1_t inpose;
3603
3604                         memcpy(&inpose, &inposes1[i], sizeof(iqmpose1_t));
3605                         pose1[i].parent = LittleLong(inpose.parent);
3606                         pose1[i].channelmask = LittleLong(inpose.channelmask);
3607                         for (j = 0;j < 9;j++)
3608                         {
3609                                 pose1[i].channeloffset[j] = LittleFloat(inpose.channeloffset[j]);
3610                                 pose1[i].channelscale[j] = LittleFloat(inpose.channelscale[j]);
3611                         }
3612                         f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3613                         f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3614                         f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3615                         f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3616                         f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3617                         f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3618                 }
3619                 if (header.num_frames <= 0)
3620                 {
3621                         for (i = 0;i < loadmodel->num_bones;i++)
3622                         {
3623                                 float f;
3624                                 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3625                                 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3626                                 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3627                         }
3628                 }
3629         }
3630         else
3631         {
3632                 iqmpose_t *inposes = (iqmpose_t *)(pbase + header.ofs_poses);
3633
3634                 if (header.num_poses)
3635                         pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3636                 for (i = 0;i < (int)header.num_poses;i++)
3637                 {
3638                         float f;
3639                         iqmpose_t inpose;
3640
3641                         memcpy(&inpose, &inposes[i], sizeof(iqmpose_t));
3642                         pose[i].parent = LittleLong(inpose.parent);
3643                         pose[i].channelmask = LittleLong(inpose.channelmask);
3644                         for (j = 0;j < 10;j++)
3645                         {
3646                                 pose[i].channeloffset[j] = LittleFloat(inpose.channeloffset[j]);
3647                                 pose[i].channelscale[j] = LittleFloat(inpose.channelscale[j]);
3648                         }
3649                         f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3650                         f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3651                         f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3652                         f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3653                         f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3654                         f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3655                 }
3656                 if (header.num_frames <= 0)
3657                 {
3658                         for (i = 0;i < loadmodel->num_bones;i++)
3659                         {
3660                                 float f;
3661                                 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3662                                 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3663                                 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3664                         }
3665                 }
3666         }
3667         loadmodel->num_posescale = biggestorigin / 32767.0f;
3668         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3669
3670         // load the pose data
3671         // this unaligned memory access is safe (LittleShort reads as bytes)
3672         framedata = (const unsigned short *)(pbase + header.ofs_frames);
3673         if (header.version == 1)
3674         {
3675                 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3676                 {
3677                         for (j = 0;j < (int)header.num_poses;j++, k++)
3678                         {
3679                                 float qx, qy, qz, qw;
3680                                 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));
3681                                 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));
3682                                 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));
3683                                 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3684                                 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3685                                 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3686                                 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3687                                 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3688                                 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3689                                 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3690                                 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3691                                 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3692                                 // skip scale data for now
3693                                 if(pose1[j].channelmask&64) framedata++;
3694                                 if(pose1[j].channelmask&128) framedata++;
3695                                 if(pose1[j].channelmask&256) framedata++;
3696                         }
3697                 }
3698                 if (header.num_frames <= 0)
3699                 {
3700                         for (i = 0;i < loadmodel->num_bones;i++)
3701                         {
3702                                 float qx, qy, qz, qw;
3703                                 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3704                                 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3705                                 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3706                                 qx = joint1[i].rotation[0];
3707                                 qy = joint1[i].rotation[1];
3708                                 qz = joint1[i].rotation[2];
3709                                 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3710                                 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3711                                 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3712                                 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3713                                 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3714                                 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3715                         }
3716                 }
3717         }
3718         else
3719         {
3720                 for (i = 0, k = 0;i < (int)header.num_frames;i++)       
3721                 {
3722                         for (j = 0;j < (int)header.num_poses;j++, k++)
3723                         {
3724                                 float rot[4];
3725                                 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));
3726                                 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));
3727                                 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));
3728                                 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3729                                 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3730                                 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3731                                 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3732                                 if (rot[3] > 0)
3733                                         Vector4Negate(rot, rot);
3734                                 Vector4Normalize2(rot, rot);
3735                                 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3736                                 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3737                                 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3738                                 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3739                                 // skip scale data for now
3740                                 if(pose[j].channelmask&128) framedata++;
3741                                 if(pose[j].channelmask&256) framedata++;
3742                                 if(pose[j].channelmask&512) framedata++;
3743                         }
3744                 }
3745                 if (header.num_frames <= 0)
3746                 {
3747                         for (i = 0;i < loadmodel->num_bones;i++)
3748                         {
3749                                 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3750                                 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3751                                 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3752                                 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3753                                 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3754                                 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3755                                 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3756                         }
3757                 }
3758         }
3759
3760         // load bounding box data
3761         if (header.ofs_bounds)
3762         {
3763                 float xyradius = 0, radius = 0;
3764                 VectorClear(loadmodel->normalmins);
3765                 VectorClear(loadmodel->normalmaxs);
3766                 for (i = 0; i < (int)header.num_frames;i++)
3767                 {
3768                         iqmbounds_t bound;
3769                         bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3770                         bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3771                         bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3772                         bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);                 
3773                         bound.maxs[1] = LittleFloat(bounds[i].maxs[1]); 
3774                         bound.maxs[2] = LittleFloat(bounds[i].maxs[2]); 
3775                         bound.xyradius = LittleFloat(bounds[i].xyradius);
3776                         bound.radius = LittleFloat(bounds[i].radius);
3777                         if (!i)
3778                         {
3779                                 VectorCopy(bound.mins, loadmodel->normalmins);
3780                                 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3781                         }
3782                         else
3783                         {
3784                                 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3785                                 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3786                                 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3787                                 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3788                                 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3789                                 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3790                         }
3791                         if (bound.xyradius > xyradius)
3792                                 xyradius = bound.xyradius;
3793                         if (bound.radius > radius)
3794                                 radius = bound.radius;
3795                 }
3796                 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3797                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3798                 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3799                 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3800                 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3801                 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3802                 loadmodel->radius = radius;
3803                 loadmodel->radius2 = radius * radius;
3804         }
3805
3806         // load triangle data
3807         // this unaligned memory access is safe (LittleLong reads as bytes)
3808         inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3809         outelements = loadmodel->surfmesh.data_element3i;
3810         for (i = 0;i < (int)header.num_triangles;i++)
3811         {
3812                 outelements[0] = LittleLong(inelements[0]);
3813                 outelements[1] = LittleLong(inelements[1]);
3814                 outelements[2] = LittleLong(inelements[2]);
3815                 outelements += 3;
3816                 inelements += 3;
3817         }
3818         if (loadmodel->surfmesh.data_element3s)
3819                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3820                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3821         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3822
3823         // load vertex data
3824         // this unaligned memory access is safe (LittleFloat reads as bytes)
3825         outvertex = loadmodel->surfmesh.data_vertex3f;
3826         for (i = 0;i < (int)header.num_vertexes;i++)
3827         {
3828                 outvertex[0] = LittleFloat(vposition[0]);
3829                 outvertex[1] = LittleFloat(vposition[1]);
3830                 outvertex[2] = LittleFloat(vposition[2]);
3831                 vposition += 3;
3832                 outvertex += 3;
3833         }
3834
3835         outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3836         // this unaligned memory access is safe (LittleFloat reads as bytes)
3837         for (i = 0;i < (int)header.num_vertexes;i++)
3838         {
3839                 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3840                 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3841                 vtexcoord += 2;
3842                 outtexcoord += 2;
3843         }
3844
3845         // this unaligned memory access is safe (LittleFloat reads as bytes)
3846         if(vnormal)
3847         {
3848                 outnormal = loadmodel->surfmesh.data_normal3f;
3849                 for (i = 0;i < (int)header.num_vertexes;i++)
3850                 {
3851                         outnormal[0] = LittleFloat(vnormal[0]);
3852                         outnormal[1] = LittleFloat(vnormal[1]);
3853                         outnormal[2] = LittleFloat(vnormal[2]);
3854                         vnormal += 3;
3855                         outnormal += 3;
3856                 }
3857         }
3858
3859         // this unaligned memory access is safe (LittleFloat reads as bytes)
3860         if(vnormal && vtangent)
3861         {
3862                 outnormal = loadmodel->surfmesh.data_normal3f;
3863                 outsvector = loadmodel->surfmesh.data_svector3f;
3864                 outtvector = loadmodel->surfmesh.data_tvector3f;
3865                 for (i = 0;i < (int)header.num_vertexes;i++)
3866                 {
3867                         outsvector[0] = LittleFloat(vtangent[0]);
3868                         outsvector[1] = LittleFloat(vtangent[1]);
3869                         outsvector[2] = LittleFloat(vtangent[2]);
3870                         if(LittleFloat(vtangent[3]) < 0)
3871                                 CrossProduct(outsvector, outnormal, outtvector);
3872                         else
3873                                 CrossProduct(outnormal, outsvector, outtvector);
3874                         vtangent += 4;
3875                         outnormal += 3;
3876                         outsvector += 3;
3877                         outtvector += 3;
3878                 }
3879         }
3880
3881         // this unaligned memory access is safe (all bytes)
3882         if (vblendindexes && vblendweights)
3883         {
3884                 for (i = 0; i < (int)header.num_vertexes;i++)
3885                 {
3886                         blendweights_t weights;
3887                         memcpy(weights.index, vblendindexes + i*4, 4);
3888                         memcpy(weights.influence, vblendweights + i*4, 4);
3889                         loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3890                         loadmodel->surfmesh.data_skeletalindex4ub[i*4  ] = weights.index[0];
3891                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3892                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3893                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3894                         loadmodel->surfmesh.data_skeletalweight4ub[i*4  ] = weights.influence[0];
3895                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3896                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3897                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3898                 }
3899         }
3900
3901         if (vcolor4f)
3902         {
3903                 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3904                 // this unaligned memory access is safe (LittleFloat reads as bytes)
3905                 for (i = 0;i < (int)header.num_vertexes;i++)
3906                 {
3907                         outcolor[0] = LittleFloat(vcolor4f[0]);
3908                         outcolor[1] = LittleFloat(vcolor4f[1]);
3909                         outcolor[2] = LittleFloat(vcolor4f[2]);
3910                         outcolor[3] = LittleFloat(vcolor4f[3]);
3911                         vcolor4f += 4;
3912                         outcolor += 4;
3913                 }
3914         }
3915         else if (vcolor4ub)
3916         {
3917                 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3918                 // this unaligned memory access is safe (all bytes)
3919                 for (i = 0;i < (int)header.num_vertexes;i++)
3920                 {
3921                         outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3922                         outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3923                         outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3924                         outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3925                         vcolor4ub += 4;
3926                         outcolor += 4;
3927                 }
3928         }
3929
3930         // load meshes
3931         for (i = 0;i < (int)header.num_meshes;i++)
3932         {
3933                 iqmmesh_t mesh;
3934                 msurface_t *surface;
3935
3936                 memcpy(&mesh, &meshes[i], sizeof(iqmmesh_t));
3937                 mesh.name = LittleLong(mesh.name);
3938                 mesh.material = LittleLong(mesh.material);
3939                 mesh.first_vertex = LittleLong(mesh.first_vertex);
3940                 mesh.num_vertexes = LittleLong(mesh.num_vertexes);
3941                 mesh.first_triangle = LittleLong(mesh.first_triangle);
3942                 mesh.num_triangles = LittleLong(mesh.num_triangles);
3943
3944                 loadmodel->modelsurfaces_sorted[i] = i;
3945                 surface = loadmodel->data_surfaces + i;
3946                 surface->texture = loadmodel->data_textures + i;
3947                 surface->num_firsttriangle = mesh.first_triangle;
3948                 surface->num_triangles = mesh.num_triangles;
3949                 surface->num_firstvertex = mesh.first_vertex;
3950                 surface->num_vertices = mesh.num_vertexes;
3951
3952                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3953         }
3954
3955         Mod_FreeSkinFiles(skinfiles);
3956         Mod_MakeSortedSurfaces(loadmodel);
3957
3958         // compute all the mesh information that was not loaded from the file
3959         if (!vnormal)
3960                 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);
3961         if (!vnormal || !vtangent)
3962                 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);
3963         if (!header.ofs_bounds)
3964                 Mod_Alias_CalculateBoundingBox();
3965
3966         // Always make a BIH for the first frame, we can use it where possible.
3967         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3968         if (!loadmodel->surfmesh.isanimated)
3969         {
3970                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3971                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3972                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3973                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3974                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3975         }
3976
3977         if (joint)  { Mem_Free(joint);  joint  = NULL; }
3978         if (joint1) { Mem_Free(joint1); joint1 = NULL; }
3979         if (pose)   { Mem_Free(pose);   pose   = NULL; }
3980         if (pose1)  { Mem_Free(pose1);  pose1  = NULL; }
3981 }