]> git.xonotic.org Git - xonotic/darkplaces.git/blob - model_alias.c
Merge PR 'Use the text from modinfo.txt as the mod menu entry'
[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                 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 = ((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                         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                 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 = ((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                 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                 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         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[2]) + meshvertices * loadmodel->numframes * sizeof(md3vertex_t));
1678         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1679         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1680         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1681         loadmodel->surfmesh.num_vertices = meshvertices;
1682         loadmodel->surfmesh.num_triangles = meshtriangles;
1683         loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1684         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1685         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1686         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1687         loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1688         if (meshvertices <= 65536)
1689         {
1690                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1691         }
1692
1693         meshvertices = 0;
1694         meshtriangles = 0;
1695         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)))
1696         {
1697                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1698                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1699                 loadmodel->modelsurfaces_sorted[i] = i;
1700                 surface = loadmodel->data_surfaces + i;
1701                 surface->texture = loadmodel->data_textures + i;
1702                 surface->num_firsttriangle = meshtriangles;
1703                 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1704                 surface->num_firstvertex = meshvertices;
1705                 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1706                 meshvertices += surface->num_vertices;
1707                 meshtriangles += surface->num_triangles;
1708
1709                 for (j = 0;j < surface->num_triangles * 3;j++)
1710                 {
1711                         int e = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1712                         loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = e;
1713                         if (loadmodel->surfmesh.data_element3s)
1714                                 loadmodel->surfmesh.data_element3s[j + surface->num_firsttriangle * 3] = e;
1715                 }
1716                 for (j = 0;j < surface->num_vertices;j++)
1717                 {
1718                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1719                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1720                 }
1721                 for (j = 0;j < loadmodel->numframes;j++)
1722                 {
1723                         const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1724                         md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1725                         for (k = 0;k < surface->num_vertices;k++, in++, out++)
1726                         {
1727                                 out->origin[0] = LittleShort(in->origin[0]);
1728                                 out->origin[1] = LittleShort(in->origin[1]);
1729                                 out->origin[2] = LittleShort(in->origin[2]);
1730                                 out->pitch = in->pitch;
1731                                 out->yaw = in->yaw;
1732                         }
1733                 }
1734
1735                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1736
1737                 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__);
1738         }
1739         Mod_Alias_MorphMesh_CompileFrames();
1740         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1741         Mod_FreeSkinFiles(skinfiles);
1742         Mod_MakeSortedSurfaces(loadmodel);
1743         if(mod_alias_force_animated.string[0])
1744                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1745
1746         // Always make a BIH for the first frame, we can use it where possible.
1747         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1748         if (!loadmodel->surfmesh.isanimated)
1749         {
1750                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1751                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1752                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1753                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1754                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1755         }
1756 }
1757
1758 void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend)
1759 {
1760         zymtype1header_t *pinmodel, *pheader;
1761         unsigned char *pbase;
1762         int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1763         float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1764         zymvertex_t *verts, *vertdata;
1765         zymscene_t *scene;
1766         zymbone_t *bone;
1767         char *shadername;
1768         skinfile_t *skinfiles;
1769         unsigned char *data;
1770         msurface_t *surface;
1771
1772         pinmodel = (zymtype1header_t *)buffer;
1773         pbase = (unsigned char *)buffer;
1774         if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1775                 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1776         if (BigLong(pinmodel->type) != 1)
1777                 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1778
1779         loadmodel->modeldatatypestring = "ZYM";
1780
1781         loadmodel->type = mod_alias;
1782         loadmodel->synctype = ST_RAND;
1783
1784         // byteswap header
1785         pheader = pinmodel;
1786         pheader->type = BigLong(pinmodel->type);
1787         pheader->filesize = BigLong(pinmodel->filesize);
1788         pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1789         pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1790         pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1791         pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1792         pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1793         pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1794         pheader->radius = BigFloat(pinmodel->radius);
1795         pheader->numverts = BigLong(pinmodel->numverts);
1796         pheader->numtris = BigLong(pinmodel->numtris);
1797         pheader->numshaders = BigLong(pinmodel->numshaders);
1798         pheader->numbones = BigLong(pinmodel->numbones);
1799         pheader->numscenes = BigLong(pinmodel->numscenes);
1800         pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1801         pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1802         pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1803         pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1804         pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1805         pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1806         pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1807         pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1808         pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1809         pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1810         pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1811         pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1812         pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1813         pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1814         pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1815         pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1816         pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1817         pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1818
1819         if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1820         {
1821                 Con_Printf("%s has no geometry\n", loadmodel->name);
1822                 return;
1823         }
1824         if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1825         {
1826                 Con_Printf("%s has no animations\n", loadmodel->name);
1827                 return;
1828         }
1829
1830         loadmodel->Draw = R_Mod_Draw;
1831         loadmodel->DrawDepth = R_Mod_DrawDepth;
1832         loadmodel->DrawDebug = R_Mod_DrawDebug;
1833         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1834         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1835         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1836         loadmodel->DrawLight = R_Mod_DrawLight;
1837         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1838         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1839         loadmodel->PointSuperContents = NULL;
1840         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1841
1842         loadmodel->numframes = pheader->numscenes;
1843         loadmodel->num_surfaces = pheader->numshaders;
1844
1845         skinfiles = Mod_LoadSkinFiles();
1846         if (loadmodel->numskins < 1)
1847                 loadmodel->numskins = 1;
1848
1849         // make skinscenes for the skins (no groups)
1850         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1851         for (i = 0;i < loadmodel->numskins;i++)
1852         {
1853                 loadmodel->skinscenes[i].firstframe = i;
1854                 loadmodel->skinscenes[i].framecount = 1;
1855                 loadmodel->skinscenes[i].loop = true;
1856                 loadmodel->skinscenes[i].framerate = 10;
1857         }
1858
1859         // model bbox
1860         // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1861         modelradius = pheader->radius;
1862         for (i = 0;i < 3;i++)
1863         {
1864                 loadmodel->normalmins[i] = pheader->mins[i];
1865                 loadmodel->normalmaxs[i] = pheader->maxs[i];
1866                 loadmodel->rotatedmins[i] = -modelradius;
1867                 loadmodel->rotatedmaxs[i] = modelradius;
1868         }
1869         corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1870         corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1871         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1872         if (loadmodel->yawmaxs[0] > modelradius)
1873                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1874         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1875         loadmodel->yawmins[2] = loadmodel->normalmins[2];
1876         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1877         loadmodel->radius = modelradius;
1878         loadmodel->radius2 = modelradius * modelradius;
1879
1880         // go through the lumps, swapping things
1881
1882         //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1883         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1884         scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1885         numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1886         for (i = 0;i < pheader->numscenes;i++)
1887         {
1888                 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1889                 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1890                 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1891                 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1892                 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1893                 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1894                         Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1895                 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1896                         Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1897                 if (loadmodel->animscenes[i].framerate < 0)
1898                         Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1899                 scene++;
1900         }
1901
1902         //zymlump_t lump_bones; // zymbone_t bone[numbones];
1903         loadmodel->num_bones = pheader->numbones;
1904         loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1905         bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1906         for (i = 0;i < pheader->numbones;i++)
1907         {
1908                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1909                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1910                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1911                 if (loadmodel->data_bones[i].parent >= i)
1912                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1913         }
1914
1915         //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1916         vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1917         bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1918         for (i = 0;i < pheader->numverts;i++)
1919         {
1920                 vertbonecounts[i] = BigLong(bonecount[i]);
1921                 if (vertbonecounts[i] != 1)
1922                         Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1923         }
1924
1925         loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1926
1927         meshvertices = pheader->numverts;
1928         meshtriangles = pheader->numtris;
1929
1930         loadmodel->submodelsurfaces_start = 0;
1931         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1932         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1933         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1934         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4])) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]));
1935         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1936         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1937         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1938         loadmodel->surfmesh.num_vertices = meshvertices;
1939         loadmodel->surfmesh.num_triangles = meshtriangles;
1940         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1941         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1942         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1943         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1944         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1945         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1946         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1947         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1948         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1949         loadmodel->surfmesh.num_blends = 0;
1950         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
1951         if (loadmodel->surfmesh.num_vertices <= 65536)
1952         {
1953                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1954         }
1955         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
1956         loadmodel->surfmesh.data_blendweights = NULL;
1957
1958         //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1959         poses = (float *) (pheader->lump_poses.start + pbase);
1960         // figure out scale of model from root bone, for compatibility with old zmodel versions
1961         tempvec[0] = BigFloat(poses[0]);
1962         tempvec[1] = BigFloat(poses[1]);
1963         tempvec[2] = BigFloat(poses[2]);
1964         modelscale = VectorLength(tempvec);
1965         biggestorigin = 0;
1966         for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
1967         {
1968                 f = fabs(BigFloat(poses[i]));
1969                 biggestorigin = max(biggestorigin, f);
1970         }
1971         loadmodel->num_posescale = biggestorigin / 32767.0f;
1972         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
1973         for (i = 0;i < numposes;i++)
1974         {
1975                 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
1976                 for (j = 0;j < loadmodel->num_bones;j++)
1977                 {
1978                         float pose[12];
1979                         matrix4x4_t posematrix;
1980                         for (k = 0;k < 12;k++)
1981                                 pose[k] = BigFloat(frameposes[j*12+k]);
1982                         //if (j < loadmodel->num_bones)
1983                         //      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));
1984                         // scale child bones to match the root scale
1985                         if (loadmodel->data_bones[j].parent >= 0)
1986                         {
1987                                 pose[3] *= modelscale;
1988                                 pose[7] *= modelscale;
1989                                 pose[11] *= modelscale;
1990                         }
1991                         // normalize rotation matrix
1992                         VectorNormalize(pose + 0);
1993                         VectorNormalize(pose + 4);
1994                         VectorNormalize(pose + 8);
1995                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
1996                         Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
1997                 }
1998         }
1999
2000         //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2001         verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2002         vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2003         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2004         // (converting from weight-blending skeletal animation to
2005         //  deformation-based skeletal animation)
2006         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2007         for (i = 0;i < loadmodel->num_bones;i++)
2008         {
2009                 float m[12];
2010                 for (k = 0;k < 12;k++)
2011                         m[k] = BigFloat(poses[i*12+k]);
2012                 if (loadmodel->data_bones[i].parent >= 0)
2013                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2014                 else
2015                         for (k = 0;k < 12;k++)
2016                                 bonepose[12*i+k] = m[k];
2017         }
2018         for (j = 0;j < pheader->numverts;j++)
2019         {
2020                 // this format really should have had a per vertexweight weight value...
2021                 // but since it does not, the weighting is completely ignored and
2022                 // only one weight is allowed per vertex
2023                 int boneindex = BigLong(vertdata[j].bonenum);
2024                 const float *m = bonepose + 12 * boneindex;
2025                 float relativeorigin[3];
2026                 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2027                 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2028                 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2029                 // transform the vertex bone weight into the base mesh
2030                 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2031                 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2032                 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2033                 // store the weight as the primary weight on this vertex
2034                 loadmodel->surfmesh.blends[j] = boneindex;
2035                 loadmodel->surfmesh.data_skeletalindex4ub[j*4  ] = boneindex;
2036                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2037                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2038                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2039                 loadmodel->surfmesh.data_skeletalweight4ub[j*4  ] = 255;
2040                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2041                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2042                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2043         }
2044         Z_Free(bonepose);
2045         // normals and tangents are calculated after elements are loaded
2046
2047         //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2048         outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2049         intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2050         for (i = 0;i < pheader->numverts;i++)
2051         {
2052                 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2053                 // flip T coordinate for OpenGL
2054                 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2055         }
2056
2057         //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2058         //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2059         //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2060
2061         //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2062         //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)
2063         // byteswap, validate, and swap winding order of tris
2064         count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2065         if (pheader->lump_render.length != count)
2066                 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2067         renderlist = (int *) (pheader->lump_render.start + pbase);
2068         renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2069         meshtriangles = 0;
2070         for (i = 0;i < loadmodel->num_surfaces;i++)
2071         {
2072                 int firstvertex, lastvertex;
2073                 if (renderlist >= renderlistend)
2074                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2075                 count = BigLong(*renderlist);renderlist++;
2076                 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2077                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2078
2079                 loadmodel->modelsurfaces_sorted[i] = i;
2080                 surface = loadmodel->data_surfaces + i;
2081                 surface->texture = loadmodel->data_textures + i;
2082                 surface->num_firsttriangle = meshtriangles;
2083                 surface->num_triangles = count;
2084                 meshtriangles += surface->num_triangles;
2085
2086                 // load the elements
2087                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2088                 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2089                 {
2090                         outelements[j*3+2] = BigLong(renderlist[0]);
2091                         outelements[j*3+1] = BigLong(renderlist[1]);
2092                         outelements[j*3+0] = BigLong(renderlist[2]);
2093                 }
2094                 // validate the elements and find the used vertex range
2095                 firstvertex = meshvertices;
2096                 lastvertex = 0;
2097                 for (j = 0;j < surface->num_triangles * 3;j++)
2098                 {
2099                         if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2100                                 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2101                         firstvertex = min(firstvertex, outelements[j]);
2102                         lastvertex = max(lastvertex, outelements[j]);
2103                 }
2104                 surface->num_firstvertex = firstvertex;
2105                 surface->num_vertices = lastvertex + 1 - firstvertex;
2106
2107                 // since zym models do not have named sections, reuse their shader
2108                 // name as the section name
2109                 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2110                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2111         }
2112         Mod_FreeSkinFiles(skinfiles);
2113         Mem_Free(vertbonecounts);
2114         Mem_Free(verts);
2115         Mod_MakeSortedSurfaces(loadmodel);
2116
2117         // compute all the mesh information that was not loaded from the file
2118         if (loadmodel->surfmesh.data_element3s)
2119                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2120                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2121         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2122         Mod_BuildBaseBonePoses();
2123         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);
2124         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);
2125         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2126         if(mod_alias_force_animated.string[0])
2127                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2128
2129         // Always make a BIH for the first frame, we can use it where possible.
2130         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2131         if (!loadmodel->surfmesh.isanimated)
2132         {
2133                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2134                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2135                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2136                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2137                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2138         }
2139 }
2140
2141 void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend)
2142 {
2143         dpmheader_t *pheader;
2144         dpmframe_t *frames;
2145         dpmbone_t *bone;
2146         dpmmesh_t *dpmmesh;
2147         unsigned char *pbase;
2148         int i, j, k, meshvertices, meshtriangles;
2149         skinfile_t *skinfiles;
2150         unsigned char *data;
2151         float *bonepose;
2152         float biggestorigin, tempvec[3], modelscale;
2153         float f;
2154         float *poses;
2155
2156         pheader = (dpmheader_t *)buffer;
2157         pbase = (unsigned char *)buffer;
2158         if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2159                 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2160         if (BigLong(pheader->type) != 2)
2161                 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2162
2163         loadmodel->modeldatatypestring = "DPM";
2164
2165         loadmodel->type = mod_alias;
2166         loadmodel->synctype = ST_RAND;
2167
2168         // byteswap header
2169         pheader->type = BigLong(pheader->type);
2170         pheader->filesize = BigLong(pheader->filesize);
2171         pheader->mins[0] = BigFloat(pheader->mins[0]);
2172         pheader->mins[1] = BigFloat(pheader->mins[1]);
2173         pheader->mins[2] = BigFloat(pheader->mins[2]);
2174         pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2175         pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2176         pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2177         pheader->yawradius = BigFloat(pheader->yawradius);
2178         pheader->allradius = BigFloat(pheader->allradius);
2179         pheader->num_bones = BigLong(pheader->num_bones);
2180         pheader->num_meshs = BigLong(pheader->num_meshs);
2181         pheader->num_frames = BigLong(pheader->num_frames);
2182         pheader->ofs_bones = BigLong(pheader->ofs_bones);
2183         pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2184         pheader->ofs_frames = BigLong(pheader->ofs_frames);
2185
2186         if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2187         {
2188                 Con_Printf("%s has no geometry\n", loadmodel->name);
2189                 return;
2190         }
2191         if (pheader->num_frames < 1)
2192         {
2193                 Con_Printf("%s has no frames\n", loadmodel->name);
2194                 return;
2195         }
2196
2197         loadmodel->Draw = R_Mod_Draw;
2198         loadmodel->DrawDepth = R_Mod_DrawDepth;
2199         loadmodel->DrawDebug = R_Mod_DrawDebug;
2200         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2201         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2202         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2203         loadmodel->DrawLight = R_Mod_DrawLight;
2204         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2205         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2206         loadmodel->PointSuperContents = NULL;
2207         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2208
2209         // model bbox
2210         // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2211         for (i = 0;i < 3;i++)
2212         {
2213                 loadmodel->normalmins[i] = pheader->mins[i];
2214                 loadmodel->normalmaxs[i] = pheader->maxs[i];
2215                 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2216                 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2217                 loadmodel->rotatedmins[i] = -pheader->allradius;
2218                 loadmodel->rotatedmaxs[i] = pheader->allradius;
2219         }
2220         loadmodel->radius = pheader->allradius;
2221         loadmodel->radius2 = pheader->allradius * pheader->allradius;
2222
2223         // load external .skin files if present
2224         skinfiles = Mod_LoadSkinFiles();
2225         if (loadmodel->numskins < 1)
2226                 loadmodel->numskins = 1;
2227
2228         meshvertices = 0;
2229         meshtriangles = 0;
2230
2231         // gather combined statistics from the meshes
2232         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2233         for (i = 0;i < (int)pheader->num_meshs;i++)
2234         {
2235                 int numverts = BigLong(dpmmesh->num_verts);
2236                 meshvertices += numverts;
2237                 meshtriangles += BigLong(dpmmesh->num_tris);
2238                 dpmmesh++;
2239         }
2240
2241         loadmodel->numframes = pheader->num_frames;
2242         loadmodel->num_bones = pheader->num_bones;
2243         loadmodel->num_poses = loadmodel->numframes;
2244         loadmodel->submodelsurfaces_start = 0;
2245         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = pheader->num_meshs;
2246         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2247         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2248         // do most allocations as one merged chunk
2249         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4])) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t));
2250         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2251         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2252         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2253         loadmodel->surfmesh.num_vertices = meshvertices;
2254         loadmodel->surfmesh.num_triangles = meshtriangles;
2255         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2256         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2257         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2258         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2259         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2260         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2261         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2262         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2263         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2264         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2265         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2266         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2267         loadmodel->surfmesh.num_blends = 0;
2268         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2269         if (meshvertices <= 65536)
2270         {
2271                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2272         }
2273         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2274         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2275
2276         for (i = 0;i < loadmodel->numskins;i++)
2277         {
2278                 loadmodel->skinscenes[i].firstframe = i;
2279                 loadmodel->skinscenes[i].framecount = 1;
2280                 loadmodel->skinscenes[i].loop = true;
2281                 loadmodel->skinscenes[i].framerate = 10;
2282         }
2283
2284         // load the bone info
2285         bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2286         for (i = 0;i < loadmodel->num_bones;i++)
2287         {
2288                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2289                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2290                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2291                 if (loadmodel->data_bones[i].parent >= i)
2292                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2293         }
2294
2295         // load the frames
2296         frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2297         // figure out scale of model from root bone, for compatibility with old dpmodel versions
2298         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2299         tempvec[0] = BigFloat(poses[0]);
2300         tempvec[1] = BigFloat(poses[1]);
2301         tempvec[2] = BigFloat(poses[2]);
2302         modelscale = VectorLength(tempvec);
2303         biggestorigin = 0;
2304         for (i = 0;i < loadmodel->numframes;i++)
2305         {
2306                 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2307                 loadmodel->animscenes[i].firstframe = i;
2308                 loadmodel->animscenes[i].framecount = 1;
2309                 loadmodel->animscenes[i].loop = true;
2310                 loadmodel->animscenes[i].framerate = 10;
2311                 // load the bone poses for this frame
2312                 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2313                 for (j = 0;j < loadmodel->num_bones*12;j++)
2314                 {
2315                         f = fabs(BigFloat(poses[j]));
2316                         biggestorigin = max(biggestorigin, f);
2317                 }
2318                 // stuff not processed here: mins, maxs, yawradius, allradius
2319         }
2320         loadmodel->num_posescale = biggestorigin / 32767.0f;
2321         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2322         for (i = 0;i < loadmodel->numframes;i++)
2323         {
2324                 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2325                 for (j = 0;j < loadmodel->num_bones;j++)
2326                 {
2327                         float pose[12];
2328                         matrix4x4_t posematrix;
2329                         for (k = 0;k < 12;k++)
2330                                 pose[k] = BigFloat(frameposes[j*12+k]);
2331                         // scale child bones to match the root scale
2332                         if (loadmodel->data_bones[j].parent >= 0)
2333                         {
2334                                 pose[3] *= modelscale;
2335                                 pose[7] *= modelscale;
2336                                 pose[11] *= modelscale;
2337                         }
2338                         // normalize rotation matrix
2339                         VectorNormalize(pose + 0);
2340                         VectorNormalize(pose + 4);
2341                         VectorNormalize(pose + 8);
2342                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2343                         Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2344                 }
2345         }
2346
2347         // load the meshes now
2348         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2349         meshvertices = 0;
2350         meshtriangles = 0;
2351         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2352         // (converting from weight-blending skeletal animation to
2353         //  deformation-based skeletal animation)
2354         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2355         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2356         for (i = 0;i < loadmodel->num_bones;i++)
2357         {
2358                 float m[12];
2359                 for (k = 0;k < 12;k++)
2360                         m[k] = BigFloat(poses[i*12+k]);
2361                 if (loadmodel->data_bones[i].parent >= 0)
2362                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2363                 else
2364                         for (k = 0;k < 12;k++)
2365                                 bonepose[12*i+k] = m[k];
2366         }
2367         for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2368         {
2369                 const int *inelements;
2370                 int *outelement3i;
2371                 unsigned short *outelement3s;
2372                 const float *intexcoord;
2373                 msurface_t *surface;
2374
2375                 loadmodel->modelsurfaces_sorted[i] = i;
2376                 surface = loadmodel->data_surfaces + i;
2377                 surface->texture = loadmodel->data_textures + i;
2378                 surface->num_firsttriangle = meshtriangles;
2379                 surface->num_triangles = BigLong(dpmmesh->num_tris);
2380                 surface->num_firstvertex = meshvertices;
2381                 surface->num_vertices = BigLong(dpmmesh->num_verts);
2382                 meshvertices += surface->num_vertices;
2383                 meshtriangles += surface->num_triangles;
2384
2385                 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2386                 outelement3i = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2387                 outelement3s = loadmodel->surfmesh.data_element3s ? loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3 : NULL;
2388                 for (j = 0;j < surface->num_triangles;j++)
2389                 {
2390                         // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2391                         outelement3i[j * 3 + 0] = surface->num_firstvertex + BigLong(inelements[j * 3 + 2]);
2392                         outelement3i[j * 3 + 1] = surface->num_firstvertex + BigLong(inelements[j * 3 + 1]);
2393                         outelement3i[j * 3 + 2] = surface->num_firstvertex + BigLong(inelements[j * 3 + 0]);
2394                         if (outelement3s)
2395                         {
2396                                 outelement3s[j * 3 + 0] = outelement3i[j * 3 + 0];
2397                                 outelement3s[j * 3 + 1] = outelement3i[j * 3 + 1];
2398                                 outelement3s[j * 3 + 2] = outelement3i[j * 3 + 2];
2399                         }
2400                 }
2401
2402                 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2403                 for (j = 0;j < surface->num_vertices*2;j++)
2404                         loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2405
2406                 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2407                 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2408                 {
2409                         int weightindex[4] = { 0, 0, 0, 0 };
2410                         float weightinfluence[4] = { 0, 0, 0, 0 };
2411                         int l;
2412                         int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2413                         data += sizeof(dpmvertex_t);
2414                         for (k = 0;k < numweights;k++)
2415                         {
2416                                 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2417                                 int boneindex = BigLong(vert->bonenum);
2418                                 const float *m = bonepose + 12 * boneindex;
2419                                 float influence = BigFloat(vert->influence);
2420                                 float relativeorigin[3], relativenormal[3];
2421                                 relativeorigin[0] = BigFloat(vert->origin[0]);
2422                                 relativeorigin[1] = BigFloat(vert->origin[1]);
2423                                 relativeorigin[2] = BigFloat(vert->origin[2]);
2424                                 relativenormal[0] = BigFloat(vert->normal[0]);
2425                                 relativenormal[1] = BigFloat(vert->normal[1]);
2426                                 relativenormal[2] = BigFloat(vert->normal[2]);
2427                                 // blend the vertex bone weights into the base mesh
2428                                 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2429                                 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2430                                 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2431                                 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2432                                 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2433                                 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2434                                 if (!k)
2435                                 {
2436                                         // store the first (and often only) weight
2437                                         weightinfluence[0] = influence;
2438                                         weightindex[0] = boneindex;
2439                                 }
2440                                 else
2441                                 {
2442                                         // sort the new weight into this vertex's weight table
2443                                         // (which only accepts up to 4 bones per vertex)
2444                                         for (l = 0;l < 4;l++)
2445                                         {
2446                                                 if (weightinfluence[l] < influence)
2447                                                 {
2448                                                         // move weaker influence weights out of the way first
2449                                                         int l2;
2450                                                         for (l2 = 3;l2 > l;l2--)
2451                                                         {
2452                                                                 weightinfluence[l2] = weightinfluence[l2-1];
2453                                                                 weightindex[l2] = weightindex[l2-1];
2454                                                         }
2455                                                         // store the new weight
2456                                                         weightinfluence[l] = influence;
2457                                                         weightindex[l] = boneindex;
2458                                                         break;
2459                                                 }
2460                                         }
2461                                 }
2462                                 data += sizeof(dpmbonevert_t);
2463                         }
2464                         loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2465                         loadmodel->surfmesh.data_skeletalindex4ub[j*4  ] = weightindex[0];
2466                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2467                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2468                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2469                         loadmodel->surfmesh.data_skeletalweight4ub[j*4  ] = (unsigned char)(weightinfluence[0]*255.0f);
2470                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2471                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2472                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2473                 }
2474
2475                 // since dpm models do not have named sections, reuse their shader name as the section name
2476                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2477
2478                 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__);
2479         }
2480         if (loadmodel->surfmesh.num_blends < meshvertices)
2481                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2482         Z_Free(bonepose);
2483         Mod_FreeSkinFiles(skinfiles);
2484         Mod_MakeSortedSurfaces(loadmodel);
2485
2486         // compute all the mesh information that was not loaded from the file
2487         Mod_BuildBaseBonePoses();
2488         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);
2489         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2490         if(mod_alias_force_animated.string[0])
2491                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2492
2493         // Always make a BIH for the first frame, we can use it where possible.
2494         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2495         if (!loadmodel->surfmesh.isanimated)
2496         {
2497                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2498                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2499                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2500                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2501                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2502         }
2503 }
2504
2505 // no idea why PSK/PSA files contain weird quaternions but they do...
2506 #define PSKQUATNEGATIONS
2507 void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
2508 {
2509         int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2510         int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2511         fs_offset_t filesize;
2512         pskpnts_t *pnts;
2513         pskvtxw_t *vtxw;
2514         pskface_t *faces;
2515         pskmatt_t *matts;
2516         pskboneinfo_t *bones;
2517         pskrawweights_t *rawweights;
2518         //pskboneinfo_t *animbones;
2519         pskaniminfo_t *anims;
2520         pskanimkeys_t *animkeys;
2521         void *animfilebuffer, *animbuffer, *animbufferend;
2522         unsigned char *data;
2523         pskchunk_t *pchunk;
2524         skinfile_t *skinfiles;
2525         char animname[MAX_QPATH];
2526         size_t size;
2527         float biggestorigin;
2528
2529         pchunk = (pskchunk_t *)buffer;
2530         if (strcmp(pchunk->id, "ACTRHEAD"))
2531                 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2532
2533         loadmodel->modeldatatypestring = "PSK";
2534
2535         loadmodel->type = mod_alias;
2536         loadmodel->Draw = R_Mod_Draw;
2537         loadmodel->DrawDepth = R_Mod_DrawDepth;
2538         loadmodel->DrawDebug = R_Mod_DrawDebug;
2539         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2540         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2541         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2542         loadmodel->DrawLight = R_Mod_DrawLight;
2543         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2544         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2545         loadmodel->PointSuperContents = NULL;
2546         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2547         loadmodel->synctype = ST_RAND;
2548
2549         FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2550         strlcat(animname, ".psa", sizeof(animname));
2551         animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2552         animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2553         if (!animbuffer)
2554                 animbufferend = animbuffer;
2555
2556         numpnts = 0;
2557         pnts = NULL;
2558         numvtxw = 0;
2559         vtxw = NULL;
2560         numfaces = 0;
2561         faces = NULL;
2562         nummatts = 0;
2563         matts = NULL;
2564         numbones = 0;
2565         bones = NULL;
2566         numrawweights = 0;
2567         rawweights = NULL;
2568         numanims = 0;
2569         anims = NULL;
2570         numanimkeys = 0;
2571         animkeys = NULL;
2572
2573         while (buffer < bufferend)
2574         {
2575                 pchunk = (pskchunk_t *)buffer;
2576                 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2577                 version = LittleLong(pchunk->version);
2578                 recordsize = LittleLong(pchunk->recordsize);
2579                 numrecords = LittleLong(pchunk->numrecords);
2580                 if (developer_extra.integer)
2581                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2582                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2583                         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);
2584                 if (!strcmp(pchunk->id, "ACTRHEAD"))
2585                 {
2586                         // nothing to do
2587                 }
2588                 else if (!strcmp(pchunk->id, "PNTS0000"))
2589                 {
2590                         pskpnts_t *p;
2591                         if (recordsize != sizeof(*p))
2592                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2593                         // byteswap in place and keep the pointer
2594                         numpnts = numrecords;
2595                         pnts = (pskpnts_t *)buffer;
2596                         for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2597                         {
2598                                 p->origin[0] = LittleFloat(p->origin[0]);
2599                                 p->origin[1] = LittleFloat(p->origin[1]);
2600                                 p->origin[2] = LittleFloat(p->origin[2]);
2601                         }
2602                         buffer = p;
2603                 }
2604                 else if (!strcmp(pchunk->id, "VTXW0000"))
2605                 {
2606                         pskvtxw_t *p;
2607                         if (recordsize != sizeof(*p))
2608                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2609                         // byteswap in place and keep the pointer
2610                         numvtxw = numrecords;
2611                         vtxw = (pskvtxw_t *)buffer;
2612                         for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2613                         {
2614                                 p->pntsindex = LittleShort(p->pntsindex);
2615                                 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2616                                 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2617                                 if (p->pntsindex >= numpnts)
2618                                 {
2619                                         Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2620                                         p->pntsindex = 0;
2621                                 }
2622                         }
2623                         buffer = p;
2624                 }
2625                 else if (!strcmp(pchunk->id, "FACE0000"))
2626                 {
2627                         pskface_t *p;
2628                         if (recordsize != sizeof(*p))
2629                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2630                         // byteswap in place and keep the pointer
2631                         numfaces = numrecords;
2632                         faces = (pskface_t *)buffer;
2633                         for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2634                         {
2635                                 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2636                                 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2637                                 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2638                                 p->group = LittleLong(p->group);
2639                                 if (p->vtxwindex[0] >= numvtxw)
2640                                 {
2641                                         Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2642                                         p->vtxwindex[0] = 0;
2643                                 }
2644                                 if (p->vtxwindex[1] >= numvtxw)
2645                                 {
2646                                         Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2647                                         p->vtxwindex[1] = 0;
2648                                 }
2649                                 if (p->vtxwindex[2] >= numvtxw)
2650                                 {
2651                                         Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2652                                         p->vtxwindex[2] = 0;
2653                                 }
2654                         }
2655                         buffer = p;
2656                 }
2657                 else if (!strcmp(pchunk->id, "MATT0000"))
2658                 {
2659                         pskmatt_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                         nummatts = numrecords;
2664                         matts = (pskmatt_t *)buffer;
2665                         for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2666                         {
2667                                 // nothing to do
2668                         }
2669                         buffer = p;
2670                 }
2671                 else if (!strcmp(pchunk->id, "REFSKELT"))
2672                 {
2673                         pskboneinfo_t *p;
2674                         if (recordsize != sizeof(*p))
2675                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2676                         // byteswap in place and keep the pointer
2677                         numbones = numrecords;
2678                         bones = (pskboneinfo_t *)buffer;
2679                         for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2680                         {
2681                                 p->numchildren = LittleLong(p->numchildren);
2682                                 p->parent = LittleLong(p->parent);
2683                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2684                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2685                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2686                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2687                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2688                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2689                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2690                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2691                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2692                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2693                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2694 #ifdef PSKQUATNEGATIONS
2695                                 if (index)
2696                                 {
2697                                         p->basepose.quat[0] *= -1;
2698                                         p->basepose.quat[1] *= -1;
2699                                         p->basepose.quat[2] *= -1;
2700                                 }
2701                                 else
2702                                 {
2703                                         p->basepose.quat[0] *=  1;
2704                                         p->basepose.quat[1] *= -1;
2705                                         p->basepose.quat[2] *=  1;
2706                                 }
2707 #endif
2708                                 if (p->parent < 0 || p->parent >= numbones)
2709                                 {
2710                                         Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2711                                         p->parent = 0;
2712                                 }
2713                         }
2714                         buffer = p;
2715                 }
2716                 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2717                 {
2718                         pskrawweights_t *p;
2719                         if (recordsize != sizeof(*p))
2720                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2721                         // byteswap in place and keep the pointer
2722                         numrawweights = numrecords;
2723                         rawweights = (pskrawweights_t *)buffer;
2724                         for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2725                         {
2726                                 p->weight = LittleFloat(p->weight);
2727                                 p->pntsindex = LittleLong(p->pntsindex);
2728                                 p->boneindex = LittleLong(p->boneindex);
2729                                 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2730                                 {
2731                                         Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2732                                         p->pntsindex = 0;
2733                                 }
2734                                 if (p->boneindex < 0 || p->boneindex >= numbones)
2735                                 {
2736                                         Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2737                                         p->boneindex = 0;
2738                                 }
2739                         }
2740                         buffer = p;
2741                 }
2742         }
2743
2744         while (animbuffer < animbufferend)
2745         {
2746                 pchunk = (pskchunk_t *)animbuffer;
2747                 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2748                 version = LittleLong(pchunk->version);
2749                 recordsize = LittleLong(pchunk->recordsize);
2750                 numrecords = LittleLong(pchunk->numrecords);
2751                 if (developer_extra.integer)
2752                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2753                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2754                         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);
2755                 if (!strcmp(pchunk->id, "ANIMHEAD"))
2756                 {
2757                         // nothing to do
2758                 }
2759                 else if (!strcmp(pchunk->id, "BONENAMES"))
2760                 {
2761                         pskboneinfo_t *p;
2762                         if (recordsize != sizeof(*p))
2763                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2764                         // byteswap in place and keep the pointer
2765                         numanimbones = numrecords;
2766                         //animbones = (pskboneinfo_t *)animbuffer;
2767                         // NOTE: supposedly psa does not need to match the psk model, the
2768                         // bones missing from the psa would simply use their base
2769                         // positions from the psk, but this is hard for me to implement
2770                         // and people can easily make animations that match.
2771                         if (numanimbones != numbones)
2772                                 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2773                         for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2774                         {
2775                                 p->numchildren = LittleLong(p->numchildren);
2776                                 p->parent = LittleLong(p->parent);
2777                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2778                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2779                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2780                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2781                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2782                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2783                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2784                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2785                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2786                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2787                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2788 #ifdef PSKQUATNEGATIONS
2789                                 if (index)
2790                                 {
2791                                         p->basepose.quat[0] *= -1;
2792                                         p->basepose.quat[1] *= -1;
2793                                         p->basepose.quat[2] *= -1;
2794                                 }
2795                                 else
2796                                 {
2797                                         p->basepose.quat[0] *=  1;
2798                                         p->basepose.quat[1] *= -1;
2799                                         p->basepose.quat[2] *=  1;
2800                                 }
2801 #endif
2802                                 if (p->parent < 0 || p->parent >= numanimbones)
2803                                 {
2804                                         Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2805                                         p->parent = 0;
2806                                 }
2807                                 // check that bones are the same as in the base
2808                                 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2809                                         Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2810                         }
2811                         animbuffer = p;
2812                 }
2813                 else if (!strcmp(pchunk->id, "ANIMINFO"))
2814                 {
2815                         pskaniminfo_t *p;
2816                         if (recordsize != sizeof(*p))
2817                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2818                         // byteswap in place and keep the pointer
2819                         numanims = numrecords;
2820                         anims = (pskaniminfo_t *)animbuffer;
2821                         for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2822                         {
2823                                 p->numbones = LittleLong(p->numbones);
2824                                 p->playtime = LittleFloat(p->playtime);
2825                                 p->fps = LittleFloat(p->fps);
2826                                 p->firstframe = LittleLong(p->firstframe);
2827                                 p->numframes = LittleLong(p->numframes);
2828                                 if (p->numbones != numbones)
2829                                         Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2830                         }
2831                         animbuffer = p;
2832                 }
2833                 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2834                 {
2835                         pskanimkeys_t *p;
2836                         if (recordsize != sizeof(*p))
2837                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2838                         numanimkeys = numrecords;
2839                         animkeys = (pskanimkeys_t *)animbuffer;
2840                         for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2841                         {
2842                                 p->origin[0] = LittleFloat(p->origin[0]);
2843                                 p->origin[1] = LittleFloat(p->origin[1]);
2844                                 p->origin[2] = LittleFloat(p->origin[2]);
2845                                 p->quat[0] = LittleFloat(p->quat[0]);
2846                                 p->quat[1] = LittleFloat(p->quat[1]);
2847                                 p->quat[2] = LittleFloat(p->quat[2]);
2848                                 p->quat[3] = LittleFloat(p->quat[3]);
2849                                 p->frametime = LittleFloat(p->frametime);
2850 #ifdef PSKQUATNEGATIONS
2851                                 if (index % numbones)
2852                                 {
2853                                         p->quat[0] *= -1;
2854                                         p->quat[1] *= -1;
2855                                         p->quat[2] *= -1;
2856                                 }
2857                                 else
2858                                 {
2859                                         p->quat[0] *=  1;
2860                                         p->quat[1] *= -1;
2861                                         p->quat[2] *=  1;
2862                                 }
2863 #endif
2864                         }
2865                         animbuffer = p;
2866                         // TODO: allocate bonepose stuff
2867                 }
2868                 else
2869                         Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2870         }
2871
2872         if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2873                 Host_Error("%s: missing required chunks", loadmodel->name);
2874
2875         if (numanims)
2876         {
2877                 loadmodel->numframes = 0;
2878                 for (index = 0;index < numanims;index++)
2879                         loadmodel->numframes += anims[index].numframes;
2880                 if (numanimkeys != numbones * loadmodel->numframes)
2881                         Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2882         }
2883         else
2884                 loadmodel->numframes = loadmodel->num_poses = 1;
2885
2886         meshvertices = numvtxw;
2887         meshtriangles = numfaces;
2888
2889         // load external .skin files if present
2890         skinfiles = Mod_LoadSkinFiles();
2891         if (loadmodel->numskins < 1)
2892                 loadmodel->numskins = 1;
2893         loadmodel->num_bones = numbones;
2894         loadmodel->num_poses = loadmodel->numframes;
2895         loadmodel->submodelsurfaces_start = 0;
2896         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = nummatts;
2897         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2898         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2899         loadmodel->surfmesh.num_vertices = meshvertices;
2900         loadmodel->surfmesh.num_triangles = meshtriangles;
2901         // do most allocations as one merged chunk
2902         size = loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned short) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t) + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0);
2903         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2904         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2905         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2906         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2907         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2908         loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2909         loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2910         loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2911         loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2912         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2913         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2914         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2915         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2916         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2917         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2918         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2919         loadmodel->surfmesh.num_blends = 0;
2920         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2921         if (loadmodel->surfmesh.num_vertices <= 65536)
2922         {
2923                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2924         }
2925         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2926         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2927
2928         for (i = 0;i < loadmodel->numskins;i++)
2929         {
2930                 loadmodel->skinscenes[i].firstframe = i;
2931                 loadmodel->skinscenes[i].framecount = 1;
2932                 loadmodel->skinscenes[i].loop = true;
2933                 loadmodel->skinscenes[i].framerate = 10;
2934         }
2935
2936         // create surfaces
2937         for (index = 0, i = 0;index < nummatts;index++)
2938         {
2939                 // since psk models do not have named sections, reuse their shader name as the section name
2940                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2941                 loadmodel->modelsurfaces_sorted[index] = index;
2942                 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2943                 loadmodel->data_surfaces[index].num_firstvertex = 0;
2944                 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2945         }
2946
2947         // copy over the vertex locations and texcoords
2948         for (index = 0;index < numvtxw;index++)
2949         {
2950                 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2951                 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2952                 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2953                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2954                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
2955         }
2956
2957         // loading the faces is complicated because we need to sort them into surfaces by mattindex
2958         for (index = 0;index < numfaces;index++)
2959                 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
2960         for (index = 0, i = 0;index < nummatts;index++)
2961         {
2962                 loadmodel->data_surfaces[index].num_firsttriangle = i;
2963                 i += loadmodel->data_surfaces[index].num_triangles;
2964                 loadmodel->data_surfaces[index].num_triangles = 0;
2965         }
2966         for (index = 0;index < numfaces;index++)
2967         {
2968                 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
2969                 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
2970                 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
2971                 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
2972         }
2973
2974         // copy over the bones
2975         for (index = 0;index < numbones;index++)
2976         {
2977                 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
2978                 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
2979                 if (loadmodel->data_bones[index].parent >= index)
2980                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
2981         }
2982
2983         // convert the basepose data
2984         if (loadmodel->num_bones)
2985         {
2986                 int boneindex;
2987                 matrix4x4_t *basebonepose;
2988                 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
2989                 matrix4x4_t bonematrix;
2990                 matrix4x4_t tempbonematrix;
2991                 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
2992                 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
2993                 {
2994                         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]);
2995                         if (loadmodel->data_bones[boneindex].parent >= 0)
2996                         {
2997                                 tempbonematrix = bonematrix;
2998                                 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
2999                         }
3000                         basebonepose[boneindex] = bonematrix;
3001                         Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3002                         Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3003                 }
3004                 Mem_Free(basebonepose);
3005         }
3006
3007         // sort the psk point weights into the vertex weight tables
3008         // (which only accept up to 4 bones per vertex)
3009         for (index = 0;index < numvtxw;index++)
3010         {
3011                 int weightindex[4] = { 0, 0, 0, 0 };
3012                 float weightinfluence[4] = { 0, 0, 0, 0 };
3013                 int l;
3014                 for (j = 0;j < numrawweights;j++)
3015                 {
3016                         if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3017                         {
3018                                 int boneindex = rawweights[j].boneindex;
3019                                 float influence = rawweights[j].weight;
3020                                 for (l = 0;l < 4;l++)
3021                                 {
3022                                         if (weightinfluence[l] < influence)
3023                                         {
3024                                                 // move lower influence weights out of the way first
3025                                                 int l2;
3026                                                 for (l2 = 3;l2 > l;l2--)
3027                                                 {
3028                                                         weightinfluence[l2] = weightinfluence[l2-1];
3029                                                         weightindex[l2] = weightindex[l2-1];
3030                                                 }
3031                                                 // store the new weight
3032                                                 weightinfluence[l] = influence;
3033                                                 weightindex[l] = boneindex;
3034                                                 break;
3035                                         }
3036                                 }
3037                         }
3038                 }
3039                 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3040                 loadmodel->surfmesh.data_skeletalindex4ub[index*4  ] = weightindex[0];
3041                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3042                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3043                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3044                 loadmodel->surfmesh.data_skeletalweight4ub[index*4  ] = (unsigned char)(weightinfluence[0]*255.0f);
3045                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3046                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3047                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3048         }
3049         if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3050                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3051
3052         // set up the animscenes based on the anims
3053         if (numanims)
3054         {
3055                 for (index = 0, i = 0;index < numanims;index++)
3056                 {
3057                         for (j = 0;j < anims[index].numframes;j++, i++)
3058                         {
3059                                 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3060                                 loadmodel->animscenes[i].firstframe = i;
3061                                 loadmodel->animscenes[i].framecount = 1;
3062                                 loadmodel->animscenes[i].loop = true;
3063                                 loadmodel->animscenes[i].framerate = anims[index].fps;
3064                         }
3065                 }
3066                 // calculate the scaling value for bone origins so they can be compressed to short
3067                 biggestorigin = 0;
3068                 for (index = 0;index < numanimkeys;index++)
3069                 {
3070                         pskanimkeys_t *k = animkeys + index;
3071                         biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3072                         biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3073                         biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3074                 }
3075                 loadmodel->num_posescale = biggestorigin / 32767.0f;
3076                 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3077         
3078                 // load the poses from the animkeys
3079                 for (index = 0;index < numanimkeys;index++)
3080                 {
3081                         pskanimkeys_t *k = animkeys + index;
3082                         float quat[4];
3083                         Vector4Copy(k->quat, quat);
3084                         if (quat[3] > 0)
3085                                 Vector4Negate(quat, quat);
3086                         Vector4Normalize2(quat, quat);
3087                         // compress poses to the short[7] format for longterm storage
3088                         loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3089                         loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3090                         loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3091                         loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3092                         loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3093                         loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3094                         loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3095                 }
3096         }
3097         else
3098         {
3099                 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3100                 loadmodel->animscenes[0].firstframe = 0;
3101                 loadmodel->animscenes[0].framecount = 1;
3102                 loadmodel->animscenes[0].loop = true;
3103                 loadmodel->animscenes[0].framerate = 10;
3104
3105                 // calculate the scaling value for bone origins so they can be compressed to short
3106                 biggestorigin = 0;
3107                 for (index = 0;index < numbones;index++)
3108                 {
3109                         pskboneinfo_t *p = bones + index;
3110                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3111                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3112                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3113                 }
3114                 loadmodel->num_posescale = biggestorigin / 32767.0f;
3115                 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3116         
3117                 // load the basepose as a frame
3118                 for (index = 0;index < numbones;index++)
3119                 {
3120                         pskboneinfo_t *p = bones + index;
3121                         float quat[4];
3122                         Vector4Copy(p->basepose.quat, quat);
3123                         if (quat[3] > 0)
3124                                 Vector4Negate(quat, quat);
3125                         Vector4Normalize2(quat, quat);
3126                         // compress poses to the short[7] format for longterm storage
3127                         loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3128                         loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3129                         loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3130                         loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3131                         loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3132                         loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3133                         loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3134                 }
3135         }
3136
3137         Mod_FreeSkinFiles(skinfiles);
3138         if (animfilebuffer)
3139                 Mem_Free(animfilebuffer);
3140         Mod_MakeSortedSurfaces(loadmodel);
3141
3142         // compute all the mesh information that was not loaded from the file
3143         // TODO: honor smoothing groups somehow?
3144         if (loadmodel->surfmesh.data_element3s)
3145                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3146                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3147         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3148         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);
3149         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);
3150         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3151         if(mod_alias_force_animated.string[0])
3152                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3153
3154         // Always make a BIH for the first frame, we can use it where possible.
3155         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3156         if (!loadmodel->surfmesh.isanimated)
3157         {
3158                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3159                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3160                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3161                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3162                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3163         }
3164 }
3165
3166 void Mod_INTERQUAKEMODEL_Load(model_t *mod, void *buffer, void *bufferend)
3167 {
3168         unsigned char *data;
3169         const char *text;
3170         const unsigned char *pbase, *pend;
3171         iqmheader_t header;
3172         skinfile_t *skinfiles;
3173         int i, j, k, meshvertices, meshtriangles;
3174         float biggestorigin;
3175         const unsigned int *inelements;
3176         int *outelements;
3177         float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3178         // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3179         const float *vnormal = NULL;
3180         const float *vposition = NULL;
3181         const float *vtangent = NULL;
3182         const float *vtexcoord = NULL;
3183         const float *vcolor4f = NULL;
3184         const unsigned char *vblendindexes = NULL;
3185         const unsigned char *vblendweights = NULL;
3186         const unsigned char *vcolor4ub = NULL;
3187         const unsigned short *framedata = NULL;
3188         // temporary memory allocations (because the data in the file may be misaligned)
3189         iqmanim_t *anims = NULL;
3190         iqmbounds_t *bounds = NULL;
3191         iqmjoint1_t *joint1 = NULL;
3192         iqmjoint_t *joint = NULL;
3193         iqmmesh_t *meshes = NULL;
3194         iqmpose1_t *pose1 = NULL;
3195         iqmpose_t *pose = NULL;
3196         iqmvertexarray_t *vas = NULL;
3197
3198         pbase = (unsigned char *)buffer;
3199         pend = (unsigned char *)bufferend;
3200
3201         if (pbase + sizeof(iqmheader_t) > pend)
3202                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3203
3204         // copy struct (otherwise it may be misaligned)
3205         // LadyHavoc: okay it's definitely not misaligned here, but for consistency...
3206         memcpy(&header, pbase, sizeof(iqmheader_t));
3207
3208         if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3209                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3210         if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3211                 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3212
3213         loadmodel->modeldatatypestring = "IQM";
3214
3215         loadmodel->type = mod_alias;
3216         loadmodel->synctype = ST_RAND;
3217
3218         // byteswap header
3219         header.version = LittleLong(header.version);
3220         header.filesize = LittleLong(header.filesize);
3221         header.flags = LittleLong(header.flags);
3222         header.num_text = LittleLong(header.num_text);
3223         header.ofs_text = LittleLong(header.ofs_text);
3224         header.num_meshes = LittleLong(header.num_meshes);
3225         header.ofs_meshes = LittleLong(header.ofs_meshes);
3226         header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3227         header.num_vertexes = LittleLong(header.num_vertexes);
3228         header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3229         header.num_triangles = LittleLong(header.num_triangles);
3230         header.ofs_triangles = LittleLong(header.ofs_triangles);
3231         header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3232         header.num_joints = LittleLong(header.num_joints);
3233         header.ofs_joints = LittleLong(header.ofs_joints);
3234         header.num_poses = LittleLong(header.num_poses);
3235         header.ofs_poses = LittleLong(header.ofs_poses);
3236         header.num_anims = LittleLong(header.num_anims);
3237         header.ofs_anims = LittleLong(header.ofs_anims);
3238         header.num_frames = LittleLong(header.num_frames);
3239         header.num_framechannels = LittleLong(header.num_framechannels);
3240         header.ofs_frames = LittleLong(header.ofs_frames);
3241         header.ofs_bounds = LittleLong(header.ofs_bounds);
3242         header.num_comment = LittleLong(header.num_comment);
3243         header.ofs_comment = LittleLong(header.ofs_comment);
3244         header.num_extensions = LittleLong(header.num_extensions);
3245         header.ofs_extensions = LittleLong(header.ofs_extensions);
3246
3247         if (header.version == 1)
3248         {
3249                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3250                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3251                 {
3252                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3253                         return;
3254                 }
3255         }
3256         else
3257         {
3258                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3259                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3260                 {
3261                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3262                         return;
3263                 }
3264         }
3265         if (pbase + header.ofs_text + header.num_text > pend ||
3266                 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3267                 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3268                 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3269                 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3270                 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3271                 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3272                 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3273                 pbase + header.ofs_comment + header.num_comment > pend)
3274         {
3275                 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3276                 return;
3277         }
3278
3279         // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3280         if (header.num_vertexarrays)
3281                 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3282         if (header.num_anims)
3283                 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3284         if (header.ofs_bounds)
3285                 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3286         if (header.num_meshes)
3287                 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3288
3289         for (i = 0;i < (int)header.num_vertexarrays;i++)
3290         {
3291                 iqmvertexarray_t va;
3292                 size_t vsize;
3293                 va.type = LittleLong(vas[i].type);
3294                 va.flags = LittleLong(vas[i].flags);
3295                 va.format = LittleLong(vas[i].format);
3296                 va.size = LittleLong(vas[i].size);
3297                 va.offset = LittleLong(vas[i].offset);
3298                 vsize = header.num_vertexes*va.size;
3299                 switch (va.format)
3300                 { 
3301                 case IQM_FLOAT: vsize *= sizeof(float); break;
3302                 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3303                 default: continue;
3304                 }
3305                 if (pbase + va.offset + vsize > pend)
3306                         continue;
3307                 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3308                 switch (va.type)
3309                 {
3310                 case IQM_POSITION:
3311                         if (va.format == IQM_FLOAT && va.size == 3)
3312                                 vposition = (const float *)(pbase + va.offset);
3313                         break;
3314                 case IQM_TEXCOORD:
3315                         if (va.format == IQM_FLOAT && va.size == 2)
3316                                 vtexcoord = (const float *)(pbase + va.offset);
3317                         break;
3318                 case IQM_NORMAL:
3319                         if (va.format == IQM_FLOAT && va.size == 3)
3320                                 vnormal = (const float *)(pbase + va.offset);
3321                         break;
3322                 case IQM_TANGENT:
3323                         if (va.format == IQM_FLOAT && va.size == 4)
3324                                 vtangent = (const float *)(pbase + va.offset);
3325                         break;
3326                 case IQM_BLENDINDEXES:
3327                         if (va.format == IQM_UBYTE && va.size == 4)
3328                                 vblendindexes = (const unsigned char *)(pbase + va.offset);
3329                         break;
3330                 case IQM_BLENDWEIGHTS:
3331                         if (va.format == IQM_UBYTE && va.size == 4)
3332                                 vblendweights = (const unsigned char *)(pbase + va.offset);
3333                         break;
3334                 case IQM_COLOR:
3335                         if (va.format == IQM_FLOAT && va.size == 4)
3336                                 vcolor4f = (const float *)(pbase + va.offset);
3337                         if (va.format == IQM_UBYTE && va.size == 4)
3338                                 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3339                         break;
3340                 }
3341         }
3342         if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3343         {
3344                 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3345                 return;
3346         }
3347
3348         text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3349
3350         loadmodel->Draw = R_Mod_Draw;
3351         loadmodel->DrawDepth = R_Mod_DrawDepth;
3352         loadmodel->DrawDebug = R_Mod_DrawDebug;
3353         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
3354         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
3355         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
3356         loadmodel->DrawLight = R_Mod_DrawLight;
3357         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3358         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3359         loadmodel->PointSuperContents = NULL;
3360         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3361
3362         // load external .skin files if present
3363         skinfiles = Mod_LoadSkinFiles();
3364         if (loadmodel->numskins < 1)
3365                 loadmodel->numskins = 1;
3366
3367         loadmodel->numframes = max(header.num_anims, 1);
3368         loadmodel->num_bones = header.num_joints;
3369         loadmodel->num_poses = max(header.num_frames, 1);
3370         loadmodel->submodelsurfaces_start = 0;
3371         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = header.num_meshes;
3372         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3373         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3374
3375         meshvertices = header.num_vertexes;
3376         meshtriangles = header.num_triangles;
3377
3378         // do most allocations as one merged chunk
3379         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * (sizeof(float[14]) + (vcolor4f || vcolor4ub ? sizeof(float[4]) : 0)) + (vblendindexes && vblendweights ? meshvertices * (sizeof(unsigned short) + sizeof(unsigned char[2][4])) : 0) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t));
3380         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3381         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3382         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3383         loadmodel->surfmesh.num_vertices = meshvertices;
3384         loadmodel->surfmesh.num_triangles = meshtriangles;
3385         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3386         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3387         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3388         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3389         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3390         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3391         if (vcolor4f || vcolor4ub)
3392         {
3393                 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3394         }
3395         if (vblendindexes && vblendweights)
3396         {
3397                 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3398                 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3399         }
3400         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3401         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3402         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3403         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3404         if (vblendindexes && vblendweights)
3405         {
3406                 loadmodel->surfmesh.num_blends = 0;
3407                 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3408         }
3409         if (meshvertices <= 65536)
3410         {
3411                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3412         }
3413         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3414         if (vblendindexes && vblendweights)
3415                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3416
3417         for (i = 0;i < loadmodel->numskins;i++)
3418         {
3419                 loadmodel->skinscenes[i].firstframe = i;
3420                 loadmodel->skinscenes[i].framecount = 1;
3421                 loadmodel->skinscenes[i].loop = true;
3422                 loadmodel->skinscenes[i].framerate = 10;
3423         }
3424
3425         // load the bone info
3426         if (header.version == 1)
3427         {
3428                 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3429                 if (loadmodel->num_bones)
3430                         joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3431                 for (i = 0;i < loadmodel->num_bones;i++)
3432                 {
3433                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3434                         joint1[i].name = LittleLong(injoint1[i].name);
3435                         joint1[i].parent = LittleLong(injoint1[i].parent);
3436                         for (j = 0;j < 3;j++)
3437                         {
3438                                 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3439                                 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3440                                 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3441                         }
3442                         strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3443                         loadmodel->data_bones[i].parent = joint1[i].parent;
3444                         if (loadmodel->data_bones[i].parent >= i)
3445                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3446                         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]);
3447                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3448                         if (loadmodel->data_bones[i].parent >= 0)
3449                         {
3450                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3451                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3452                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3453                         }
3454                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3455                 }
3456         }
3457         else
3458         {
3459                 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3460                 if (header.num_joints)
3461                         joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3462                 for (i = 0;i < loadmodel->num_bones;i++)
3463                 {
3464                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3465                         joint[i].name = LittleLong(injoint[i].name);
3466                         joint[i].parent = LittleLong(injoint[i].parent);
3467                         for (j = 0;j < 3;j++)
3468                         {
3469                                 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3470                                 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3471                                 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3472                         }
3473                         joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3474                         strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3475                         loadmodel->data_bones[i].parent = joint[i].parent;
3476                         if (loadmodel->data_bones[i].parent >= i)
3477                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3478                         if (joint[i].rotation[3] > 0)
3479                                 Vector4Negate(joint[i].rotation, joint[i].rotation);
3480                         Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3481                         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]);
3482                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3483                         if (loadmodel->data_bones[i].parent >= 0)
3484                         {
3485                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3486                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3487                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3488                         }       
3489                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3490                 }
3491         }
3492
3493         // set up the animscenes based on the anims
3494         for (i = 0;i < (int)header.num_anims;i++)
3495         {
3496                 iqmanim_t anim;
3497                 anim.name = LittleLong(anims[i].name);
3498                 anim.first_frame = LittleLong(anims[i].first_frame);
3499                 anim.num_frames = LittleLong(anims[i].num_frames);
3500                 anim.framerate = LittleFloat(anims[i].framerate);
3501                 anim.flags = LittleLong(anims[i].flags);
3502                 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3503                 loadmodel->animscenes[i].firstframe = anim.first_frame;
3504                 loadmodel->animscenes[i].framecount = anim.num_frames;
3505                 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3506                 loadmodel->animscenes[i].framerate = anim.framerate;
3507         }
3508         if (header.num_anims <= 0)
3509         {
3510                 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3511                 loadmodel->animscenes[0].firstframe = 0;
3512                 loadmodel->animscenes[0].framecount = 1;
3513                 loadmodel->animscenes[0].loop = true;
3514                 loadmodel->animscenes[0].framerate = 10;
3515         }
3516
3517         loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3518         if(mod_alias_force_animated.string[0])
3519                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3520
3521         biggestorigin = 0;
3522         if (header.version == 1)
3523         {
3524                 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3525                 if (header.num_poses)
3526                         pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3527                 for (i = 0;i < (int)header.num_poses;i++)
3528                 {
3529                         float f;
3530                         pose1[i].parent = LittleLong(inpose1[i].parent);
3531                         pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3532                         for (j = 0;j < 9;j++)
3533                         {
3534                                 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3535                                 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3536                         }
3537                         f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3538                         f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3539                         f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3540                         f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3541                         f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3542                         f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3543                 }
3544                 if (header.num_frames <= 0)
3545                 {
3546                         for (i = 0;i < loadmodel->num_bones;i++)
3547                         {
3548                                 float f;
3549                                 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3550                                 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3551                                 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3552                         }
3553                 }
3554         }
3555         else
3556         {
3557                 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3558                 if (header.num_poses)
3559                         pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3560                 for (i = 0;i < (int)header.num_poses;i++)
3561                 {
3562                         float f;
3563                         pose[i].parent = LittleLong(inpose[i].parent);
3564                         pose[i].channelmask = LittleLong(inpose[i].channelmask);
3565                         for (j = 0;j < 10;j++)
3566                         {
3567                                 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3568                                 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3569                         }
3570                         f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3571                         f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3572                         f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3573                         f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3574                         f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3575                         f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3576                 }
3577                 if (header.num_frames <= 0)
3578                 {
3579                         for (i = 0;i < loadmodel->num_bones;i++)
3580                         {
3581                                 float f;
3582                                 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3583                                 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3584                                 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3585                         }
3586                 }
3587         }
3588         loadmodel->num_posescale = biggestorigin / 32767.0f;
3589         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3590
3591         // load the pose data
3592         // this unaligned memory access is safe (LittleShort reads as bytes)
3593         framedata = (const unsigned short *)(pbase + header.ofs_frames);
3594         if (header.version == 1)
3595         {
3596                 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3597                 {
3598                         for (j = 0;j < (int)header.num_poses;j++, k++)
3599                         {
3600                                 float qx, qy, qz, qw;
3601                                 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));
3602                                 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));
3603                                 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));
3604                                 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3605                                 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3606                                 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3607                                 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3608                                 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3609                                 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3610                                 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3611                                 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3612                                 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3613                                 // skip scale data for now
3614                                 if(pose1[j].channelmask&64) framedata++;
3615                                 if(pose1[j].channelmask&128) framedata++;
3616                                 if(pose1[j].channelmask&256) framedata++;
3617                         }
3618                 }
3619                 if (header.num_frames <= 0)
3620                 {
3621                         for (i = 0;i < loadmodel->num_bones;i++)
3622                         {
3623                                 float qx, qy, qz, qw;
3624                                 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3625                                 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3626                                 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3627                                 qx = joint1[i].rotation[0];
3628                                 qy = joint1[i].rotation[1];
3629                                 qz = joint1[i].rotation[2];
3630                                 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3631                                 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3632                                 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3633                                 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3634                                 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3635                                 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3636                         }
3637                 }
3638         }
3639         else
3640         {
3641                 for (i = 0, k = 0;i < (int)header.num_frames;i++)       
3642                 {
3643                         for (j = 0;j < (int)header.num_poses;j++, k++)
3644                         {
3645                                 float rot[4];
3646                                 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));
3647                                 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));
3648                                 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));
3649                                 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3650                                 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3651                                 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3652                                 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3653                                 if (rot[3] > 0)
3654                                         Vector4Negate(rot, rot);
3655                                 Vector4Normalize2(rot, rot);
3656                                 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3657                                 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3658                                 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3659                                 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3660                                 // skip scale data for now
3661                                 if(pose[j].channelmask&128) framedata++;
3662                                 if(pose[j].channelmask&256) framedata++;
3663                                 if(pose[j].channelmask&512) framedata++;
3664                         }
3665                 }
3666                 if (header.num_frames <= 0)
3667                 {
3668                         for (i = 0;i < loadmodel->num_bones;i++)
3669                         {
3670                                 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3671                                 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3672                                 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3673                                 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3674                                 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3675                                 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3676                                 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3677                         }
3678                 }
3679         }
3680
3681         // load bounding box data
3682         if (header.ofs_bounds)
3683         {
3684                 float xyradius = 0, radius = 0;
3685                 VectorClear(loadmodel->normalmins);
3686                 VectorClear(loadmodel->normalmaxs);
3687                 for (i = 0; i < (int)header.num_frames;i++)
3688                 {
3689                         iqmbounds_t bound;
3690                         bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3691                         bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3692                         bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3693                         bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);                 
3694                         bound.maxs[1] = LittleFloat(bounds[i].maxs[1]); 
3695                         bound.maxs[2] = LittleFloat(bounds[i].maxs[2]); 
3696                         bound.xyradius = LittleFloat(bounds[i].xyradius);
3697                         bound.radius = LittleFloat(bounds[i].radius);
3698                         if (!i)
3699                         {
3700                                 VectorCopy(bound.mins, loadmodel->normalmins);
3701                                 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3702                         }
3703                         else
3704                         {
3705                                 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3706                                 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3707                                 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3708                                 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3709                                 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3710                                 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3711                         }
3712                         if (bound.xyradius > xyradius)
3713                                 xyradius = bound.xyradius;
3714                         if (bound.radius > radius)
3715                                 radius = bound.radius;
3716                 }
3717                 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3718                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3719                 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3720                 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3721                 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3722                 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3723                 loadmodel->radius = radius;
3724                 loadmodel->radius2 = radius * radius;
3725         }
3726
3727         // load triangle data
3728         // this unaligned memory access is safe (LittleLong reads as bytes)
3729         inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3730         outelements = loadmodel->surfmesh.data_element3i;
3731         for (i = 0;i < (int)header.num_triangles;i++)
3732         {
3733                 outelements[0] = LittleLong(inelements[0]);
3734                 outelements[1] = LittleLong(inelements[1]);
3735                 outelements[2] = LittleLong(inelements[2]);
3736                 outelements += 3;
3737                 inelements += 3;
3738         }
3739         if (loadmodel->surfmesh.data_element3s)
3740                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3741                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3742         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3743
3744         // load vertex data
3745         // this unaligned memory access is safe (LittleFloat reads as bytes)
3746         outvertex = loadmodel->surfmesh.data_vertex3f;
3747         for (i = 0;i < (int)header.num_vertexes;i++)
3748         {
3749                 outvertex[0] = LittleFloat(vposition[0]);
3750                 outvertex[1] = LittleFloat(vposition[1]);
3751                 outvertex[2] = LittleFloat(vposition[2]);
3752                 vposition += 3;
3753                 outvertex += 3;
3754         }
3755
3756         outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3757         // this unaligned memory access is safe (LittleFloat reads as bytes)
3758         for (i = 0;i < (int)header.num_vertexes;i++)
3759         {
3760                 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3761                 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3762                 vtexcoord += 2;
3763                 outtexcoord += 2;
3764         }
3765
3766         // this unaligned memory access is safe (LittleFloat reads as bytes)
3767         if(vnormal)
3768         {
3769                 outnormal = loadmodel->surfmesh.data_normal3f;
3770                 for (i = 0;i < (int)header.num_vertexes;i++)
3771                 {
3772                         outnormal[0] = LittleFloat(vnormal[0]);
3773                         outnormal[1] = LittleFloat(vnormal[1]);
3774                         outnormal[2] = LittleFloat(vnormal[2]);
3775                         vnormal += 3;
3776                         outnormal += 3;
3777                 }
3778         }
3779
3780         // this unaligned memory access is safe (LittleFloat reads as bytes)
3781         if(vnormal && vtangent)
3782         {
3783                 outnormal = loadmodel->surfmesh.data_normal3f;
3784                 outsvector = loadmodel->surfmesh.data_svector3f;
3785                 outtvector = loadmodel->surfmesh.data_tvector3f;
3786                 for (i = 0;i < (int)header.num_vertexes;i++)
3787                 {
3788                         outsvector[0] = LittleFloat(vtangent[0]);
3789                         outsvector[1] = LittleFloat(vtangent[1]);
3790                         outsvector[2] = LittleFloat(vtangent[2]);
3791                         if(LittleFloat(vtangent[3]) < 0)
3792                                 CrossProduct(outsvector, outnormal, outtvector);
3793                         else
3794                                 CrossProduct(outnormal, outsvector, outtvector);
3795                         vtangent += 4;
3796                         outnormal += 3;
3797                         outsvector += 3;
3798                         outtvector += 3;
3799                 }
3800         }
3801
3802         // this unaligned memory access is safe (all bytes)
3803         if (vblendindexes && vblendweights)
3804         {
3805                 for (i = 0; i < (int)header.num_vertexes;i++)
3806                 {
3807                         blendweights_t weights;
3808                         memcpy(weights.index, vblendindexes + i*4, 4);
3809                         memcpy(weights.influence, vblendweights + i*4, 4);
3810                         loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3811                         loadmodel->surfmesh.data_skeletalindex4ub[i*4  ] = weights.index[0];
3812                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3813                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3814                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3815                         loadmodel->surfmesh.data_skeletalweight4ub[i*4  ] = weights.influence[0];
3816                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3817                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3818                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3819                 }
3820         }
3821
3822         if (vcolor4f)
3823         {
3824                 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3825                 // this unaligned memory access is safe (LittleFloat reads as bytes)
3826                 for (i = 0;i < (int)header.num_vertexes;i++)
3827                 {
3828                         outcolor[0] = LittleFloat(vcolor4f[0]);
3829                         outcolor[1] = LittleFloat(vcolor4f[1]);
3830                         outcolor[2] = LittleFloat(vcolor4f[2]);
3831                         outcolor[3] = LittleFloat(vcolor4f[3]);
3832                         vcolor4f += 4;
3833                         outcolor += 4;
3834                 }
3835         }
3836         else if (vcolor4ub)
3837         {
3838                 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3839                 // this unaligned memory access is safe (all bytes)
3840                 for (i = 0;i < (int)header.num_vertexes;i++)
3841                 {
3842                         outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3843                         outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3844                         outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3845                         outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3846                         vcolor4ub += 4;
3847                         outcolor += 4;
3848                 }
3849         }
3850
3851         // load meshes
3852         for (i = 0;i < (int)header.num_meshes;i++)
3853         {
3854                 iqmmesh_t mesh;
3855                 msurface_t *surface;
3856
3857                 mesh.name = LittleLong(meshes[i].name);
3858                 mesh.material = LittleLong(meshes[i].material);
3859                 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3860                 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3861                 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3862                 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3863
3864                 loadmodel->modelsurfaces_sorted[i] = i;
3865                 surface = loadmodel->data_surfaces + i;
3866                 surface->texture = loadmodel->data_textures + i;
3867                 surface->num_firsttriangle = mesh.first_triangle;
3868                 surface->num_triangles = mesh.num_triangles;
3869                 surface->num_firstvertex = mesh.first_vertex;
3870                 surface->num_vertices = mesh.num_vertexes;
3871
3872                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3873         }
3874
3875         Mod_FreeSkinFiles(skinfiles);
3876         Mod_MakeSortedSurfaces(loadmodel);
3877
3878         // compute all the mesh information that was not loaded from the file
3879         if (!vnormal)
3880                 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);
3881         if (!vnormal || !vtangent)
3882                 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);
3883         if (!header.ofs_bounds)
3884                 Mod_Alias_CalculateBoundingBox();
3885
3886         // Always make a BIH for the first frame, we can use it where possible.
3887         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3888         if (!loadmodel->surfmesh.isanimated)
3889         {
3890                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3891                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3892                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3893                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3894                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3895         }
3896
3897         if (joint        ) Mem_Free(joint        );joint         = NULL;
3898         if (joint1       ) Mem_Free(joint1       );joint1        = NULL;
3899         if (pose         ) Mem_Free(pose         );pose          = NULL;
3900         if (pose1        ) Mem_Free(pose1        );pose1         = NULL;
3901 }