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