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