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