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