]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - model_alias.c
Disable PRVM_64 until it can be developed further. Improves perf. in some cases
[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 qboolean r_skeletal_use_sse_defined = false;
31 cvar_t r_skeletal_use_sse = {CVAR_CLIENT, "r_skeletal_use_sse", "1", "use SSE for skeletal model animation"};
32 #endif
33 cvar_t r_skeletal_debugbone = {CVAR_CLIENT, "r_skeletal_debugbone", "-1", "development cvar for testing skeletal model code"};
34 cvar_t r_skeletal_debugbonecomponent = {CVAR_CLIENT, "r_skeletal_debugbonecomponent", "3", "development cvar for testing skeletal model code"};
35 cvar_t r_skeletal_debugbonevalue = {CVAR_CLIENT, "r_skeletal_debugbonevalue", "100", "development cvar for testing skeletal model code"};
36 cvar_t r_skeletal_debugtranslatex = {CVAR_CLIENT, "r_skeletal_debugtranslatex", "1", "development cvar for testing skeletal model code"};
37 cvar_t r_skeletal_debugtranslatey = {CVAR_CLIENT, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"};
38 cvar_t r_skeletal_debugtranslatez = {CVAR_CLIENT, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"};
39 cvar_t mod_alias_supporttagscale = {CVAR_CLIENT | CVAR_SERVER, "mod_alias_supporttagscale", "1", "support scaling factors in bone/tag attachment matrices as supported by MD3"};
40 cvar_t mod_alias_force_animated = {CVAR_CLIENT | CVAR_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 dp_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 dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
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(dp_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(dp_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 dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
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 dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
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 dp_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 dp_model_t *model, unsigned int skin, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
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 dp_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 qboolean Mod_Alias_CalculateBoundingBox(void)
627 {
628         int vnum;
629         qboolean firstvertex = true;
630         float dist, yawradius, radius;
631         float *v;
632         qboolean 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(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
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(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
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(dp_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->DrawSky = NULL;
1008         loadmodel->DrawAddWaterPlanes = NULL;
1009         loadmodel->Draw = R_Q1BSP_Draw;
1010         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1011         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1012         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1013         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1014         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1015         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1016         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1017         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1018         // FIXME add TraceBrush!
1019         loadmodel->PointSuperContents = NULL;
1020         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1021
1022         loadmodel->num_surfaces = 1;
1023         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1024         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1025         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1026         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1027         loadmodel->sortedmodelsurfaces[0] = 0;
1028
1029         loadmodel->numskins = LittleLong(pinmodel->numskins);
1030         BOUNDI(loadmodel->numskins,0,65536);
1031         skinwidth = LittleLong (pinmodel->skinwidth);
1032         BOUNDI(skinwidth,0,65536);
1033         skinheight = LittleLong (pinmodel->skinheight);
1034         BOUNDI(skinheight,0,65536);
1035         numverts = LittleLong(pinmodel->numverts);
1036         BOUNDI(numverts,0,65536);
1037         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1038         BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1039         loadmodel->numframes = LittleLong(pinmodel->numframes);
1040         BOUNDI(loadmodel->numframes,0,65536);
1041         loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1042         BOUNDI((int)loadmodel->synctype,0,2);
1043         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1044         i = LittleLong (pinmodel->flags);
1045         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1046
1047         if (strstr(r_nolerp_list.string, loadmodel->name))
1048                 loadmodel->nolerp = true;
1049
1050         for (i = 0;i < 3;i++)
1051         {
1052                 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1053                 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1054         }
1055
1056         startskins = datapointer;
1057         totalskins = 0;
1058         for (i = 0;i < loadmodel->numskins;i++)
1059         {
1060                 pinskintype = (daliasskintype_t *)datapointer;
1061                 datapointer += sizeof(daliasskintype_t);
1062                 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1063                         groupskins = 1;
1064                 else
1065                 {
1066                         pinskingroup = (daliasskingroup_t *)datapointer;
1067                         datapointer += sizeof(daliasskingroup_t);
1068                         groupskins = LittleLong(pinskingroup->numskins);
1069                         datapointer += sizeof(daliasskininterval_t) * groupskins;
1070                 }
1071
1072                 for (j = 0;j < groupskins;j++)
1073                 {
1074                         datapointer += skinwidth * skinheight;
1075                         totalskins++;
1076                 }
1077         }
1078
1079         pinstverts = (stvert_t *)datapointer;
1080         datapointer += sizeof(stvert_t) * numverts;
1081
1082         pintriangles = (dtriangle_t *)datapointer;
1083         datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1084
1085         startframes = datapointer;
1086         loadmodel->surfmesh.num_morphframes = 0;
1087         for (i = 0;i < loadmodel->numframes;i++)
1088         {
1089                 pinframetype = (daliasframetype_t *)datapointer;
1090                 datapointer += sizeof(daliasframetype_t);
1091                 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1092                         groupframes = 1;
1093                 else
1094                 {
1095                         pinframegroup = (daliasgroup_t *)datapointer;
1096                         datapointer += sizeof(daliasgroup_t);
1097                         groupframes = LittleLong(pinframegroup->numframes);
1098                         datapointer += sizeof(daliasinterval_t) * groupframes;
1099                 }
1100
1101                 for (j = 0;j < groupframes;j++)
1102                 {
1103                         datapointer += sizeof(daliasframe_t);
1104                         datapointer += sizeof(trivertx_t) * numverts;
1105                         loadmodel->surfmesh.num_morphframes++;
1106                 }
1107         }
1108         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1109
1110         // store texture coordinates into temporary array, they will be stored
1111         // after usage is determined (triangle data)
1112         vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1113         vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1114         vertonseam = vertremap + numverts * 2;
1115
1116         scales = 1.0 / skinwidth;
1117         scalet = 1.0 / skinheight;
1118         for (i = 0;i < numverts;i++)
1119         {
1120                 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1121                 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1122                 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1123                 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1124                 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1125         }
1126
1127 // load triangle data
1128         loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1129
1130         // read the triangle elements
1131         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1132                 for (j = 0;j < 3;j++)
1133                         loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1134         // validate (note numverts is used because this is the original data)
1135         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, NULL, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1136         // now butcher the elements according to vertonseam and tri->facesfront
1137         // and then compact the vertex set to remove duplicates
1138         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1139                 if (!LittleLong(pintriangles[i].facesfront)) // backface
1140                         for (j = 0;j < 3;j++)
1141                                 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1142                                         loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1143         // count the usage
1144         // (this uses vertremap to count usage to save some memory)
1145         for (i = 0;i < numverts*2;i++)
1146                 vertremap[i] = 0;
1147         for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1148                 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1149         // build remapping table and compact array
1150         loadmodel->surfmesh.num_vertices = 0;
1151         for (i = 0;i < numverts*2;i++)
1152         {
1153                 if (vertremap[i])
1154                 {
1155                         vertremap[i] = loadmodel->surfmesh.num_vertices;
1156                         vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1157                         vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1158                         loadmodel->surfmesh.num_vertices++;
1159                 }
1160                 else
1161                         vertremap[i] = -1; // not used at all
1162         }
1163         // remap the elements to the new vertex set
1164         for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1165                 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1166         // store the texture coordinates
1167         loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1168         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1169         {
1170                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1171                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1172         }
1173
1174         // generate ushort elements array if possible
1175         if (loadmodel->surfmesh.num_vertices <= 65536)
1176                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1177         if (loadmodel->surfmesh.data_element3s)
1178                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1179                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1180
1181 // load the frames
1182         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1183         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1184         Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1185         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1186         Mod_Alias_MorphMesh_CompileFrames();
1187
1188         Mem_Free(vertst);
1189         Mem_Free(vertremap);
1190
1191         // load the skins
1192         skinfiles = Mod_LoadSkinFiles();
1193         if (skinfiles)
1194         {
1195                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1196                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1197                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1198                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1199                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1200                 Mod_FreeSkinFiles(skinfiles);
1201                 for (i = 0;i < loadmodel->numskins;i++)
1202                 {
1203                         loadmodel->skinscenes[i].firstframe = i;
1204                         loadmodel->skinscenes[i].framecount = 1;
1205                         loadmodel->skinscenes[i].loop = true;
1206                         loadmodel->skinscenes[i].framerate = 10;
1207                 }
1208         }
1209         else
1210         {
1211                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1212                 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1213                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1214                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1215                 totalskins = 0;
1216                 datapointer = startskins;
1217                 for (i = 0;i < loadmodel->numskins;i++)
1218                 {
1219                         pinskintype = (daliasskintype_t *)datapointer;
1220                         datapointer += sizeof(daliasskintype_t);
1221
1222                         if (pinskintype->type == ALIAS_SKIN_SINGLE)
1223                         {
1224                                 groupskins = 1;
1225                                 interval = 0.1f;
1226                         }
1227                         else
1228                         {
1229                                 pinskingroup = (daliasskingroup_t *)datapointer;
1230                                 datapointer += sizeof(daliasskingroup_t);
1231
1232                                 groupskins = LittleLong (pinskingroup->numskins);
1233
1234                                 pinskinintervals = (daliasskininterval_t *)datapointer;
1235                                 datapointer += sizeof(daliasskininterval_t) * groupskins;
1236
1237                                 interval = LittleFloat(pinskinintervals[0].interval);
1238                                 if (interval < 0.01f)
1239                                 {
1240                                         Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1241                                         interval = 0.1f;
1242                                 }
1243                         }
1244
1245                         dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1246                         loadmodel->skinscenes[i].firstframe = totalskins;
1247                         loadmodel->skinscenes[i].framecount = groupskins;
1248                         loadmodel->skinscenes[i].framerate = 1.0f / interval;
1249                         loadmodel->skinscenes[i].loop = true;
1250
1251                         for (j = 0;j < groupskins;j++)
1252                         {
1253                                 if (groupskins > 1)
1254                                         dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1255                                 else
1256                                         dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1257                                 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))
1258                                         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));
1259                                 datapointer += skinwidth * skinheight;
1260                                 totalskins++;
1261                         }
1262                 }
1263                 // check for skins that don't exist in the model, but do exist as external images
1264                 // (this was added because yummyluv kept pestering me about support for it)
1265                 // TODO: support shaders here?
1266                 for (;;)
1267                 {
1268                         dpsnprintf(name, sizeof(name), "%s_%i", loadmodel->name, loadmodel->numskins);
1269                         tempskinframe = R_SkinFrame_LoadExternal(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false, false);
1270                         if (!tempskinframe)
1271                                 break;
1272                         // expand the arrays to make room
1273                         tempskinscenes = loadmodel->skinscenes;
1274                         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1275                         memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1276                         Mem_Free(tempskinscenes);
1277
1278                         tempaliasskins = loadmodel->data_textures;
1279                         loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1280                         memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1281                         Mem_Free(tempaliasskins);
1282
1283                         // store the info about the new skin
1284                         Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, tempskinframe);
1285                         strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1286                         loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1287                         loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1288                         loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1289                         loadmodel->skinscenes[loadmodel->numskins].loop = true;
1290
1291                         //increase skin counts
1292                         loadmodel->num_textures++;
1293                         loadmodel->numskins++;
1294                         totalskins++;
1295
1296                         // fix up the pointers since they are pointing at the old textures array
1297                         // FIXME: this is a hack!
1298                         for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1299                                 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1300                 }
1301         }
1302
1303         surface = loadmodel->data_surfaces;
1304         surface->texture = loadmodel->data_textures;
1305         surface->num_firsttriangle = 0;
1306         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1307         surface->num_firstvertex = 0;
1308         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1309
1310         if(mod_alias_force_animated.string[0])
1311                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1312
1313         // Always make a BIH for the first frame, we can use it where possible.
1314         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1315         if (!loadmodel->surfmesh.isanimated)
1316         {
1317                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1318                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1319                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1320                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1321                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1322         }
1323
1324         // because shaders can do somewhat unexpected things, check for unusual features now
1325         for (i = 0;i < loadmodel->num_textures;i++)
1326         {
1327                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1328                         mod->DrawSky = R_Q1BSP_DrawSky;
1329                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1330                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1331         }
1332 }
1333
1334 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1335 {
1336         int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1337         float iskinwidth, iskinheight;
1338         unsigned char *data;
1339         msurface_t *surface;
1340         md2_t *pinmodel;
1341         unsigned char *base, *datapointer;
1342         md2frame_t *pinframe;
1343         char *inskin;
1344         md2triangle_t *intri;
1345         unsigned short *inst;
1346         struct md2verthash_s
1347         {
1348                 struct md2verthash_s *next;
1349                 unsigned short xyz;
1350                 unsigned short st;
1351         }
1352         *hash, **md2verthash, *md2verthashdata;
1353         skinfile_t *skinfiles;
1354
1355         pinmodel = (md2_t *)buffer;
1356         base = (unsigned char *)buffer;
1357
1358         version = LittleLong (pinmodel->version);
1359         if (version != MD2ALIAS_VERSION)
1360                 Host_Error ("%s has wrong version number (%i should be %i)",
1361                         loadmodel->name, version, MD2ALIAS_VERSION);
1362
1363         loadmodel->modeldatatypestring = "MD2";
1364
1365         loadmodel->type = mod_alias;
1366         loadmodel->DrawSky = NULL;
1367         loadmodel->DrawAddWaterPlanes = NULL;
1368         loadmodel->Draw = R_Q1BSP_Draw;
1369         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1370         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1371         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1372         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1373         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1374         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1375         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1376         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1377         loadmodel->PointSuperContents = NULL;
1378         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1379
1380         if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1381                 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1382         if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1383                 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1384         if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1385                 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1386         if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1387                 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1388
1389         end = LittleLong(pinmodel->ofs_end);
1390         if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1391                 Host_Error ("%s is not a valid model", loadmodel->name);
1392         if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1393                 Host_Error ("%s is not a valid model", loadmodel->name);
1394         if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1395                 Host_Error ("%s is not a valid model", loadmodel->name);
1396         if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1397                 Host_Error ("%s is not a valid model", loadmodel->name);
1398         if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1399                 Host_Error ("%s is not a valid model", loadmodel->name);
1400
1401         loadmodel->numskins = LittleLong(pinmodel->num_skins);
1402         numxyz = LittleLong(pinmodel->num_xyz);
1403         numst = LittleLong(pinmodel->num_st);
1404         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1405         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1406         loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1407         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1408         skinwidth = LittleLong(pinmodel->skinwidth);
1409         skinheight = LittleLong(pinmodel->skinheight);
1410         iskinwidth = 1.0f / skinwidth;
1411         iskinheight = 1.0f / skinheight;
1412
1413         loadmodel->num_surfaces = 1;
1414         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1415         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]));
1416         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1417         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1418         loadmodel->sortedmodelsurfaces[0] = 0;
1419         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1420         loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1421         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1422
1423         loadmodel->synctype = ST_RAND;
1424
1425         // load the skins
1426         inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1427         skinfiles = Mod_LoadSkinFiles();
1428         if (skinfiles)
1429         {
1430                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1431                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1432                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1433                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1434                 Mod_FreeSkinFiles(skinfiles);
1435         }
1436         else if (loadmodel->numskins)
1437         {
1438                 // skins found (most likely not a player model)
1439                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1440                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1441                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1442                 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1443                         Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
1444         }
1445         else
1446         {
1447                 // no skins (most likely a player model)
1448                 loadmodel->numskins = 1;
1449                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1450                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1451                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1452                 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures, loadmodel->name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
1453         }
1454
1455         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1456         for (i = 0;i < loadmodel->numskins;i++)
1457         {
1458                 loadmodel->skinscenes[i].firstframe = i;
1459                 loadmodel->skinscenes[i].framecount = 1;
1460                 loadmodel->skinscenes[i].loop = true;
1461                 loadmodel->skinscenes[i].framerate = 10;
1462         }
1463
1464         // load the triangles and stvert data
1465         inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1466         intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1467         md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1468         md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1469         // swap the triangle list
1470         loadmodel->surfmesh.num_vertices = 0;
1471         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1472         {
1473                 for (j = 0;j < 3;j++)
1474                 {
1475                         xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1476                         st = (unsigned short) LittleShort (intri[i].index_st[j]);
1477                         if (xyz >= numxyz)
1478                         {
1479                                 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1480                                 xyz = 0;
1481                         }
1482                         if (st >= numst)
1483                         {
1484                                 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1485                                 st = 0;
1486                         }
1487                         hashindex = (xyz * 256 + st) & 65535;
1488                         for (hash = md2verthash[hashindex];hash;hash = hash->next)
1489                                 if (hash->xyz == xyz && hash->st == st)
1490                                         break;
1491                         if (hash == NULL)
1492                         {
1493                                 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1494                                 hash->xyz = xyz;
1495                                 hash->st = st;
1496                                 hash->next = md2verthash[hashindex];
1497                                 md2verthash[hashindex] = hash;
1498                         }
1499                         loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1500                 }
1501         }
1502
1503         vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1504         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));
1505         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1506         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1507         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1508         {
1509                 int sts, stt;
1510                 hash = md2verthashdata + i;
1511                 vertremap[i] = hash->xyz;
1512                 sts = LittleShort(inst[hash->st*2+0]);
1513                 stt = LittleShort(inst[hash->st*2+1]);
1514                 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1515                 {
1516                         Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1517                         sts = 0;
1518                         stt = 0;
1519                 }
1520                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1521                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1522         }
1523
1524         Mem_Free(md2verthash);
1525         Mem_Free(md2verthashdata);
1526
1527         // generate ushort elements array if possible
1528         if (loadmodel->surfmesh.num_vertices <= 65536)
1529                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1530         if (loadmodel->surfmesh.data_element3s)
1531                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1532                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1533
1534         // load the frames
1535         datapointer = (base + LittleLong(pinmodel->ofs_frames));
1536         for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1537         {
1538                 int k;
1539                 trivertx_t *v;
1540                 trivertx_t *out;
1541                 pinframe = (md2frame_t *)datapointer;
1542                 datapointer += sizeof(md2frame_t);
1543                 // store the frame scale/translate into the appropriate array
1544                 for (j = 0;j < 3;j++)
1545                 {
1546                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1547                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1548                 }
1549                 // convert the vertices
1550                 v = (trivertx_t *)datapointer;
1551                 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1552                 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1553                         out[k] = v[vertremap[k]];
1554                 datapointer += numxyz * sizeof(trivertx_t);
1555
1556                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1557                 loadmodel->animscenes[i].firstframe = i;
1558                 loadmodel->animscenes[i].framecount = 1;
1559                 loadmodel->animscenes[i].framerate = 10;
1560                 loadmodel->animscenes[i].loop = true;
1561         }
1562
1563         Mem_Free(vertremap);
1564
1565         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1566         Mod_Alias_MorphMesh_CompileFrames();
1567         if(mod_alias_force_animated.string[0])
1568                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1569
1570         surface = loadmodel->data_surfaces;
1571         surface->texture = loadmodel->data_textures;
1572         surface->num_firsttriangle = 0;
1573         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1574         surface->num_firstvertex = 0;
1575         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1576
1577         // Always make a BIH for the first frame, we can use it where possible.
1578         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1579         if (!loadmodel->surfmesh.isanimated)
1580         {
1581                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1582                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1583                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1584                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1585                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1586         }
1587
1588         // because shaders can do somewhat unexpected things, check for unusual features now
1589         for (i = 0;i < loadmodel->num_textures;i++)
1590         {
1591                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1592                         mod->DrawSky = R_Q1BSP_DrawSky;
1593                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1594                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1595         }
1596 }
1597
1598 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1599 {
1600         int i, j, k, version, meshvertices, meshtriangles;
1601         unsigned char *data;
1602         msurface_t *surface;
1603         md3modelheader_t *pinmodel;
1604         md3frameinfo_t *pinframe;
1605         md3mesh_t *pinmesh;
1606         md3tag_t *pintag;
1607         skinfile_t *skinfiles;
1608
1609         pinmodel = (md3modelheader_t *)buffer;
1610
1611         if (memcmp(pinmodel->identifier, "IDP3", 4))
1612                 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1613         version = LittleLong (pinmodel->version);
1614         if (version != MD3VERSION)
1615                 Host_Error ("%s has wrong version number (%i should be %i)",
1616                         loadmodel->name, version, MD3VERSION);
1617
1618         skinfiles = Mod_LoadSkinFiles();
1619         if (loadmodel->numskins < 1)
1620                 loadmodel->numskins = 1;
1621
1622         loadmodel->modeldatatypestring = "MD3";
1623
1624         loadmodel->type = mod_alias;
1625         loadmodel->DrawSky = NULL;
1626         loadmodel->DrawAddWaterPlanes = NULL;
1627         loadmodel->Draw = R_Q1BSP_Draw;
1628         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1629         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1630         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1631         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1632         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1633         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1634         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1635         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1636         loadmodel->PointSuperContents = NULL;
1637         loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1638         loadmodel->synctype = ST_RAND;
1639         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1640         i = LittleLong (pinmodel->flags);
1641         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1642
1643         // set up some global info about the model
1644         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1645         loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1646
1647         // make skinscenes for the skins (no groups)
1648         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1649         for (i = 0;i < loadmodel->numskins;i++)
1650         {
1651                 loadmodel->skinscenes[i].firstframe = i;
1652                 loadmodel->skinscenes[i].framecount = 1;
1653                 loadmodel->skinscenes[i].loop = true;
1654                 loadmodel->skinscenes[i].framerate = 10;
1655         }
1656
1657         // load frameinfo
1658         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1659         for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1660         {
1661                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1662                 loadmodel->animscenes[i].firstframe = i;
1663                 loadmodel->animscenes[i].framecount = 1;
1664                 loadmodel->animscenes[i].framerate = 10;
1665                 loadmodel->animscenes[i].loop = true;
1666         }
1667
1668         // load tags
1669         loadmodel->num_tagframes = loadmodel->numframes;
1670         loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1671         loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1672         for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1673         {
1674                 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1675                 for (j = 0;j < 9;j++)
1676                         loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1677                 for (j = 0;j < 3;j++)
1678                         loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1679                 //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);
1680         }
1681
1682         // load meshes
1683         meshvertices = 0;
1684         meshtriangles = 0;
1685         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)))
1686         {
1687                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1688                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1689                 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1690                         Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1691                 meshvertices += LittleLong(pinmesh->num_vertices);
1692                 meshtriangles += LittleLong(pinmesh->num_triangles);
1693         }
1694
1695         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1696         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1697         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1698         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));
1699         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1700         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1701         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1702         loadmodel->surfmesh.num_vertices = meshvertices;
1703         loadmodel->surfmesh.num_triangles = meshtriangles;
1704         loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1705         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1706         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1707         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1708         loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1709         if (meshvertices <= 65536)
1710         {
1711                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1712         }
1713
1714         meshvertices = 0;
1715         meshtriangles = 0;
1716         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)))
1717         {
1718                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1719                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1720                 loadmodel->sortedmodelsurfaces[i] = i;
1721                 surface = loadmodel->data_surfaces + i;
1722                 surface->texture = loadmodel->data_textures + i;
1723                 surface->num_firsttriangle = meshtriangles;
1724                 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1725                 surface->num_firstvertex = meshvertices;
1726                 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1727                 meshvertices += surface->num_vertices;
1728                 meshtriangles += surface->num_triangles;
1729
1730                 for (j = 0;j < surface->num_triangles * 3;j++)
1731                 {
1732                         int e = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1733                         loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = e;
1734                         if (loadmodel->surfmesh.data_element3s)
1735                                 loadmodel->surfmesh.data_element3s[j + surface->num_firsttriangle * 3] = e;
1736                 }
1737                 for (j = 0;j < surface->num_vertices;j++)
1738                 {
1739                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1740                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1741                 }
1742                 for (j = 0;j < loadmodel->numframes;j++)
1743                 {
1744                         const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1745                         md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1746                         for (k = 0;k < surface->num_vertices;k++, in++, out++)
1747                         {
1748                                 out->origin[0] = LittleShort(in->origin[0]);
1749                                 out->origin[1] = LittleShort(in->origin[1]);
1750                                 out->origin[2] = LittleShort(in->origin[2]);
1751                                 out->pitch = in->pitch;
1752                                 out->yaw = in->yaw;
1753                         }
1754                 }
1755
1756                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1757
1758                 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__);
1759         }
1760         Mod_Alias_MorphMesh_CompileFrames();
1761         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1762         Mod_FreeSkinFiles(skinfiles);
1763         Mod_MakeSortedSurfaces(loadmodel);
1764         if(mod_alias_force_animated.string[0])
1765                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1766
1767         // Always make a BIH for the first frame, we can use it where possible.
1768         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1769         if (!loadmodel->surfmesh.isanimated)
1770         {
1771                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1772                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1773                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1774                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1775                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1776         }
1777
1778         // because shaders can do somewhat unexpected things, check for unusual features now
1779         for (i = 0;i < loadmodel->num_textures;i++)
1780         {
1781                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1782                         mod->DrawSky = R_Q1BSP_DrawSky;
1783                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1784                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1785         }
1786 }
1787
1788 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1789 {
1790         zymtype1header_t *pinmodel, *pheader;
1791         unsigned char *pbase;
1792         int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1793         float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1794         zymvertex_t *verts, *vertdata;
1795         zymscene_t *scene;
1796         zymbone_t *bone;
1797         char *shadername;
1798         skinfile_t *skinfiles;
1799         unsigned char *data;
1800         msurface_t *surface;
1801
1802         pinmodel = (zymtype1header_t *)buffer;
1803         pbase = (unsigned char *)buffer;
1804         if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1805                 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1806         if (BigLong(pinmodel->type) != 1)
1807                 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1808
1809         loadmodel->modeldatatypestring = "ZYM";
1810
1811         loadmodel->type = mod_alias;
1812         loadmodel->synctype = ST_RAND;
1813
1814         // byteswap header
1815         pheader = pinmodel;
1816         pheader->type = BigLong(pinmodel->type);
1817         pheader->filesize = BigLong(pinmodel->filesize);
1818         pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1819         pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1820         pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1821         pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1822         pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1823         pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1824         pheader->radius = BigFloat(pinmodel->radius);
1825         pheader->numverts = BigLong(pinmodel->numverts);
1826         pheader->numtris = BigLong(pinmodel->numtris);
1827         pheader->numshaders = BigLong(pinmodel->numshaders);
1828         pheader->numbones = BigLong(pinmodel->numbones);
1829         pheader->numscenes = BigLong(pinmodel->numscenes);
1830         pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1831         pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1832         pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1833         pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1834         pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1835         pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1836         pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1837         pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1838         pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1839         pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1840         pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1841         pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1842         pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1843         pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1844         pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1845         pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1846         pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1847         pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1848
1849         if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1850         {
1851                 Con_Printf("%s has no geometry\n", loadmodel->name);
1852                 return;
1853         }
1854         if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1855         {
1856                 Con_Printf("%s has no animations\n", loadmodel->name);
1857                 return;
1858         }
1859
1860         loadmodel->DrawSky = NULL;
1861         loadmodel->DrawAddWaterPlanes = NULL;
1862         loadmodel->Draw = R_Q1BSP_Draw;
1863         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1864         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1865         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1866         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1867         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1868         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1869         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1870         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1871         loadmodel->PointSuperContents = NULL;
1872         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1873
1874         loadmodel->numframes = pheader->numscenes;
1875         loadmodel->num_surfaces = pheader->numshaders;
1876
1877         skinfiles = Mod_LoadSkinFiles();
1878         if (loadmodel->numskins < 1)
1879                 loadmodel->numskins = 1;
1880
1881         // make skinscenes for the skins (no groups)
1882         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1883         for (i = 0;i < loadmodel->numskins;i++)
1884         {
1885                 loadmodel->skinscenes[i].firstframe = i;
1886                 loadmodel->skinscenes[i].framecount = 1;
1887                 loadmodel->skinscenes[i].loop = true;
1888                 loadmodel->skinscenes[i].framerate = 10;
1889         }
1890
1891         // model bbox
1892         // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1893         modelradius = pheader->radius;
1894         for (i = 0;i < 3;i++)
1895         {
1896                 loadmodel->normalmins[i] = pheader->mins[i];
1897                 loadmodel->normalmaxs[i] = pheader->maxs[i];
1898                 loadmodel->rotatedmins[i] = -modelradius;
1899                 loadmodel->rotatedmaxs[i] = modelradius;
1900         }
1901         corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1902         corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1903         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1904         if (loadmodel->yawmaxs[0] > modelradius)
1905                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1906         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1907         loadmodel->yawmins[2] = loadmodel->normalmins[2];
1908         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1909         loadmodel->radius = modelradius;
1910         loadmodel->radius2 = modelradius * modelradius;
1911
1912         // go through the lumps, swapping things
1913
1914         //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1915         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1916         scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1917         numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1918         for (i = 0;i < pheader->numscenes;i++)
1919         {
1920                 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1921                 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1922                 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1923                 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1924                 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1925                 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1926                         Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1927                 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1928                         Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1929                 if (loadmodel->animscenes[i].framerate < 0)
1930                         Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1931                 scene++;
1932         }
1933
1934         //zymlump_t lump_bones; // zymbone_t bone[numbones];
1935         loadmodel->num_bones = pheader->numbones;
1936         loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1937         bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1938         for (i = 0;i < pheader->numbones;i++)
1939         {
1940                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1941                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1942                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1943                 if (loadmodel->data_bones[i].parent >= i)
1944                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1945         }
1946
1947         //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1948         vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1949         bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1950         for (i = 0;i < pheader->numverts;i++)
1951         {
1952                 vertbonecounts[i] = BigLong(bonecount[i]);
1953                 if (vertbonecounts[i] != 1)
1954                         Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1955         }
1956
1957         loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1958
1959         meshvertices = pheader->numverts;
1960         meshtriangles = pheader->numtris;
1961
1962         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1963         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1964         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1965         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]));
1966         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1967         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1968         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1969         loadmodel->surfmesh.num_vertices = meshvertices;
1970         loadmodel->surfmesh.num_triangles = meshtriangles;
1971         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1972         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1973         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1974         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1975         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1976         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1977         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1978         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1979         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1980         loadmodel->surfmesh.num_blends = 0;
1981         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
1982         if (loadmodel->surfmesh.num_vertices <= 65536)
1983         {
1984                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1985         }
1986         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
1987         loadmodel->surfmesh.data_blendweights = NULL;
1988
1989         //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1990         poses = (float *) (pheader->lump_poses.start + pbase);
1991         // figure out scale of model from root bone, for compatibility with old zmodel versions
1992         tempvec[0] = BigFloat(poses[0]);
1993         tempvec[1] = BigFloat(poses[1]);
1994         tempvec[2] = BigFloat(poses[2]);
1995         modelscale = VectorLength(tempvec);
1996         biggestorigin = 0;
1997         for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
1998         {
1999                 f = fabs(BigFloat(poses[i]));
2000                 biggestorigin = max(biggestorigin, f);
2001         }
2002         loadmodel->num_posescale = biggestorigin / 32767.0f;
2003         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2004         for (i = 0;i < numposes;i++)
2005         {
2006                 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
2007                 for (j = 0;j < loadmodel->num_bones;j++)
2008                 {
2009                         float pose[12];
2010                         matrix4x4_t posematrix;
2011                         for (k = 0;k < 12;k++)
2012                                 pose[k] = BigFloat(frameposes[j*12+k]);
2013                         //if (j < loadmodel->num_bones)
2014                         //      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));
2015                         // scale child bones to match the root scale
2016                         if (loadmodel->data_bones[j].parent >= 0)
2017                         {
2018                                 pose[3] *= modelscale;
2019                                 pose[7] *= modelscale;
2020                                 pose[11] *= modelscale;
2021                         }
2022                         // normalize rotation matrix
2023                         VectorNormalize(pose + 0);
2024                         VectorNormalize(pose + 4);
2025                         VectorNormalize(pose + 8);
2026                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2027                         Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2028                 }
2029         }
2030
2031         //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2032         verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2033         vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2034         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2035         // (converting from weight-blending skeletal animation to
2036         //  deformation-based skeletal animation)
2037         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2038         for (i = 0;i < loadmodel->num_bones;i++)
2039         {
2040                 float m[12];
2041                 for (k = 0;k < 12;k++)
2042                         m[k] = BigFloat(poses[i*12+k]);
2043                 if (loadmodel->data_bones[i].parent >= 0)
2044                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2045                 else
2046                         for (k = 0;k < 12;k++)
2047                                 bonepose[12*i+k] = m[k];
2048         }
2049         for (j = 0;j < pheader->numverts;j++)
2050         {
2051                 // this format really should have had a per vertexweight weight value...
2052                 // but since it does not, the weighting is completely ignored and
2053                 // only one weight is allowed per vertex
2054                 int boneindex = BigLong(vertdata[j].bonenum);
2055                 const float *m = bonepose + 12 * boneindex;
2056                 float relativeorigin[3];
2057                 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2058                 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2059                 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2060                 // transform the vertex bone weight into the base mesh
2061                 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2062                 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2063                 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2064                 // store the weight as the primary weight on this vertex
2065                 loadmodel->surfmesh.blends[j] = boneindex;
2066                 loadmodel->surfmesh.data_skeletalindex4ub[j*4  ] = boneindex;
2067                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2068                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2069                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2070                 loadmodel->surfmesh.data_skeletalweight4ub[j*4  ] = 255;
2071                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2072                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2073                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2074         }
2075         Z_Free(bonepose);
2076         // normals and tangents are calculated after elements are loaded
2077
2078         //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2079         outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2080         intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2081         for (i = 0;i < pheader->numverts;i++)
2082         {
2083                 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2084                 // flip T coordinate for OpenGL
2085                 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2086         }
2087
2088         //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2089         //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2090         //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2091
2092         //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2093         //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)
2094         // byteswap, validate, and swap winding order of tris
2095         count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2096         if (pheader->lump_render.length != count)
2097                 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2098         renderlist = (int *) (pheader->lump_render.start + pbase);
2099         renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2100         meshtriangles = 0;
2101         for (i = 0;i < loadmodel->num_surfaces;i++)
2102         {
2103                 int firstvertex, lastvertex;
2104                 if (renderlist >= renderlistend)
2105                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2106                 count = BigLong(*renderlist);renderlist++;
2107                 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2108                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2109
2110                 loadmodel->sortedmodelsurfaces[i] = i;
2111                 surface = loadmodel->data_surfaces + i;
2112                 surface->texture = loadmodel->data_textures + i;
2113                 surface->num_firsttriangle = meshtriangles;
2114                 surface->num_triangles = count;
2115                 meshtriangles += surface->num_triangles;
2116
2117                 // load the elements
2118                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2119                 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2120                 {
2121                         outelements[j*3+2] = BigLong(renderlist[0]);
2122                         outelements[j*3+1] = BigLong(renderlist[1]);
2123                         outelements[j*3+0] = BigLong(renderlist[2]);
2124                 }
2125                 // validate the elements and find the used vertex range
2126                 firstvertex = meshvertices;
2127                 lastvertex = 0;
2128                 for (j = 0;j < surface->num_triangles * 3;j++)
2129                 {
2130                         if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2131                                 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2132                         firstvertex = min(firstvertex, outelements[j]);
2133                         lastvertex = max(lastvertex, outelements[j]);
2134                 }
2135                 surface->num_firstvertex = firstvertex;
2136                 surface->num_vertices = lastvertex + 1 - firstvertex;
2137
2138                 // since zym models do not have named sections, reuse their shader
2139                 // name as the section name
2140                 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2141                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2142         }
2143         Mod_FreeSkinFiles(skinfiles);
2144         Mem_Free(vertbonecounts);
2145         Mem_Free(verts);
2146         Mod_MakeSortedSurfaces(loadmodel);
2147
2148         // compute all the mesh information that was not loaded from the file
2149         if (loadmodel->surfmesh.data_element3s)
2150                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2151                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2152         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2153         Mod_BuildBaseBonePoses();
2154         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);
2155         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);
2156         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2157         if(mod_alias_force_animated.string[0])
2158                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2159
2160         // Always make a BIH for the first frame, we can use it where possible.
2161         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2162         if (!loadmodel->surfmesh.isanimated)
2163         {
2164                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2165                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2166                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2167                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2168                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2169         }
2170
2171         // because shaders can do somewhat unexpected things, check for unusual features now
2172         for (i = 0;i < loadmodel->num_textures;i++)
2173         {
2174                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2175                         mod->DrawSky = R_Q1BSP_DrawSky;
2176                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2177                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2178         }
2179 }
2180
2181 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2182 {
2183         dpmheader_t *pheader;
2184         dpmframe_t *frames;
2185         dpmbone_t *bone;
2186         dpmmesh_t *dpmmesh;
2187         unsigned char *pbase;
2188         int i, j, k, meshvertices, meshtriangles;
2189         skinfile_t *skinfiles;
2190         unsigned char *data;
2191         float *bonepose;
2192         float biggestorigin, tempvec[3], modelscale;
2193         float f;
2194         float *poses;
2195
2196         pheader = (dpmheader_t *)buffer;
2197         pbase = (unsigned char *)buffer;
2198         if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2199                 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2200         if (BigLong(pheader->type) != 2)
2201                 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2202
2203         loadmodel->modeldatatypestring = "DPM";
2204
2205         loadmodel->type = mod_alias;
2206         loadmodel->synctype = ST_RAND;
2207
2208         // byteswap header
2209         pheader->type = BigLong(pheader->type);
2210         pheader->filesize = BigLong(pheader->filesize);
2211         pheader->mins[0] = BigFloat(pheader->mins[0]);
2212         pheader->mins[1] = BigFloat(pheader->mins[1]);
2213         pheader->mins[2] = BigFloat(pheader->mins[2]);
2214         pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2215         pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2216         pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2217         pheader->yawradius = BigFloat(pheader->yawradius);
2218         pheader->allradius = BigFloat(pheader->allradius);
2219         pheader->num_bones = BigLong(pheader->num_bones);
2220         pheader->num_meshs = BigLong(pheader->num_meshs);
2221         pheader->num_frames = BigLong(pheader->num_frames);
2222         pheader->ofs_bones = BigLong(pheader->ofs_bones);
2223         pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2224         pheader->ofs_frames = BigLong(pheader->ofs_frames);
2225
2226         if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2227         {
2228                 Con_Printf("%s has no geometry\n", loadmodel->name);
2229                 return;
2230         }
2231         if (pheader->num_frames < 1)
2232         {
2233                 Con_Printf("%s has no frames\n", loadmodel->name);
2234                 return;
2235         }
2236
2237         loadmodel->DrawSky = NULL;
2238         loadmodel->DrawAddWaterPlanes = NULL;
2239         loadmodel->Draw = R_Q1BSP_Draw;
2240         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2241         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2242         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2243         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2244         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2245         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2246         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2247         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2248         loadmodel->PointSuperContents = NULL;
2249         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2250
2251         // model bbox
2252         // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2253         for (i = 0;i < 3;i++)
2254         {
2255                 loadmodel->normalmins[i] = pheader->mins[i];
2256                 loadmodel->normalmaxs[i] = pheader->maxs[i];
2257                 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2258                 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2259                 loadmodel->rotatedmins[i] = -pheader->allradius;
2260                 loadmodel->rotatedmaxs[i] = pheader->allradius;
2261         }
2262         loadmodel->radius = pheader->allradius;
2263         loadmodel->radius2 = pheader->allradius * pheader->allradius;
2264
2265         // load external .skin files if present
2266         skinfiles = Mod_LoadSkinFiles();
2267         if (loadmodel->numskins < 1)
2268                 loadmodel->numskins = 1;
2269
2270         meshvertices = 0;
2271         meshtriangles = 0;
2272
2273         // gather combined statistics from the meshes
2274         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2275         for (i = 0;i < (int)pheader->num_meshs;i++)
2276         {
2277                 int numverts = BigLong(dpmmesh->num_verts);
2278                 meshvertices += numverts;
2279                 meshtriangles += BigLong(dpmmesh->num_tris);
2280                 dpmmesh++;
2281         }
2282
2283         loadmodel->numframes = pheader->num_frames;
2284         loadmodel->num_bones = pheader->num_bones;
2285         loadmodel->num_poses = loadmodel->numframes;
2286         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2287         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2288         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2289         // do most allocations as one merged chunk
2290         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));
2291         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2292         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2293         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2294         loadmodel->surfmesh.num_vertices = meshvertices;
2295         loadmodel->surfmesh.num_triangles = meshtriangles;
2296         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2297         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2298         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2299         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2300         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2301         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2302         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2303         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2304         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2305         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2306         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2307         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2308         loadmodel->surfmesh.num_blends = 0;
2309         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2310         if (meshvertices <= 65536)
2311         {
2312                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2313         }
2314         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2315         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2316
2317         for (i = 0;i < loadmodel->numskins;i++)
2318         {
2319                 loadmodel->skinscenes[i].firstframe = i;
2320                 loadmodel->skinscenes[i].framecount = 1;
2321                 loadmodel->skinscenes[i].loop = true;
2322                 loadmodel->skinscenes[i].framerate = 10;
2323         }
2324
2325         // load the bone info
2326         bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2327         for (i = 0;i < loadmodel->num_bones;i++)
2328         {
2329                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2330                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2331                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2332                 if (loadmodel->data_bones[i].parent >= i)
2333                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2334         }
2335
2336         // load the frames
2337         frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2338         // figure out scale of model from root bone, for compatibility with old dpmodel versions
2339         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2340         tempvec[0] = BigFloat(poses[0]);
2341         tempvec[1] = BigFloat(poses[1]);
2342         tempvec[2] = BigFloat(poses[2]);
2343         modelscale = VectorLength(tempvec);
2344         biggestorigin = 0;
2345         for (i = 0;i < loadmodel->numframes;i++)
2346         {
2347                 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2348                 loadmodel->animscenes[i].firstframe = i;
2349                 loadmodel->animscenes[i].framecount = 1;
2350                 loadmodel->animscenes[i].loop = true;
2351                 loadmodel->animscenes[i].framerate = 10;
2352                 // load the bone poses for this frame
2353                 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2354                 for (j = 0;j < loadmodel->num_bones*12;j++)
2355                 {
2356                         f = fabs(BigFloat(poses[j]));
2357                         biggestorigin = max(biggestorigin, f);
2358                 }
2359                 // stuff not processed here: mins, maxs, yawradius, allradius
2360         }
2361         loadmodel->num_posescale = biggestorigin / 32767.0f;
2362         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2363         for (i = 0;i < loadmodel->numframes;i++)
2364         {
2365                 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2366                 for (j = 0;j < loadmodel->num_bones;j++)
2367                 {
2368                         float pose[12];
2369                         matrix4x4_t posematrix;
2370                         for (k = 0;k < 12;k++)
2371                                 pose[k] = BigFloat(frameposes[j*12+k]);
2372                         // scale child bones to match the root scale
2373                         if (loadmodel->data_bones[j].parent >= 0)
2374                         {
2375                                 pose[3] *= modelscale;
2376                                 pose[7] *= modelscale;
2377                                 pose[11] *= modelscale;
2378                         }
2379                         // normalize rotation matrix
2380                         VectorNormalize(pose + 0);
2381                         VectorNormalize(pose + 4);
2382                         VectorNormalize(pose + 8);
2383                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2384                         Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2385                 }
2386         }
2387
2388         // load the meshes now
2389         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2390         meshvertices = 0;
2391         meshtriangles = 0;
2392         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2393         // (converting from weight-blending skeletal animation to
2394         //  deformation-based skeletal animation)
2395         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2396         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2397         for (i = 0;i < loadmodel->num_bones;i++)
2398         {
2399                 float m[12];
2400                 for (k = 0;k < 12;k++)
2401                         m[k] = BigFloat(poses[i*12+k]);
2402                 if (loadmodel->data_bones[i].parent >= 0)
2403                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2404                 else
2405                         for (k = 0;k < 12;k++)
2406                                 bonepose[12*i+k] = m[k];
2407         }
2408         for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2409         {
2410                 const int *inelements;
2411                 int *outelement3i;
2412                 unsigned short *outelement3s;
2413                 const float *intexcoord;
2414                 msurface_t *surface;
2415
2416                 loadmodel->sortedmodelsurfaces[i] = i;
2417                 surface = loadmodel->data_surfaces + i;
2418                 surface->texture = loadmodel->data_textures + i;
2419                 surface->num_firsttriangle = meshtriangles;
2420                 surface->num_triangles = BigLong(dpmmesh->num_tris);
2421                 surface->num_firstvertex = meshvertices;
2422                 surface->num_vertices = BigLong(dpmmesh->num_verts);
2423                 meshvertices += surface->num_vertices;
2424                 meshtriangles += surface->num_triangles;
2425
2426                 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2427                 outelement3i = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2428                 outelement3s = loadmodel->surfmesh.data_element3s ? loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3 : NULL;
2429                 for (j = 0;j < surface->num_triangles;j++)
2430                 {
2431                         // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2432                         outelement3i[j * 3 + 0] = surface->num_firstvertex + BigLong(inelements[j * 3 + 2]);
2433                         outelement3i[j * 3 + 1] = surface->num_firstvertex + BigLong(inelements[j * 3 + 1]);
2434                         outelement3i[j * 3 + 2] = surface->num_firstvertex + BigLong(inelements[j * 3 + 0]);
2435                         if (outelement3s)
2436                         {
2437                                 outelement3s[j * 3 + 0] = outelement3i[j * 3 + 0];
2438                                 outelement3s[j * 3 + 1] = outelement3i[j * 3 + 1];
2439                                 outelement3s[j * 3 + 2] = outelement3i[j * 3 + 2];
2440                         }
2441                 }
2442
2443                 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2444                 for (j = 0;j < surface->num_vertices*2;j++)
2445                         loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2446
2447                 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2448                 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2449                 {
2450                         int weightindex[4] = { 0, 0, 0, 0 };
2451                         float weightinfluence[4] = { 0, 0, 0, 0 };
2452                         int l;
2453                         int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2454                         data += sizeof(dpmvertex_t);
2455                         for (k = 0;k < numweights;k++)
2456                         {
2457                                 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2458                                 int boneindex = BigLong(vert->bonenum);
2459                                 const float *m = bonepose + 12 * boneindex;
2460                                 float influence = BigFloat(vert->influence);
2461                                 float relativeorigin[3], relativenormal[3];
2462                                 relativeorigin[0] = BigFloat(vert->origin[0]);
2463                                 relativeorigin[1] = BigFloat(vert->origin[1]);
2464                                 relativeorigin[2] = BigFloat(vert->origin[2]);
2465                                 relativenormal[0] = BigFloat(vert->normal[0]);
2466                                 relativenormal[1] = BigFloat(vert->normal[1]);
2467                                 relativenormal[2] = BigFloat(vert->normal[2]);
2468                                 // blend the vertex bone weights into the base mesh
2469                                 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2470                                 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2471                                 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2472                                 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2473                                 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2474                                 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2475                                 if (!k)
2476                                 {
2477                                         // store the first (and often only) weight
2478                                         weightinfluence[0] = influence;
2479                                         weightindex[0] = boneindex;
2480                                 }
2481                                 else
2482                                 {
2483                                         // sort the new weight into this vertex's weight table
2484                                         // (which only accepts up to 4 bones per vertex)
2485                                         for (l = 0;l < 4;l++)
2486                                         {
2487                                                 if (weightinfluence[l] < influence)
2488                                                 {
2489                                                         // move weaker influence weights out of the way first
2490                                                         int l2;
2491                                                         for (l2 = 3;l2 > l;l2--)
2492                                                         {
2493                                                                 weightinfluence[l2] = weightinfluence[l2-1];
2494                                                                 weightindex[l2] = weightindex[l2-1];
2495                                                         }
2496                                                         // store the new weight
2497                                                         weightinfluence[l] = influence;
2498                                                         weightindex[l] = boneindex;
2499                                                         break;
2500                                                 }
2501                                         }
2502                                 }
2503                                 data += sizeof(dpmbonevert_t);
2504                         }
2505                         loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2506                         loadmodel->surfmesh.data_skeletalindex4ub[j*4  ] = weightindex[0];
2507                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2508                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2509                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2510                         loadmodel->surfmesh.data_skeletalweight4ub[j*4  ] = (unsigned char)(weightinfluence[0]*255.0f);
2511                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2512                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2513                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2514                 }
2515
2516                 // since dpm models do not have named sections, reuse their shader name as the section name
2517                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2518
2519                 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__);
2520         }
2521         if (loadmodel->surfmesh.num_blends < meshvertices)
2522                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2523         Z_Free(bonepose);
2524         Mod_FreeSkinFiles(skinfiles);
2525         Mod_MakeSortedSurfaces(loadmodel);
2526
2527         // compute all the mesh information that was not loaded from the file
2528         Mod_BuildBaseBonePoses();
2529         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);
2530         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2531         if(mod_alias_force_animated.string[0])
2532                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2533
2534         // Always make a BIH for the first frame, we can use it where possible.
2535         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2536         if (!loadmodel->surfmesh.isanimated)
2537         {
2538                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2539                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2540                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2541                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2542                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2543         }
2544
2545         // because shaders can do somewhat unexpected things, check for unusual features now
2546         for (i = 0;i < loadmodel->num_textures;i++)
2547         {
2548                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2549                         mod->DrawSky = R_Q1BSP_DrawSky;
2550                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2551                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2552         }
2553 }
2554
2555 // no idea why PSK/PSA files contain weird quaternions but they do...
2556 #define PSKQUATNEGATIONS
2557 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2558 {
2559         int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2560         int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2561         fs_offset_t filesize;
2562         pskpnts_t *pnts;
2563         pskvtxw_t *vtxw;
2564         pskface_t *faces;
2565         pskmatt_t *matts;
2566         pskboneinfo_t *bones;
2567         pskrawweights_t *rawweights;
2568         //pskboneinfo_t *animbones;
2569         pskaniminfo_t *anims;
2570         pskanimkeys_t *animkeys;
2571         void *animfilebuffer, *animbuffer, *animbufferend;
2572         unsigned char *data;
2573         pskchunk_t *pchunk;
2574         skinfile_t *skinfiles;
2575         char animname[MAX_QPATH];
2576         size_t size;
2577         float biggestorigin;
2578
2579         pchunk = (pskchunk_t *)buffer;
2580         if (strcmp(pchunk->id, "ACTRHEAD"))
2581                 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2582
2583         loadmodel->modeldatatypestring = "PSK";
2584
2585         loadmodel->type = mod_alias;
2586         loadmodel->DrawSky = NULL;
2587         loadmodel->DrawAddWaterPlanes = NULL;
2588         loadmodel->Draw = R_Q1BSP_Draw;
2589         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2590         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2591         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2592         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2593         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2594         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2595         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2596         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2597         loadmodel->PointSuperContents = NULL;
2598         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2599         loadmodel->synctype = ST_RAND;
2600
2601         FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2602         strlcat(animname, ".psa", sizeof(animname));
2603         animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2604         animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2605         if (!animbuffer)
2606                 animbufferend = animbuffer;
2607
2608         numpnts = 0;
2609         pnts = NULL;
2610         numvtxw = 0;
2611         vtxw = NULL;
2612         numfaces = 0;
2613         faces = NULL;
2614         nummatts = 0;
2615         matts = NULL;
2616         numbones = 0;
2617         bones = NULL;
2618         numrawweights = 0;
2619         rawweights = NULL;
2620         numanims = 0;
2621         anims = NULL;
2622         numanimkeys = 0;
2623         animkeys = NULL;
2624
2625         while (buffer < bufferend)
2626         {
2627                 pchunk = (pskchunk_t *)buffer;
2628                 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2629                 version = LittleLong(pchunk->version);
2630                 recordsize = LittleLong(pchunk->recordsize);
2631                 numrecords = LittleLong(pchunk->numrecords);
2632                 if (developer_extra.integer)
2633                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2634                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2635                         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);
2636                 if (!strcmp(pchunk->id, "ACTRHEAD"))
2637                 {
2638                         // nothing to do
2639                 }
2640                 else if (!strcmp(pchunk->id, "PNTS0000"))
2641                 {
2642                         pskpnts_t *p;
2643                         if (recordsize != sizeof(*p))
2644                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2645                         // byteswap in place and keep the pointer
2646                         numpnts = numrecords;
2647                         pnts = (pskpnts_t *)buffer;
2648                         for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2649                         {
2650                                 p->origin[0] = LittleFloat(p->origin[0]);
2651                                 p->origin[1] = LittleFloat(p->origin[1]);
2652                                 p->origin[2] = LittleFloat(p->origin[2]);
2653                         }
2654                         buffer = p;
2655                 }
2656                 else if (!strcmp(pchunk->id, "VTXW0000"))
2657                 {
2658                         pskvtxw_t *p;
2659                         if (recordsize != sizeof(*p))
2660                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2661                         // byteswap in place and keep the pointer
2662                         numvtxw = numrecords;
2663                         vtxw = (pskvtxw_t *)buffer;
2664                         for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2665                         {
2666                                 p->pntsindex = LittleShort(p->pntsindex);
2667                                 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2668                                 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2669                                 if (p->pntsindex >= numpnts)
2670                                 {
2671                                         Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2672                                         p->pntsindex = 0;
2673                                 }
2674                         }
2675                         buffer = p;
2676                 }
2677                 else if (!strcmp(pchunk->id, "FACE0000"))
2678                 {
2679                         pskface_t *p;
2680                         if (recordsize != sizeof(*p))
2681                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2682                         // byteswap in place and keep the pointer
2683                         numfaces = numrecords;
2684                         faces = (pskface_t *)buffer;
2685                         for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2686                         {
2687                                 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2688                                 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2689                                 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2690                                 p->group = LittleLong(p->group);
2691                                 if (p->vtxwindex[0] >= numvtxw)
2692                                 {
2693                                         Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2694                                         p->vtxwindex[0] = 0;
2695                                 }
2696                                 if (p->vtxwindex[1] >= numvtxw)
2697                                 {
2698                                         Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2699                                         p->vtxwindex[1] = 0;
2700                                 }
2701                                 if (p->vtxwindex[2] >= numvtxw)
2702                                 {
2703                                         Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2704                                         p->vtxwindex[2] = 0;
2705                                 }
2706                         }
2707                         buffer = p;
2708                 }
2709                 else if (!strcmp(pchunk->id, "MATT0000"))
2710                 {
2711                         pskmatt_t *p;
2712                         if (recordsize != sizeof(*p))
2713                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2714                         // byteswap in place and keep the pointer
2715                         nummatts = numrecords;
2716                         matts = (pskmatt_t *)buffer;
2717                         for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2718                         {
2719                                 // nothing to do
2720                         }
2721                         buffer = p;
2722                 }
2723                 else if (!strcmp(pchunk->id, "REFSKELT"))
2724                 {
2725                         pskboneinfo_t *p;
2726                         if (recordsize != sizeof(*p))
2727                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2728                         // byteswap in place and keep the pointer
2729                         numbones = numrecords;
2730                         bones = (pskboneinfo_t *)buffer;
2731                         for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2732                         {
2733                                 p->numchildren = LittleLong(p->numchildren);
2734                                 p->parent = LittleLong(p->parent);
2735                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2736                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2737                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2738                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2739                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2740                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2741                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2742                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2743                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2744                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2745                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2746 #ifdef PSKQUATNEGATIONS
2747                                 if (index)
2748                                 {
2749                                         p->basepose.quat[0] *= -1;
2750                                         p->basepose.quat[1] *= -1;
2751                                         p->basepose.quat[2] *= -1;
2752                                 }
2753                                 else
2754                                 {
2755                                         p->basepose.quat[0] *=  1;
2756                                         p->basepose.quat[1] *= -1;
2757                                         p->basepose.quat[2] *=  1;
2758                                 }
2759 #endif
2760                                 if (p->parent < 0 || p->parent >= numbones)
2761                                 {
2762                                         Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2763                                         p->parent = 0;
2764                                 }
2765                         }
2766                         buffer = p;
2767                 }
2768                 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2769                 {
2770                         pskrawweights_t *p;
2771                         if (recordsize != sizeof(*p))
2772                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2773                         // byteswap in place and keep the pointer
2774                         numrawweights = numrecords;
2775                         rawweights = (pskrawweights_t *)buffer;
2776                         for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2777                         {
2778                                 p->weight = LittleFloat(p->weight);
2779                                 p->pntsindex = LittleLong(p->pntsindex);
2780                                 p->boneindex = LittleLong(p->boneindex);
2781                                 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2782                                 {
2783                                         Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2784                                         p->pntsindex = 0;
2785                                 }
2786                                 if (p->boneindex < 0 || p->boneindex >= numbones)
2787                                 {
2788                                         Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2789                                         p->boneindex = 0;
2790                                 }
2791                         }
2792                         buffer = p;
2793                 }
2794         }
2795
2796         while (animbuffer < animbufferend)
2797         {
2798                 pchunk = (pskchunk_t *)animbuffer;
2799                 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2800                 version = LittleLong(pchunk->version);
2801                 recordsize = LittleLong(pchunk->recordsize);
2802                 numrecords = LittleLong(pchunk->numrecords);
2803                 if (developer_extra.integer)
2804                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2805                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2806                         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);
2807                 if (!strcmp(pchunk->id, "ANIMHEAD"))
2808                 {
2809                         // nothing to do
2810                 }
2811                 else if (!strcmp(pchunk->id, "BONENAMES"))
2812                 {
2813                         pskboneinfo_t *p;
2814                         if (recordsize != sizeof(*p))
2815                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2816                         // byteswap in place and keep the pointer
2817                         numanimbones = numrecords;
2818                         //animbones = (pskboneinfo_t *)animbuffer;
2819                         // NOTE: supposedly psa does not need to match the psk model, the
2820                         // bones missing from the psa would simply use their base
2821                         // positions from the psk, but this is hard for me to implement
2822                         // and people can easily make animations that match.
2823                         if (numanimbones != numbones)
2824                                 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2825                         for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2826                         {
2827                                 p->numchildren = LittleLong(p->numchildren);
2828                                 p->parent = LittleLong(p->parent);
2829                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2830                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2831                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2832                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2833                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2834                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2835                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2836                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2837                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2838                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2839                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2840 #ifdef PSKQUATNEGATIONS
2841                                 if (index)
2842                                 {
2843                                         p->basepose.quat[0] *= -1;
2844                                         p->basepose.quat[1] *= -1;
2845                                         p->basepose.quat[2] *= -1;
2846                                 }
2847                                 else
2848                                 {
2849                                         p->basepose.quat[0] *=  1;
2850                                         p->basepose.quat[1] *= -1;
2851                                         p->basepose.quat[2] *=  1;
2852                                 }
2853 #endif
2854                                 if (p->parent < 0 || p->parent >= numanimbones)
2855                                 {
2856                                         Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2857                                         p->parent = 0;
2858                                 }
2859                                 // check that bones are the same as in the base
2860                                 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2861                                         Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2862                         }
2863                         animbuffer = p;
2864                 }
2865                 else if (!strcmp(pchunk->id, "ANIMINFO"))
2866                 {
2867                         pskaniminfo_t *p;
2868                         if (recordsize != sizeof(*p))
2869                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2870                         // byteswap in place and keep the pointer
2871                         numanims = numrecords;
2872                         anims = (pskaniminfo_t *)animbuffer;
2873                         for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2874                         {
2875                                 p->numbones = LittleLong(p->numbones);
2876                                 p->playtime = LittleFloat(p->playtime);
2877                                 p->fps = LittleFloat(p->fps);
2878                                 p->firstframe = LittleLong(p->firstframe);
2879                                 p->numframes = LittleLong(p->numframes);
2880                                 if (p->numbones != numbones)
2881                                         Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2882                         }
2883                         animbuffer = p;
2884                 }
2885                 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2886                 {
2887                         pskanimkeys_t *p;
2888                         if (recordsize != sizeof(*p))
2889                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2890                         numanimkeys = numrecords;
2891                         animkeys = (pskanimkeys_t *)animbuffer;
2892                         for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2893                         {
2894                                 p->origin[0] = LittleFloat(p->origin[0]);
2895                                 p->origin[1] = LittleFloat(p->origin[1]);
2896                                 p->origin[2] = LittleFloat(p->origin[2]);
2897                                 p->quat[0] = LittleFloat(p->quat[0]);
2898                                 p->quat[1] = LittleFloat(p->quat[1]);
2899                                 p->quat[2] = LittleFloat(p->quat[2]);
2900                                 p->quat[3] = LittleFloat(p->quat[3]);
2901                                 p->frametime = LittleFloat(p->frametime);
2902 #ifdef PSKQUATNEGATIONS
2903                                 if (index % numbones)
2904                                 {
2905                                         p->quat[0] *= -1;
2906                                         p->quat[1] *= -1;
2907                                         p->quat[2] *= -1;
2908                                 }
2909                                 else
2910                                 {
2911                                         p->quat[0] *=  1;
2912                                         p->quat[1] *= -1;
2913                                         p->quat[2] *=  1;
2914                                 }
2915 #endif
2916                         }
2917                         animbuffer = p;
2918                         // TODO: allocate bonepose stuff
2919                 }
2920                 else
2921                         Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2922         }
2923
2924         if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2925                 Host_Error("%s: missing required chunks", loadmodel->name);
2926
2927         if (numanims)
2928         {
2929                 loadmodel->numframes = 0;
2930                 for (index = 0;index < numanims;index++)
2931                         loadmodel->numframes += anims[index].numframes;
2932                 if (numanimkeys != numbones * loadmodel->numframes)
2933                         Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2934         }
2935         else
2936                 loadmodel->numframes = loadmodel->num_poses = 1;
2937
2938         meshvertices = numvtxw;
2939         meshtriangles = numfaces;
2940
2941         // load external .skin files if present
2942         skinfiles = Mod_LoadSkinFiles();
2943         if (loadmodel->numskins < 1)
2944                 loadmodel->numskins = 1;
2945         loadmodel->num_bones = numbones;
2946         loadmodel->num_poses = loadmodel->numframes;
2947         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2948         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2949         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2950         loadmodel->surfmesh.num_vertices = meshvertices;
2951         loadmodel->surfmesh.num_triangles = meshtriangles;
2952         // do most allocations as one merged chunk
2953         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);
2954         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2955         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2956         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2957         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2958         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2959         loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2960         loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2961         loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2962         loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2963         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2964         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2965         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2966         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2967         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2968         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2969         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2970         loadmodel->surfmesh.num_blends = 0;
2971         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2972         if (loadmodel->surfmesh.num_vertices <= 65536)
2973         {
2974                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2975         }
2976         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2977         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2978
2979         for (i = 0;i < loadmodel->numskins;i++)
2980         {
2981                 loadmodel->skinscenes[i].firstframe = i;
2982                 loadmodel->skinscenes[i].framecount = 1;
2983                 loadmodel->skinscenes[i].loop = true;
2984                 loadmodel->skinscenes[i].framerate = 10;
2985         }
2986
2987         // create surfaces
2988         for (index = 0, i = 0;index < nummatts;index++)
2989         {
2990                 // since psk models do not have named sections, reuse their shader name as the section name
2991                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2992                 loadmodel->sortedmodelsurfaces[index] = index;
2993                 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2994                 loadmodel->data_surfaces[index].num_firstvertex = 0;
2995                 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2996         }
2997
2998         // copy over the vertex locations and texcoords
2999         for (index = 0;index < numvtxw;index++)
3000         {
3001                 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
3002                 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
3003                 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
3004                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
3005                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
3006         }
3007
3008         // loading the faces is complicated because we need to sort them into surfaces by mattindex
3009         for (index = 0;index < numfaces;index++)
3010                 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
3011         for (index = 0, i = 0;index < nummatts;index++)
3012         {
3013                 loadmodel->data_surfaces[index].num_firsttriangle = i;
3014                 i += loadmodel->data_surfaces[index].num_triangles;
3015                 loadmodel->data_surfaces[index].num_triangles = 0;
3016         }
3017         for (index = 0;index < numfaces;index++)
3018         {
3019                 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3020                 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3021                 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3022                 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3023         }
3024
3025         // copy over the bones
3026         for (index = 0;index < numbones;index++)
3027         {
3028                 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3029                 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3030                 if (loadmodel->data_bones[index].parent >= index)
3031                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3032         }
3033
3034         // convert the basepose data
3035         if (loadmodel->num_bones)
3036         {
3037                 int boneindex;
3038                 matrix4x4_t *basebonepose;
3039                 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3040                 matrix4x4_t bonematrix;
3041                 matrix4x4_t tempbonematrix;
3042                 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3043                 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3044                 {
3045                         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]);
3046                         if (loadmodel->data_bones[boneindex].parent >= 0)
3047                         {
3048                                 tempbonematrix = bonematrix;
3049                                 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3050                         }
3051                         basebonepose[boneindex] = bonematrix;
3052                         Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3053                         Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3054                 }
3055                 Mem_Free(basebonepose);
3056         }
3057
3058         // sort the psk point weights into the vertex weight tables
3059         // (which only accept up to 4 bones per vertex)
3060         for (index = 0;index < numvtxw;index++)
3061         {
3062                 int weightindex[4] = { 0, 0, 0, 0 };
3063                 float weightinfluence[4] = { 0, 0, 0, 0 };
3064                 int l;
3065                 for (j = 0;j < numrawweights;j++)
3066                 {
3067                         if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3068                         {
3069                                 int boneindex = rawweights[j].boneindex;
3070                                 float influence = rawweights[j].weight;
3071                                 for (l = 0;l < 4;l++)
3072                                 {
3073                                         if (weightinfluence[l] < influence)
3074                                         {
3075                                                 // move lower influence weights out of the way first
3076                                                 int l2;
3077                                                 for (l2 = 3;l2 > l;l2--)
3078                                                 {
3079                                                         weightinfluence[l2] = weightinfluence[l2-1];
3080                                                         weightindex[l2] = weightindex[l2-1];
3081                                                 }
3082                                                 // store the new weight
3083                                                 weightinfluence[l] = influence;
3084                                                 weightindex[l] = boneindex;
3085                                                 break;
3086                                         }
3087                                 }
3088                         }
3089                 }
3090                 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3091                 loadmodel->surfmesh.data_skeletalindex4ub[index*4  ] = weightindex[0];
3092                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3093                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3094                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3095                 loadmodel->surfmesh.data_skeletalweight4ub[index*4  ] = (unsigned char)(weightinfluence[0]*255.0f);
3096                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3097                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3098                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3099         }
3100         if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3101                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3102
3103         // set up the animscenes based on the anims
3104         if (numanims)
3105         {
3106                 for (index = 0, i = 0;index < numanims;index++)
3107                 {
3108                         for (j = 0;j < anims[index].numframes;j++, i++)
3109                         {
3110                                 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3111                                 loadmodel->animscenes[i].firstframe = i;
3112                                 loadmodel->animscenes[i].framecount = 1;
3113                                 loadmodel->animscenes[i].loop = true;
3114                                 loadmodel->animscenes[i].framerate = anims[index].fps;
3115                         }
3116                 }
3117                 // calculate the scaling value for bone origins so they can be compressed to short
3118                 biggestorigin = 0;
3119                 for (index = 0;index < numanimkeys;index++)
3120                 {
3121                         pskanimkeys_t *k = animkeys + index;
3122                         biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3123                         biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3124                         biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3125                 }
3126                 loadmodel->num_posescale = biggestorigin / 32767.0f;
3127                 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3128         
3129                 // load the poses from the animkeys
3130                 for (index = 0;index < numanimkeys;index++)
3131                 {
3132                         pskanimkeys_t *k = animkeys + index;
3133                         float quat[4];
3134                         Vector4Copy(k->quat, quat);
3135                         if (quat[3] > 0)
3136                                 Vector4Negate(quat, quat);
3137                         Vector4Normalize2(quat, quat);
3138                         // compress poses to the short[7] format for longterm storage
3139                         loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3140                         loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3141                         loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3142                         loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3143                         loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3144                         loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3145                         loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3146                 }
3147         }
3148         else
3149         {
3150                 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3151                 loadmodel->animscenes[0].firstframe = 0;
3152                 loadmodel->animscenes[0].framecount = 1;
3153                 loadmodel->animscenes[0].loop = true;
3154                 loadmodel->animscenes[0].framerate = 10;
3155
3156                 // calculate the scaling value for bone origins so they can be compressed to short
3157                 biggestorigin = 0;
3158                 for (index = 0;index < numbones;index++)
3159                 {
3160                         pskboneinfo_t *p = bones + index;
3161                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3162                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3163                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3164                 }
3165                 loadmodel->num_posescale = biggestorigin / 32767.0f;
3166                 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3167         
3168                 // load the basepose as a frame
3169                 for (index = 0;index < numbones;index++)
3170                 {
3171                         pskboneinfo_t *p = bones + index;
3172                         float quat[4];
3173                         Vector4Copy(p->basepose.quat, quat);
3174                         if (quat[3] > 0)
3175                                 Vector4Negate(quat, quat);
3176                         Vector4Normalize2(quat, quat);
3177                         // compress poses to the short[7] format for longterm storage
3178                         loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3179                         loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3180                         loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3181                         loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3182                         loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3183                         loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3184                         loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3185                 }
3186         }
3187
3188         Mod_FreeSkinFiles(skinfiles);
3189         if (animfilebuffer)
3190                 Mem_Free(animfilebuffer);
3191         Mod_MakeSortedSurfaces(loadmodel);
3192
3193         // compute all the mesh information that was not loaded from the file
3194         // TODO: honor smoothing groups somehow?
3195         if (loadmodel->surfmesh.data_element3s)
3196                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3197                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3198         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3199         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);
3200         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);
3201         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3202         if(mod_alias_force_animated.string[0])
3203                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3204
3205         // Always make a BIH for the first frame, we can use it where possible.
3206         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3207         if (!loadmodel->surfmesh.isanimated)
3208         {
3209                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3210                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3211                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3212                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3213                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3214         }
3215
3216         // because shaders can do somewhat unexpected things, check for unusual features now
3217         for (i = 0;i < loadmodel->num_textures;i++)
3218         {
3219                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3220                         mod->DrawSky = R_Q1BSP_DrawSky;
3221                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3222                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3223         }
3224 }
3225
3226 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
3227 {
3228         unsigned char *data;
3229         const char *text;
3230         const unsigned char *pbase, *pend;
3231         iqmheader_t header;
3232         skinfile_t *skinfiles;
3233         int i, j, k, meshvertices, meshtriangles;
3234         float biggestorigin;
3235         const unsigned int *inelements;
3236         int *outelements;
3237         float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3238         // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3239         const float *vnormal = NULL;
3240         const float *vposition = NULL;
3241         const float *vtangent = NULL;
3242         const float *vtexcoord = NULL;
3243         const float *vcolor4f = NULL;
3244         const unsigned char *vblendindexes = NULL;
3245         const unsigned char *vblendweights = NULL;
3246         const unsigned char *vcolor4ub = NULL;
3247         const unsigned short *framedata = NULL;
3248         // temporary memory allocations (because the data in the file may be misaligned)
3249         iqmanim_t *anims = NULL;
3250         iqmbounds_t *bounds = NULL;
3251         iqmjoint1_t *joint1 = NULL;
3252         iqmjoint_t *joint = NULL;
3253         iqmmesh_t *meshes = NULL;
3254         iqmpose1_t *pose1 = NULL;
3255         iqmpose_t *pose = NULL;
3256         iqmvertexarray_t *vas = NULL;
3257
3258         pbase = (unsigned char *)buffer;
3259         pend = (unsigned char *)bufferend;
3260
3261         if (pbase + sizeof(iqmheader_t) > pend)
3262                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3263
3264         // copy struct (otherwise it may be misaligned)
3265         // LadyHavoc: okay it's definitely not misaligned here, but for consistency...
3266         memcpy(&header, pbase, sizeof(iqmheader_t));
3267
3268         if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3269                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3270         if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3271                 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3272
3273         loadmodel->modeldatatypestring = "IQM";
3274
3275         loadmodel->type = mod_alias;
3276         loadmodel->synctype = ST_RAND;
3277
3278         // byteswap header
3279         header.version = LittleLong(header.version);
3280         header.filesize = LittleLong(header.filesize);
3281         header.flags = LittleLong(header.flags);
3282         header.num_text = LittleLong(header.num_text);
3283         header.ofs_text = LittleLong(header.ofs_text);
3284         header.num_meshes = LittleLong(header.num_meshes);
3285         header.ofs_meshes = LittleLong(header.ofs_meshes);
3286         header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3287         header.num_vertexes = LittleLong(header.num_vertexes);
3288         header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3289         header.num_triangles = LittleLong(header.num_triangles);
3290         header.ofs_triangles = LittleLong(header.ofs_triangles);
3291         header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3292         header.num_joints = LittleLong(header.num_joints);
3293         header.ofs_joints = LittleLong(header.ofs_joints);
3294         header.num_poses = LittleLong(header.num_poses);
3295         header.ofs_poses = LittleLong(header.ofs_poses);
3296         header.num_anims = LittleLong(header.num_anims);
3297         header.ofs_anims = LittleLong(header.ofs_anims);
3298         header.num_frames = LittleLong(header.num_frames);
3299         header.num_framechannels = LittleLong(header.num_framechannels);
3300         header.ofs_frames = LittleLong(header.ofs_frames);
3301         header.ofs_bounds = LittleLong(header.ofs_bounds);
3302         header.num_comment = LittleLong(header.num_comment);
3303         header.ofs_comment = LittleLong(header.ofs_comment);
3304         header.num_extensions = LittleLong(header.num_extensions);
3305         header.ofs_extensions = LittleLong(header.ofs_extensions);
3306
3307         if (header.version == 1)
3308         {
3309                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3310                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3311                 {
3312                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3313                         return;
3314                 }
3315         }
3316         else
3317         {
3318                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3319                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3320                 {
3321                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3322                         return;
3323                 }
3324         }
3325         if (pbase + header.ofs_text + header.num_text > pend ||
3326                 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3327                 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3328                 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3329                 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3330                 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3331                 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3332                 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3333                 pbase + header.ofs_comment + header.num_comment > pend)
3334         {
3335                 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3336                 return;
3337         }
3338
3339         // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3340         if (header.num_vertexarrays)
3341                 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3342         if (header.num_anims)
3343                 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3344         if (header.ofs_bounds)
3345                 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3346         if (header.num_meshes)
3347                 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3348
3349         for (i = 0;i < (int)header.num_vertexarrays;i++)
3350         {
3351                 iqmvertexarray_t va;
3352                 size_t vsize;
3353                 va.type = LittleLong(vas[i].type);
3354                 va.flags = LittleLong(vas[i].flags);
3355                 va.format = LittleLong(vas[i].format);
3356                 va.size = LittleLong(vas[i].size);
3357                 va.offset = LittleLong(vas[i].offset);
3358                 vsize = header.num_vertexes*va.size;
3359                 switch (va.format)
3360                 { 
3361                 case IQM_FLOAT: vsize *= sizeof(float); break;
3362                 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3363                 default: continue;
3364                 }
3365                 if (pbase + va.offset + vsize > pend)
3366                         continue;
3367                 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3368                 switch (va.type)
3369                 {
3370                 case IQM_POSITION:
3371                         if (va.format == IQM_FLOAT && va.size == 3)
3372                                 vposition = (const float *)(pbase + va.offset);
3373                         break;
3374                 case IQM_TEXCOORD:
3375                         if (va.format == IQM_FLOAT && va.size == 2)
3376                                 vtexcoord = (const float *)(pbase + va.offset);
3377                         break;
3378                 case IQM_NORMAL:
3379                         if (va.format == IQM_FLOAT && va.size == 3)
3380                                 vnormal = (const float *)(pbase + va.offset);
3381                         break;
3382                 case IQM_TANGENT:
3383                         if (va.format == IQM_FLOAT && va.size == 4)
3384                                 vtangent = (const float *)(pbase + va.offset);
3385                         break;
3386                 case IQM_BLENDINDEXES:
3387                         if (va.format == IQM_UBYTE && va.size == 4)
3388                                 vblendindexes = (const unsigned char *)(pbase + va.offset);
3389                         break;
3390                 case IQM_BLENDWEIGHTS:
3391                         if (va.format == IQM_UBYTE && va.size == 4)
3392                                 vblendweights = (const unsigned char *)(pbase + va.offset);
3393                         break;
3394                 case IQM_COLOR:
3395                         if (va.format == IQM_FLOAT && va.size == 4)
3396                                 vcolor4f = (const float *)(pbase + va.offset);
3397                         if (va.format == IQM_UBYTE && va.size == 4)
3398                                 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3399                         break;
3400                 }
3401         }
3402         if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3403         {
3404                 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3405                 return;
3406         }
3407
3408         text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3409
3410         loadmodel->DrawSky = NULL;
3411         loadmodel->DrawAddWaterPlanes = NULL;
3412         loadmodel->Draw = R_Q1BSP_Draw;
3413         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
3414         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
3415         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
3416         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
3417         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
3418         loadmodel->DrawLight = R_Q1BSP_DrawLight;
3419         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3420         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3421         loadmodel->PointSuperContents = NULL;
3422         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3423
3424         // load external .skin files if present
3425         skinfiles = Mod_LoadSkinFiles();
3426         if (loadmodel->numskins < 1)
3427                 loadmodel->numskins = 1;
3428
3429         loadmodel->numframes = max(header.num_anims, 1);
3430         loadmodel->num_bones = header.num_joints;
3431         loadmodel->num_poses = max(header.num_frames, 1);
3432         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
3433         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3434         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3435
3436         meshvertices = header.num_vertexes;
3437         meshtriangles = header.num_triangles;
3438
3439         // do most allocations as one merged chunk
3440         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));
3441         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3442         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3443         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3444         loadmodel->surfmesh.num_vertices = meshvertices;
3445         loadmodel->surfmesh.num_triangles = meshtriangles;
3446         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3447         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3448         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3449         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3450         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3451         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3452         if (vcolor4f || vcolor4ub)
3453         {
3454                 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3455         }
3456         if (vblendindexes && vblendweights)
3457         {
3458                 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3459                 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3460         }
3461         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3462         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3463         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3464         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3465         if (vblendindexes && vblendweights)
3466         {
3467                 loadmodel->surfmesh.num_blends = 0;
3468                 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3469         }
3470         if (meshvertices <= 65536)
3471         {
3472                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3473         }
3474         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3475         if (vblendindexes && vblendweights)
3476                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3477
3478         for (i = 0;i < loadmodel->numskins;i++)
3479         {
3480                 loadmodel->skinscenes[i].firstframe = i;
3481                 loadmodel->skinscenes[i].framecount = 1;
3482                 loadmodel->skinscenes[i].loop = true;
3483                 loadmodel->skinscenes[i].framerate = 10;
3484         }
3485
3486         // load the bone info
3487         if (header.version == 1)
3488         {
3489                 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3490                 if (loadmodel->num_bones)
3491                         joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3492                 for (i = 0;i < loadmodel->num_bones;i++)
3493                 {
3494                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3495                         joint1[i].name = LittleLong(injoint1[i].name);
3496                         joint1[i].parent = LittleLong(injoint1[i].parent);
3497                         for (j = 0;j < 3;j++)
3498                         {
3499                                 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3500                                 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3501                                 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3502                         }
3503                         strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3504                         loadmodel->data_bones[i].parent = joint1[i].parent;
3505                         if (loadmodel->data_bones[i].parent >= i)
3506                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3507                         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]);
3508                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3509                         if (loadmodel->data_bones[i].parent >= 0)
3510                         {
3511                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3512                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3513                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3514                         }
3515                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3516                 }
3517         }
3518         else
3519         {
3520                 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3521                 if (header.num_joints)
3522                         joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3523                 for (i = 0;i < loadmodel->num_bones;i++)
3524                 {
3525                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3526                         joint[i].name = LittleLong(injoint[i].name);
3527                         joint[i].parent = LittleLong(injoint[i].parent);
3528                         for (j = 0;j < 3;j++)
3529                         {
3530                                 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3531                                 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3532                                 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3533                         }
3534                         joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3535                         strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3536                         loadmodel->data_bones[i].parent = joint[i].parent;
3537                         if (loadmodel->data_bones[i].parent >= i)
3538                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3539                         if (joint[i].rotation[3] > 0)
3540                                 Vector4Negate(joint[i].rotation, joint[i].rotation);
3541                         Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3542                         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]);
3543                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3544                         if (loadmodel->data_bones[i].parent >= 0)
3545                         {
3546                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3547                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3548                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3549                         }       
3550                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3551                 }
3552         }
3553
3554         // set up the animscenes based on the anims
3555         for (i = 0;i < (int)header.num_anims;i++)
3556         {
3557                 iqmanim_t anim;
3558                 anim.name = LittleLong(anims[i].name);
3559                 anim.first_frame = LittleLong(anims[i].first_frame);
3560                 anim.num_frames = LittleLong(anims[i].num_frames);
3561                 anim.framerate = LittleFloat(anims[i].framerate);
3562                 anim.flags = LittleLong(anims[i].flags);
3563                 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3564                 loadmodel->animscenes[i].firstframe = anim.first_frame;
3565                 loadmodel->animscenes[i].framecount = anim.num_frames;
3566                 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3567                 loadmodel->animscenes[i].framerate = anim.framerate;
3568         }
3569         if (header.num_anims <= 0)
3570         {
3571                 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3572                 loadmodel->animscenes[0].firstframe = 0;
3573                 loadmodel->animscenes[0].framecount = 1;
3574                 loadmodel->animscenes[0].loop = true;
3575                 loadmodel->animscenes[0].framerate = 10;
3576         }
3577
3578         loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3579         if(mod_alias_force_animated.string[0])
3580                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3581
3582         biggestorigin = 0;
3583         if (header.version == 1)
3584         {
3585                 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3586                 if (header.num_poses)
3587                         pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3588                 for (i = 0;i < (int)header.num_poses;i++)
3589                 {
3590                         float f;
3591                         pose1[i].parent = LittleLong(inpose1[i].parent);
3592                         pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3593                         for (j = 0;j < 9;j++)
3594                         {
3595                                 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3596                                 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3597                         }
3598                         f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3599                         f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3600                         f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3601                         f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3602                         f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3603                         f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3604                 }
3605                 if (header.num_frames <= 0)
3606                 {
3607                         for (i = 0;i < loadmodel->num_bones;i++)
3608                         {
3609                                 float f;
3610                                 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3611                                 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3612                                 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3613                         }
3614                 }
3615         }
3616         else
3617         {
3618                 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3619                 if (header.num_poses)
3620                         pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3621                 for (i = 0;i < (int)header.num_poses;i++)
3622                 {
3623                         float f;
3624                         pose[i].parent = LittleLong(inpose[i].parent);
3625                         pose[i].channelmask = LittleLong(inpose[i].channelmask);
3626                         for (j = 0;j < 10;j++)
3627                         {
3628                                 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3629                                 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3630                         }
3631                         f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3632                         f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3633                         f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3634                         f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3635                         f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3636                         f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3637                 }
3638                 if (header.num_frames <= 0)
3639                 {
3640                         for (i = 0;i < loadmodel->num_bones;i++)
3641                         {
3642                                 float f;
3643                                 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3644                                 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3645                                 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3646                         }
3647                 }
3648         }
3649         loadmodel->num_posescale = biggestorigin / 32767.0f;
3650         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3651
3652         // load the pose data
3653         // this unaligned memory access is safe (LittleShort reads as bytes)
3654         framedata = (const unsigned short *)(pbase + header.ofs_frames);
3655         if (header.version == 1)
3656         {
3657                 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3658                 {
3659                         for (j = 0;j < (int)header.num_poses;j++, k++)
3660                         {
3661                                 float qx, qy, qz, qw;
3662                                 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));
3663                                 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));
3664                                 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));
3665                                 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3666                                 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3667                                 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3668                                 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3669                                 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3670                                 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3671                                 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3672                                 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3673                                 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3674                                 // skip scale data for now
3675                                 if(pose1[j].channelmask&64) framedata++;
3676                                 if(pose1[j].channelmask&128) framedata++;
3677                                 if(pose1[j].channelmask&256) framedata++;
3678                         }
3679                 }
3680                 if (header.num_frames <= 0)
3681                 {
3682                         for (i = 0;i < loadmodel->num_bones;i++)
3683                         {
3684                                 float qx, qy, qz, qw;
3685                                 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3686                                 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3687                                 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3688                                 qx = joint1[i].rotation[0];
3689                                 qy = joint1[i].rotation[1];
3690                                 qz = joint1[i].rotation[2];
3691                                 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3692                                 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3693                                 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3694                                 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3695                                 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3696                                 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3697                         }
3698                 }
3699         }
3700         else
3701         {
3702                 for (i = 0, k = 0;i < (int)header.num_frames;i++)       
3703                 {
3704                         for (j = 0;j < (int)header.num_poses;j++, k++)
3705                         {
3706                                 float rot[4];
3707                                 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));
3708                                 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));
3709                                 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));
3710                                 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3711                                 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3712                                 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3713                                 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3714                                 if (rot[3] > 0)
3715                                         Vector4Negate(rot, rot);
3716                                 Vector4Normalize2(rot, rot);
3717                                 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3718                                 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3719                                 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3720                                 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3721                                 // skip scale data for now
3722                                 if(pose[j].channelmask&128) framedata++;
3723                                 if(pose[j].channelmask&256) framedata++;
3724                                 if(pose[j].channelmask&512) framedata++;
3725                         }
3726                 }
3727                 if (header.num_frames <= 0)
3728                 {
3729                         for (i = 0;i < loadmodel->num_bones;i++)
3730                         {
3731                                 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3732                                 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3733                                 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3734                                 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3735                                 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3736                                 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3737                                 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3738                         }
3739                 }
3740         }
3741
3742         // load bounding box data
3743         if (header.ofs_bounds)
3744         {
3745                 float xyradius = 0, radius = 0;
3746                 VectorClear(loadmodel->normalmins);
3747                 VectorClear(loadmodel->normalmaxs);
3748                 for (i = 0; i < (int)header.num_frames;i++)
3749                 {
3750                         iqmbounds_t bound;
3751                         bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3752                         bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3753                         bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3754                         bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);                 
3755                         bound.maxs[1] = LittleFloat(bounds[i].maxs[1]); 
3756                         bound.maxs[2] = LittleFloat(bounds[i].maxs[2]); 
3757                         bound.xyradius = LittleFloat(bounds[i].xyradius);
3758                         bound.radius = LittleFloat(bounds[i].radius);
3759                         if (!i)
3760                         {
3761                                 VectorCopy(bound.mins, loadmodel->normalmins);
3762                                 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3763                         }
3764                         else
3765                         {
3766                                 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3767                                 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3768                                 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3769                                 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3770                                 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3771                                 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3772                         }
3773                         if (bound.xyradius > xyradius)
3774                                 xyradius = bound.xyradius;
3775                         if (bound.radius > radius)
3776                                 radius = bound.radius;
3777                 }
3778                 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3779                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3780                 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3781                 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3782                 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3783                 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3784                 loadmodel->radius = radius;
3785                 loadmodel->radius2 = radius * radius;
3786         }
3787
3788         // load triangle data
3789         // this unaligned memory access is safe (LittleLong reads as bytes)
3790         inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3791         outelements = loadmodel->surfmesh.data_element3i;
3792         for (i = 0;i < (int)header.num_triangles;i++)
3793         {
3794                 outelements[0] = LittleLong(inelements[0]);
3795                 outelements[1] = LittleLong(inelements[1]);
3796                 outelements[2] = LittleLong(inelements[2]);
3797                 outelements += 3;
3798                 inelements += 3;
3799         }
3800         if (loadmodel->surfmesh.data_element3s)
3801                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3802                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3803         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3804
3805         // load vertex data
3806         // this unaligned memory access is safe (LittleFloat reads as bytes)
3807         outvertex = loadmodel->surfmesh.data_vertex3f;
3808         for (i = 0;i < (int)header.num_vertexes;i++)
3809         {
3810                 outvertex[0] = LittleFloat(vposition[0]);
3811                 outvertex[1] = LittleFloat(vposition[1]);
3812                 outvertex[2] = LittleFloat(vposition[2]);
3813                 vposition += 3;
3814                 outvertex += 3;
3815         }
3816
3817         outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3818         // this unaligned memory access is safe (LittleFloat reads as bytes)
3819         for (i = 0;i < (int)header.num_vertexes;i++)
3820         {
3821                 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3822                 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3823                 vtexcoord += 2;
3824                 outtexcoord += 2;
3825         }
3826
3827         // this unaligned memory access is safe (LittleFloat reads as bytes)
3828         if(vnormal)
3829         {
3830                 outnormal = loadmodel->surfmesh.data_normal3f;
3831                 for (i = 0;i < (int)header.num_vertexes;i++)
3832                 {
3833                         outnormal[0] = LittleFloat(vnormal[0]);
3834                         outnormal[1] = LittleFloat(vnormal[1]);
3835                         outnormal[2] = LittleFloat(vnormal[2]);
3836                         vnormal += 3;
3837                         outnormal += 3;
3838                 }
3839         }
3840
3841         // this unaligned memory access is safe (LittleFloat reads as bytes)
3842         if(vnormal && vtangent)
3843         {
3844                 outnormal = loadmodel->surfmesh.data_normal3f;
3845                 outsvector = loadmodel->surfmesh.data_svector3f;
3846                 outtvector = loadmodel->surfmesh.data_tvector3f;
3847                 for (i = 0;i < (int)header.num_vertexes;i++)
3848                 {
3849                         outsvector[0] = LittleFloat(vtangent[0]);
3850                         outsvector[1] = LittleFloat(vtangent[1]);
3851                         outsvector[2] = LittleFloat(vtangent[2]);
3852                         if(LittleFloat(vtangent[3]) < 0)
3853                                 CrossProduct(outsvector, outnormal, outtvector);
3854                         else
3855                                 CrossProduct(outnormal, outsvector, outtvector);
3856                         vtangent += 4;
3857                         outnormal += 3;
3858                         outsvector += 3;
3859                         outtvector += 3;
3860                 }
3861         }
3862
3863         // this unaligned memory access is safe (all bytes)
3864         if (vblendindexes && vblendweights)
3865         {
3866                 for (i = 0; i < (int)header.num_vertexes;i++)
3867                 {
3868                         blendweights_t weights;
3869                         memcpy(weights.index, vblendindexes + i*4, 4);
3870                         memcpy(weights.influence, vblendweights + i*4, 4);
3871                         loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3872                         loadmodel->surfmesh.data_skeletalindex4ub[i*4  ] = weights.index[0];
3873                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3874                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3875                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3876                         loadmodel->surfmesh.data_skeletalweight4ub[i*4  ] = weights.influence[0];
3877                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3878                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3879                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3880                 }
3881         }
3882
3883         if (vcolor4f)
3884         {
3885                 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3886                 // this unaligned memory access is safe (LittleFloat reads as bytes)
3887                 for (i = 0;i < (int)header.num_vertexes;i++)
3888                 {
3889                         outcolor[0] = LittleFloat(vcolor4f[0]);
3890                         outcolor[1] = LittleFloat(vcolor4f[1]);
3891                         outcolor[2] = LittleFloat(vcolor4f[2]);
3892                         outcolor[3] = LittleFloat(vcolor4f[3]);
3893                         vcolor4f += 4;
3894                         outcolor += 4;
3895                 }
3896         }
3897         else if (vcolor4ub)
3898         {
3899                 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3900                 // this unaligned memory access is safe (all bytes)
3901                 for (i = 0;i < (int)header.num_vertexes;i++)
3902                 {
3903                         outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3904                         outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3905                         outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3906                         outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3907                         vcolor4ub += 4;
3908                         outcolor += 4;
3909                 }
3910         }
3911
3912         // load meshes
3913         for (i = 0;i < (int)header.num_meshes;i++)
3914         {
3915                 iqmmesh_t mesh;
3916                 msurface_t *surface;
3917
3918                 mesh.name = LittleLong(meshes[i].name);
3919                 mesh.material = LittleLong(meshes[i].material);
3920                 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3921                 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3922                 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3923                 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3924
3925                 loadmodel->sortedmodelsurfaces[i] = i;
3926                 surface = loadmodel->data_surfaces + i;
3927                 surface->texture = loadmodel->data_textures + i;
3928                 surface->num_firsttriangle = mesh.first_triangle;
3929                 surface->num_triangles = mesh.num_triangles;
3930                 surface->num_firstvertex = mesh.first_vertex;
3931                 surface->num_vertices = mesh.num_vertexes;
3932
3933                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3934         }
3935
3936         Mod_FreeSkinFiles(skinfiles);
3937         Mod_MakeSortedSurfaces(loadmodel);
3938
3939         // compute all the mesh information that was not loaded from the file
3940         if (!vnormal)
3941                 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);
3942         if (!vnormal || !vtangent)
3943                 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);
3944         if (!header.ofs_bounds)
3945                 Mod_Alias_CalculateBoundingBox();
3946
3947         // Always make a BIH for the first frame, we can use it where possible.
3948         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3949         if (!loadmodel->surfmesh.isanimated)
3950         {
3951                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3952                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3953                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3954                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3955                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3956         }
3957
3958         if (joint        ) Mem_Free(joint        );joint         = NULL;
3959         if (joint1       ) Mem_Free(joint1       );joint1        = NULL;
3960         if (pose         ) Mem_Free(pose         );pose          = NULL;
3961         if (pose1        ) Mem_Free(pose1        );pose1         = NULL;
3962
3963         // because shaders can do somewhat unexpected things, check for unusual features now
3964         for (i = 0;i < loadmodel->num_textures;i++)
3965         {
3966                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3967                         mod->DrawSky = R_Q1BSP_DrawSky;
3968                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3969                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3970         }
3971 }