]> git.xonotic.org Git - xonotic/darkplaces.git/blob - model_alias.c
1dda79708f71d46f6d3eadcb6baa66daa7e3a00d
[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 lheader, *header = &lheader;
2975         skinfile_t *skinfiles;
2976         int i, j, k, meshvertices, meshtriangles;
2977         float biggestorigin;
2978         const int *inelements;
2979         int *outelements;
2980         float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector;
2981         // temporary memory allocations (because the data in the file may be misaligned)
2982         float *vnormal = NULL;
2983         float *vposition = NULL;
2984         float *vtangent = NULL;
2985         float *vtexcoord = NULL;
2986         iqmanim_t *anim = NULL;
2987         iqmbounds_t *bounds = NULL;
2988         iqmjoint1_t *joint1 = NULL;
2989         iqmjoint_t *joint = NULL;
2990         iqmmesh_t *mesh = NULL;
2991         iqmpose1_t *pose1 = NULL;
2992         iqmpose_t *pose = NULL;
2993         iqmvertexarray_t *va = NULL;
2994         unsigned char *vblendindexes = NULL;
2995         unsigned char *vblendweights = NULL;
2996         unsigned short *framedata = NULL;
2997
2998         pbase = (unsigned char *)buffer;
2999         pend = (unsigned char *)bufferend;
3000
3001         if (buffer + sizeof(iqmheader_t) > bufferend)
3002                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3003
3004         // copy struct (otherwise it may be misaligned)
3005         // LordHavoc: okay it's definitely not misaligned here, but for consistency...
3006         memcpy(header, pbase, sizeof(header));
3007
3008         if (memcmp(header->id, "INTERQUAKEMODEL", 16))
3009                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3010         if (LittleLong(header->version) != 1 && LittleLong(header->version) != 2)
3011                 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3012
3013         loadmodel->modeldatatypestring = "IQM";
3014
3015         loadmodel->type = mod_alias;
3016         loadmodel->synctype = ST_RAND;
3017
3018         // byteswap header
3019         header->version = LittleLong(header->version);
3020         header->filesize = LittleLong(header->filesize);
3021         header->flags = LittleLong(header->flags);
3022         header->num_text = LittleLong(header->num_text);
3023         header->ofs_text = LittleLong(header->ofs_text);
3024         header->num_meshes = LittleLong(header->num_meshes);
3025         header->ofs_meshes = LittleLong(header->ofs_meshes);
3026         header->num_vertexarrays = LittleLong(header->num_vertexarrays);
3027         header->num_vertexes = LittleLong(header->num_vertexes);
3028         header->ofs_vertexarrays = LittleLong(header->ofs_vertexarrays);
3029         header->num_triangles = LittleLong(header->num_triangles);
3030         header->ofs_triangles = LittleLong(header->ofs_triangles);
3031         header->ofs_neighbors = LittleLong(header->ofs_neighbors);
3032         header->num_joints = LittleLong(header->num_joints);
3033         header->ofs_joints = LittleLong(header->ofs_joints);
3034         header->num_poses = LittleLong(header->num_poses);
3035         header->ofs_poses = LittleLong(header->ofs_poses);
3036         header->num_anims = LittleLong(header->num_anims);
3037         header->ofs_anims = LittleLong(header->ofs_anims);
3038         header->num_frames = LittleLong(header->num_frames);
3039         header->num_framechannels = LittleLong(header->num_framechannels);
3040         header->ofs_frames = LittleLong(header->ofs_frames);
3041         header->ofs_bounds = LittleLong(header->ofs_bounds);
3042         header->num_comment = LittleLong(header->num_comment);
3043         header->ofs_comment = LittleLong(header->ofs_comment);
3044         header->num_extensions = LittleLong(header->num_extensions);
3045         header->ofs_extensions = LittleLong(header->ofs_extensions);
3046
3047         if (header->num_triangles < 1 || header->num_vertexes < 3 || header->num_vertexarrays < 1 || header->num_meshes < 1)
3048         {
3049                 Con_Printf("%s has no geometry\n", loadmodel->name);
3050                 return;
3051         }
3052
3053         if (header->version == 1)
3054         {
3055                 if (pbase + header->ofs_joints + header->num_joints*sizeof(iqmjoint1_t) > pend ||
3056                         pbase + header->ofs_poses + header->num_poses*sizeof(iqmpose1_t) > pend)
3057                 {
3058                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3059                         return;
3060                 }
3061         }
3062         else
3063         {
3064                 if (pbase + header->ofs_joints + header->num_joints*sizeof(iqmjoint_t) > pend ||
3065                         pbase + header->ofs_poses + header->num_poses*sizeof(iqmpose_t) > pend)
3066                 {
3067                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3068                         return;
3069                 }
3070         }
3071         if (pbase + header->ofs_text + header->num_text > pend ||
3072                 pbase + header->ofs_meshes + header->num_meshes*sizeof(iqmmesh_t) > pend ||
3073                 pbase + header->ofs_vertexarrays + header->num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3074                 pbase + header->ofs_triangles + header->num_triangles*sizeof(int[3]) > pend ||
3075                 (header->ofs_neighbors && pbase + header->ofs_neighbors + header->num_triangles*sizeof(int[3]) > pend) ||
3076                 pbase + header->ofs_anims + header->num_anims*sizeof(iqmanim_t) > pend ||
3077                 pbase + header->ofs_frames + header->num_frames*header->num_framechannels*sizeof(unsigned short) > pend ||
3078                 (header->ofs_bounds && pbase + header->ofs_bounds + header->num_frames*sizeof(iqmbounds_t) > pend) ||
3079                 pbase + header->ofs_comment + header->num_comment > pend)
3080         {
3081                 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3082                 return;
3083         }
3084
3085         // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3086         if (header->num_vertexarrays)
3087         {
3088                 va = (iqmvertexarray_t *)Mem_Alloc(loadmodel->mempool, header->num_vertexarrays * sizeof(iqmvertexarray_t));
3089                 memcpy(va, pbase + header->ofs_vertexarrays, header->num_vertexarrays * sizeof(iqmvertexarray_t));
3090         }
3091         if (header->version == 1)
3092         {
3093                 if (loadmodel->num_bones)
3094                 {
3095                         joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3096                         memcpy(joint1, pbase + header->ofs_joints, loadmodel->num_bones * sizeof(iqmjoint1_t));
3097                 }
3098                 if (header->num_poses)
3099                 {
3100                         pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header->num_poses * sizeof(iqmpose1_t));
3101                         memcpy(pose1, pbase + header->ofs_poses, header->num_poses * sizeof(iqmpose1_t));
3102                 }
3103         }
3104         else
3105         {
3106                 if (loadmodel->num_bones)
3107                 {
3108                         joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3109                         memcpy(joint, pbase + header->ofs_joints, loadmodel->num_bones * sizeof(iqmjoint_t));
3110                 }
3111                 if (header->num_poses)
3112                 {
3113                         pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header->num_poses * sizeof(iqmpose_t));
3114                         memcpy(pose, pbase + header->ofs_poses, header->num_poses * sizeof(iqmpose_t));
3115                 }
3116         }
3117         if (header->num_anims)
3118         {
3119                 anim = (iqmanim_t *)Mem_Alloc(loadmodel->mempool, header->num_anims * sizeof(iqmanim_t));
3120                 memcpy(anim, pbase + header->ofs_anims, header->num_anims * sizeof(iqmanim_t));
3121         }
3122         if (header->num_framechannels)
3123         {
3124                 framedata = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short) * header->num_framechannels);
3125                 memcpy(framedata, pbase + header->ofs_frames, sizeof(unsigned short) * header->num_framechannels);
3126         }
3127         if (header->ofs_bounds)
3128         {
3129                 bounds = (iqmbounds_t *)Mem_Alloc(loadmodel->mempool, header->num_frames*sizeof(iqmbounds_t));
3130                 memcpy(bounds, pbase + header->ofs_bounds, header->num_frames*sizeof(iqmbounds_t));
3131         }
3132         if (header->num_triangles)
3133                 memcpy(loadmodel->surfmesh.data_element3i, pbase + header->ofs_triangles, sizeof(unsigned int[3]) * header->num_triangles);
3134         if (header->ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
3135                 memcpy(loadmodel->surfmesh.data_neighbor3i, pbase + header->ofs_neighbors, sizeof(int[3]) * header->num_triangles);
3136         if (header->num_meshes)
3137         {
3138                 mesh = Mem_Alloc(loadmodel->mempool, header->num_meshes * sizeof(iqmmesh_t));
3139                 memcpy(mesh, pbase + header->ofs_meshes, header->num_meshes * sizeof(iqmmesh_t));
3140         }
3141
3142         for (i = 0;i < (int)header->num_vertexarrays;i++)
3143         {
3144                 size_t vsize;
3145                 va[i].type = LittleLong(va[i].type);
3146                 va[i].flags = LittleLong(va[i].flags);
3147                 va[i].format = LittleLong(va[i].format);
3148                 va[i].size = LittleLong(va[i].size);
3149                 va[i].offset = LittleLong(va[i].offset);
3150                 vsize = header->num_vertexes*va[i].size;
3151                 switch (va[i].format)
3152                 { 
3153                 case IQM_FLOAT: vsize *= sizeof(float); break;
3154                 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3155                 default: continue;
3156                 }
3157                 if (pbase + va[i].offset + vsize > pend)
3158                   continue;
3159                 switch (va[i].type)
3160                 {
3161                 case IQM_POSITION:
3162                         if (va[i].format == IQM_FLOAT && va[i].size == 3)
3163                         {
3164                                 vposition = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * header->num_vertexes);
3165                                 memcpy(vposition, pbase + va[i].offset, sizeof(float[3]) * header->num_vertexes);
3166                         }
3167                         break;
3168                 case IQM_TEXCOORD:
3169                         if (va[i].format == IQM_FLOAT && va[i].size == 2)
3170                         {
3171                                 vtexcoord = Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * header->num_vertexes);
3172                                 memcpy(vtexcoord, pbase + va[i].offset, sizeof(float[2]) * header->num_vertexes);
3173                         }
3174                         break;
3175                 case IQM_NORMAL:
3176                         if (va[i].format == IQM_FLOAT && va[i].size == 3)
3177                         {
3178                                 vnormal = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * header->num_vertexes);
3179                                 memcpy(vnormal, pbase + va[i].offset, sizeof(float[3]) * header->num_vertexes);
3180                         }
3181                         break;
3182                 case IQM_TANGENT:
3183                         if (va[i].format == IQM_FLOAT && va[i].size == 4)
3184                         {
3185                                 vtangent = Mem_Alloc(loadmodel->mempool, sizeof(float[4]) * header->num_vertexes);
3186                                 memcpy(vtangent, pbase + va[i].offset, sizeof(float[4]) * header->num_vertexes);
3187                         }
3188                         break;
3189                 case IQM_BLENDINDEXES:
3190                         if (va[i].format == IQM_UBYTE && va[i].size == 4)
3191                         {
3192                                 vblendindexes = Mem_Alloc(loadmodel->mempool, sizeof(unsigned char[4]) * header->num_vertexes);
3193                                 memcpy(vblendindexes, pbase + va[i].offset, sizeof(unsigned char[4]) * header->num_vertexes);
3194                         }
3195                         break;
3196                 case IQM_BLENDWEIGHTS:
3197                         if (va[i].format == IQM_UBYTE && va[i].size == 4)
3198                         {
3199                                 vblendweights = Mem_Alloc(loadmodel->mempool, sizeof(unsigned char[4]) * header->num_vertexes);
3200                                 memcpy(vblendweights, pbase + va[i].offset, sizeof(unsigned char[4]) * header->num_vertexes);
3201                         }
3202                         break;
3203                 }
3204         }
3205         if (header->num_vertexes > 0 && (!vposition || !vtexcoord || ((header->num_frames > 0 || header->num_anims > 0) && (!vblendindexes || !vblendweights))))
3206         {
3207                 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3208                 return;
3209         }
3210
3211         text = header->num_text && header->ofs_text ? (const char *)(pbase + header->ofs_text) : "";
3212
3213         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3214         loadmodel->DrawSky = NULL;
3215         loadmodel->DrawAddWaterPlanes = NULL;
3216         loadmodel->Draw = R_Q1BSP_Draw;
3217         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
3218         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
3219         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
3220         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
3221         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
3222         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
3223         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
3224         loadmodel->DrawLight = R_Q1BSP_DrawLight;
3225         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3226         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3227         loadmodel->PointSuperContents = NULL;
3228
3229         // load external .skin files if present
3230         skinfiles = Mod_LoadSkinFiles();
3231         if (loadmodel->numskins < 1)
3232                 loadmodel->numskins = 1;
3233
3234         loadmodel->numframes = max(header->num_anims, 1);
3235         loadmodel->num_bones = header->num_joints;
3236         loadmodel->num_poses = max(header->num_frames, 1);
3237         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header->num_meshes;
3238         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3239         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3240
3241         meshvertices = header->num_vertexes;
3242         meshtriangles = header->num_triangles;
3243
3244         // do most allocations as one merged chunk
3245         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));
3246         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3247         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3248         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3249         loadmodel->surfmesh.num_vertices = meshvertices;
3250         loadmodel->surfmesh.num_triangles = meshtriangles;
3251         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3252         if (r_enableshadowvolumes.integer)
3253         {
3254                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3255         }
3256         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3257         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3258         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3259         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3260         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3261         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3262         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3263         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3264         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3265         if (vblendindexes && vblendweights)
3266         {
3267                 loadmodel->surfmesh.num_blends = 0;
3268                 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3269         }
3270         if (meshvertices <= 65536)
3271         {
3272                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3273         }
3274         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
3275         if (vblendindexes && vblendweights)
3276                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3277
3278         for (i = 0;i < loadmodel->numskins;i++)
3279         {
3280                 loadmodel->skinscenes[i].firstframe = i;
3281                 loadmodel->skinscenes[i].framecount = 1;
3282                 loadmodel->skinscenes[i].loop = true;
3283                 loadmodel->skinscenes[i].framerate = 10;
3284         }
3285
3286         // load the bone info
3287         if (header->version == 1)
3288         {
3289                 for (i = 0;i < loadmodel->num_bones;i++)
3290                 {
3291                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3292                         joint1[i].name = LittleLong(joint1[i].name);
3293                         joint1[i].parent = LittleLong(joint1[i].parent);
3294                         for (j = 0;j < 3;j++)
3295                         {
3296                                 joint1[i].origin[j] = LittleFloat(joint1[i].origin[j]);
3297                                 joint1[i].rotation[j] = LittleFloat(joint1[i].rotation[j]);
3298                                 joint1[i].scale[j] = LittleFloat(joint1[i].scale[j]);
3299                         }
3300                         strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3301                         loadmodel->data_bones[i].parent = joint1[i].parent;
3302                         if (loadmodel->data_bones[i].parent >= i)
3303                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3304                         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]);
3305                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3306                         if (loadmodel->data_bones[i].parent >= 0)
3307                         {
3308                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3309                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3310                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3311                         }
3312                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3313                 }
3314         }
3315         else
3316         {
3317                 for (i = 0;i < loadmodel->num_bones;i++)
3318                 {
3319                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3320                         joint[i].name = LittleLong(joint[i].name);
3321                         joint[i].parent = LittleLong(joint[i].parent);
3322                         for (j = 0;j < 3;j++)
3323                         {
3324                                 joint[i].origin[j] = LittleFloat(joint[i].origin[j]);
3325                                 joint[i].rotation[j] = LittleFloat(joint[i].rotation[j]);
3326                                 joint[i].scale[j] = LittleFloat(joint[i].scale[j]);
3327                         }
3328                         joint[i].rotation[3] = LittleFloat(joint[i].rotation[3]);
3329                         strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3330                         loadmodel->data_bones[i].parent = joint[i].parent;
3331                         if (loadmodel->data_bones[i].parent >= i)
3332                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3333                         if (joint[i].rotation[3] > 0)
3334                                 Vector4Negate(joint[i].rotation, joint[i].rotation);
3335                         Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3336                         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]);
3337                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3338                         if (loadmodel->data_bones[i].parent >= 0)
3339                         {
3340                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3341                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3342                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3343                         }       
3344                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3345                 }
3346         }
3347
3348         // set up the animscenes based on the anims
3349         for (i = 0;i < (int)header->num_anims;i++)
3350         {
3351                 anim[i].name = LittleLong(anim[i].name);
3352                 anim[i].first_frame = LittleLong(anim[i].first_frame);
3353                 anim[i].num_frames = LittleLong(anim[i].num_frames);
3354                 anim[i].framerate = LittleFloat(anim[i].framerate);
3355                 anim[i].flags = LittleLong(anim[i].flags);
3356                 strlcpy(loadmodel->animscenes[i].name, &text[anim[i].name], sizeof(loadmodel->animscenes[i].name));
3357                 loadmodel->animscenes[i].firstframe = anim[i].first_frame;
3358                 loadmodel->animscenes[i].framecount = anim[i].num_frames;
3359                 loadmodel->animscenes[i].loop = ((anim[i].flags & IQM_LOOP) != 0);
3360                 loadmodel->animscenes[i].framerate = anim[i].framerate;
3361         }
3362         if (header->num_anims <= 0)
3363         {
3364                 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3365                 loadmodel->animscenes[0].firstframe = 0;
3366                 loadmodel->animscenes[0].framecount = 1;
3367                 loadmodel->animscenes[0].loop = true;
3368                 loadmodel->animscenes[0].framerate = 10;
3369         }
3370
3371         biggestorigin = 0;
3372         if (header->version == 1)
3373         {
3374                 for (i = 0;i < (int)header->num_poses;i++)
3375                 {
3376                         float f;
3377                         pose1[i].parent = LittleLong(pose1[i].parent);
3378                         pose1[i].channelmask = LittleLong(pose1[i].channelmask);
3379                         for (j = 0;j < 9;j++)
3380                         {
3381                                 pose1[i].channeloffset[j] = LittleFloat(pose1[i].channeloffset[j]);
3382                                 pose1[i].channelscale[j] = LittleFloat(pose1[i].channelscale[j]);
3383                         }
3384                         f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3385                         f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3386                         f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3387                         f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3388                         f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3389                         f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3390                 }
3391                 if (header->num_frames <= 0)
3392                 {
3393                         for (i = 0;i < loadmodel->num_bones;i++)
3394                         {
3395                                 float f;
3396                                 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3397                                 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3398                                 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3399                         }
3400                 }
3401         }
3402         else
3403         {
3404                 for (i = 0;i < (int)header->num_poses;i++)
3405                 {
3406                         float f;
3407                         pose[i].parent = LittleLong(pose[i].parent);
3408                         pose[i].channelmask = LittleLong(pose[i].channelmask);
3409                         for (j = 0;j < 10;j++)
3410                         {
3411                                 pose[i].channeloffset[j] = LittleFloat(pose[i].channeloffset[j]);
3412                                 pose[i].channelscale[j] = LittleFloat(pose[i].channelscale[j]);
3413                         }
3414                         f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3415                         f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3416                         f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3417                         f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3418                         f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3419                         f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3420                 }
3421                 if (header->num_frames <= 0)
3422                 {
3423                         for (i = 0;i < loadmodel->num_bones;i++)
3424                         {
3425                                 float f;
3426                                 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3427                                 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3428                                 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3429                         }
3430                 }
3431         }
3432         loadmodel->num_posescale = biggestorigin / 32767.0f;
3433         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3434
3435         // load the pose data
3436         if (header->version == 1)
3437         {
3438                 for (i = 0, k = 0;i < (int)header->num_frames;i++)
3439                 {
3440                         for (j = 0;j < (int)header->num_poses;j++, k++)
3441                         {
3442                                 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));
3443                                 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));
3444                                 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));
3445                                 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));
3446                                 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));
3447                                 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));
3448                                 // skip scale data for now
3449                                 if(pose1[j].channelmask&64) framedata++;
3450                                 if(pose1[j].channelmask&128) framedata++;
3451                                 if(pose1[j].channelmask&256) framedata++;
3452                         }
3453                 }
3454                 if (header->num_frames <= 0)
3455                 {
3456                         for (i = 0;i < loadmodel->num_bones;i++)
3457                         {
3458                                 loadmodel->data_poses6s[i*6 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3459                                 loadmodel->data_poses6s[i*6 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3460                                 loadmodel->data_poses6s[i*6 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3461                                 loadmodel->data_poses6s[i*6 + 3] = 32767.0f * joint1[i].rotation[0];
3462                                 loadmodel->data_poses6s[i*6 + 4] = 32767.0f * joint1[i].rotation[1];
3463                                 loadmodel->data_poses6s[i*6 + 5] = 32767.0f * joint1[i].rotation[2];
3464                         }
3465                 }
3466         }
3467         else
3468         {
3469                 for (i = 0, k = 0;i < (int)header->num_frames;i++)      
3470                 {
3471                         for (j = 0;j < (int)header->num_poses;j++, k++)
3472                         {
3473                                 float rot[4];
3474                                 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));
3475                                 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));
3476                                 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));
3477                                 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3478                                 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3479                                 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3480                                 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3481                                 if (rot[3] > 0)
3482                                         Vector4Negate(rot, rot);
3483                                 Vector4Normalize2(rot, rot);
3484                                 loadmodel->data_poses6s[k*6 + 3] = 32767.0f * rot[0];
3485                                 loadmodel->data_poses6s[k*6 + 4] = 32767.0f * rot[1];
3486                                 loadmodel->data_poses6s[k*6 + 5] = 32767.0f * rot[2];
3487                                 // skip scale data for now
3488                                 if(pose[j].channelmask&128) framedata++;
3489                                 if(pose[j].channelmask&256) framedata++;
3490                                 if(pose[j].channelmask&512) framedata++;
3491                         }
3492                 }
3493                 if (header->num_frames <= 0)
3494                 {
3495                         for (i = 0;i < loadmodel->num_bones;i++)
3496                         {
3497                                 loadmodel->data_poses6s[i*6 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3498                                 loadmodel->data_poses6s[i*6 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3499                                 loadmodel->data_poses6s[i*6 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3500                                 loadmodel->data_poses6s[i*6 + 3] = 32767.0f * joint[i].rotation[0];
3501                                 loadmodel->data_poses6s[i*6 + 4] = 32767.0f * joint[i].rotation[1];
3502                                 loadmodel->data_poses6s[i*6 + 5] = 32767.0f * joint[i].rotation[2];
3503                         }
3504                 }
3505         }
3506
3507         // load bounding box data
3508         if (header->ofs_bounds)
3509         {
3510                 float xyradius = 0, radius = 0;
3511                 VectorClear(loadmodel->normalmins);
3512                 VectorClear(loadmodel->normalmaxs);
3513                 for (i = 0; i < (int)header->num_frames;i++)
3514                 {
3515                         bounds[i].mins[0] = LittleFloat(bounds[i].mins[0]);
3516                         bounds[i].mins[1] = LittleFloat(bounds[i].mins[1]);
3517                         bounds[i].mins[2] = LittleFloat(bounds[i].mins[2]);
3518                         bounds[i].maxs[0] = LittleFloat(bounds[i].maxs[0]);                     
3519                         bounds[i].maxs[1] = LittleFloat(bounds[i].maxs[1]);     
3520                         bounds[i].maxs[2] = LittleFloat(bounds[i].maxs[2]);     
3521                         bounds[i].xyradius = LittleFloat(bounds[i].xyradius);
3522                         bounds[i].radius = LittleFloat(bounds[i].radius);
3523                         if (!i)
3524                         {
3525                                 VectorCopy(bounds[i].mins, loadmodel->normalmins);
3526                                 VectorCopy(bounds[i].maxs, loadmodel->normalmaxs);
3527                         }
3528                         else
3529                         {
3530                                 if (loadmodel->normalmins[0] > bounds[i].mins[0]) loadmodel->normalmins[0] = bounds[i].mins[0];
3531                                 if (loadmodel->normalmins[1] > bounds[i].mins[1]) loadmodel->normalmins[1] = bounds[i].mins[1];
3532                                 if (loadmodel->normalmins[2] > bounds[i].mins[2]) loadmodel->normalmins[2] = bounds[i].mins[2];
3533                                 if (loadmodel->normalmaxs[0] < bounds[i].maxs[0]) loadmodel->normalmaxs[0] = bounds[i].maxs[0];
3534                                 if (loadmodel->normalmaxs[1] < bounds[i].maxs[1]) loadmodel->normalmaxs[1] = bounds[i].maxs[1];
3535                                 if (loadmodel->normalmaxs[2] < bounds[i].maxs[2]) loadmodel->normalmaxs[2] = bounds[i].maxs[2];
3536                         }
3537                         if (bounds[i].xyradius > xyradius)
3538                                 xyradius = bounds[i].xyradius;
3539                         if (bounds[i].radius > radius)
3540                                 radius = bounds[i].radius;
3541                 }
3542                 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3543                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3544                 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3545                 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3546                 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3547                 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3548                 loadmodel->radius = radius;
3549                 loadmodel->radius2 = radius * radius;
3550         }
3551
3552         // load triangle data
3553         inelements = loadmodel->surfmesh.data_element3i;
3554         outelements = loadmodel->surfmesh.data_element3i;
3555         for (i = 0;i < (int)header->num_triangles;i++)
3556         {
3557                 outelements[0] = LittleLong(inelements[0]);
3558                 outelements[1] = LittleLong(inelements[1]);
3559                 outelements[2] = LittleLong(inelements[2]);
3560                 outelements += 3;
3561                 inelements += 3;
3562         }
3563         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, header->num_vertexes, __FILE__, __LINE__);
3564
3565         if (header->ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
3566         {
3567                 inelements = loadmodel->surfmesh.data_neighbor3i;
3568                 outelements = loadmodel->surfmesh.data_neighbor3i;
3569                 for (i = 0;i < (int)header->num_triangles;i++)
3570                 {
3571                         outelements[0] = LittleLong(inelements[0]);
3572                         outelements[1] = LittleLong(inelements[1]);
3573                         outelements[2] = LittleLong(inelements[2]);
3574                         outelements += 3;
3575                         inelements += 3;
3576                 }
3577         }
3578
3579         // load vertex data
3580         outvertex = loadmodel->surfmesh.data_vertex3f;
3581         for (i = 0;i < (int)header->num_vertexes;i++)
3582         {
3583                 outvertex[0] = LittleFloat(vposition[0]);
3584                 outvertex[1] = LittleFloat(vposition[1]);
3585                 outvertex[2] = LittleFloat(vposition[2]);
3586                 vposition += 3;
3587                 outvertex += 3;
3588         }
3589
3590         outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3591         for (i = 0;i < (int)header->num_vertexes;i++)
3592         {
3593                 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3594                 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3595                 vtexcoord += 2;
3596                 outtexcoord += 2;
3597         }
3598
3599         if(vnormal)
3600         {
3601                 outnormal = loadmodel->surfmesh.data_normal3f;
3602                 for (i = 0;i < (int)header->num_vertexes;i++)
3603                 {
3604                         outnormal[0] = LittleFloat(vnormal[0]);
3605                         outnormal[1] = LittleFloat(vnormal[1]);
3606                         outnormal[2] = LittleFloat(vnormal[2]);
3607                         vnormal += 3;
3608                         outnormal += 3;
3609                 }
3610         }
3611
3612         if(vnormal && vtangent)
3613         {
3614                 outnormal = loadmodel->surfmesh.data_normal3f;
3615                 outsvector = loadmodel->surfmesh.data_svector3f;
3616                 outtvector = loadmodel->surfmesh.data_tvector3f;
3617                 for (i = 0;i < (int)header->num_vertexes;i++)
3618                 {
3619                         outsvector[0] = LittleFloat(vtangent[0]);
3620                         outsvector[1] = LittleFloat(vtangent[1]);
3621                         outsvector[2] = LittleFloat(vtangent[2]);
3622                         if(LittleFloat(vtangent[3]) < 0)
3623                                 CrossProduct(outsvector, outnormal, outtvector);
3624                         else
3625                                 CrossProduct(outnormal, outsvector, outtvector);
3626                         vtangent += 4;
3627                         outnormal += 3;
3628                         outsvector += 3;
3629                         outtvector += 3;
3630                 }
3631         }
3632
3633         if (vblendindexes && vblendweights)
3634         {
3635                 for (i = 0; i < (int)header->num_vertexes;i++)
3636                 {
3637                         blendweights_t weights;
3638                         memcpy(weights.index, vblendindexes + i*4, 4);
3639                         memcpy(weights.influence, vblendweights + i*4, 4);
3640                         loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3641                 }
3642         }
3643
3644         // load meshes
3645         for (i = 0;i < (int)header->num_meshes;i++)
3646         {
3647                 msurface_t *surface;
3648
3649                 mesh[i].name = LittleLong(mesh[i].name);
3650                 mesh[i].material = LittleLong(mesh[i].material);
3651                 mesh[i].first_vertex = LittleLong(mesh[i].first_vertex);
3652                 mesh[i].num_vertexes = LittleLong(mesh[i].num_vertexes);
3653                 mesh[i].first_triangle = LittleLong(mesh[i].first_triangle);
3654                 mesh[i].num_triangles = LittleLong(mesh[i].num_triangles);
3655
3656                 loadmodel->sortedmodelsurfaces[i] = i;
3657                 surface = loadmodel->data_surfaces + i;
3658                 surface->texture = loadmodel->data_textures + i;
3659                 surface->num_firsttriangle = mesh[i].first_triangle;
3660                 surface->num_triangles = mesh[i].num_triangles;
3661                 surface->num_firstvertex = mesh[i].first_vertex;
3662                 surface->num_vertices = mesh[i].num_vertexes;
3663
3664                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh[i].name], &text[mesh[i].material]);
3665         }
3666
3667         Mod_FreeSkinFiles(skinfiles);
3668         Mod_MakeSortedSurfaces(loadmodel);
3669
3670         // compute all the mesh information that was not loaded from the file
3671         if (loadmodel->surfmesh.data_element3s)
3672                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3673                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3674         if (!vnormal)
3675                 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);
3676         if (!vnormal || !vtangent)
3677                 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);
3678         if (!header->ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
3679                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
3680         if (!header->ofs_bounds)
3681                 Mod_Alias_CalculateBoundingBox();
3682
3683         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
3684
3685         if (!loadmodel->surfmesh.isanimated)
3686         {
3687                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3688                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3689                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3690                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3691                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3692                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3693         }
3694
3695         if (anim         ) Mem_Free(anim         );anim          = NULL;
3696         if (bounds       ) Mem_Free(bounds       );bounds        = NULL;
3697         if (framedata    ) Mem_Free(framedata    );framedata     = NULL;
3698         if (joint        ) Mem_Free(joint        );joint         = NULL;
3699         if (joint1       ) Mem_Free(joint1       );joint1        = NULL;
3700         if (mesh         ) Mem_Free(mesh         );mesh          = NULL;
3701         if (pose         ) Mem_Free(pose         );pose          = NULL;
3702         if (pose1        ) Mem_Free(pose1        );pose1         = NULL;
3703         if (va           ) Mem_Free(va           );va            = NULL;
3704         if (vblendindexes) Mem_Free(vblendindexes);vblendindexes = NULL;
3705         if (vblendweights) Mem_Free(vblendweights);vblendweights = NULL;
3706         if (vnormal      ) Mem_Free(vnormal      );vnormal       = NULL;
3707         if (vposition    ) Mem_Free(vposition    );vposition     = NULL;
3708         if (vtangent     ) Mem_Free(vtangent     );vtangent      = NULL;
3709         if (vtexcoord    ) Mem_Free(vtexcoord    );vtexcoord     = NULL;
3710 }