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