fix a small bug regarding bobfall
[divverent/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 equivilant 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 (skinfile)
855         {
856                 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
857                 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
858                 {
859                         memset(skin, 0, sizeof(*skin));
860                         // see if a mesh
861                         for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
862                         {
863                                 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
864                                 if (!strcmp(skinfileitem->name, meshname))
865                                 {
866                                         Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
867                                         Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
868                                         break;
869                                 }
870                         }
871                         if (!skinfileitem)
872                         {
873                                 // don't render unmentioned meshes
874                                 Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
875                                 skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
876                         }
877                 }
878         }
879         else
880         {
881                 Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
882                 Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
883         }
884 }
885
886 #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);
887 #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);
888 void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
889 {
890         int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
891         float scales, scalet, interval;
892         msurface_t *surface;
893         unsigned char *data;
894         mdl_t *pinmodel;
895         stvert_t *pinstverts;
896         dtriangle_t *pintriangles;
897         daliasskintype_t *pinskintype;
898         daliasskingroup_t *pinskingroup;
899         daliasskininterval_t *pinskinintervals;
900         daliasframetype_t *pinframetype;
901         daliasgroup_t *pinframegroup;
902         unsigned char *datapointer, *startframes, *startskins;
903         char name[MAX_QPATH];
904         skinframe_t *tempskinframe;
905         animscene_t *tempskinscenes;
906         texture_t *tempaliasskins;
907         float *vertst;
908         int *vertonseam, *vertremap;
909         skinfile_t *skinfiles;
910
911         datapointer = (unsigned char *)buffer;
912         pinmodel = (mdl_t *)datapointer;
913         datapointer += sizeof(mdl_t);
914
915         version = LittleLong (pinmodel->version);
916         if (version != ALIAS_VERSION)
917                 Host_Error ("%s has wrong version number (%i should be %i)",
918                                  loadmodel->name, version, ALIAS_VERSION);
919
920         loadmodel->modeldatatypestring = "MDL";
921
922         loadmodel->type = mod_alias;
923         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
924         loadmodel->DrawSky = NULL;
925         loadmodel->DrawAddWaterPlanes = NULL;
926         loadmodel->Draw = R_Q1BSP_Draw;
927         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
928         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
929         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
930         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
931         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
932         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
933         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
934         loadmodel->DrawLight = R_Q1BSP_DrawLight;
935         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
936         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
937         // FIXME add TraceBrush!
938         loadmodel->PointSuperContents = NULL;
939
940         loadmodel->num_surfaces = 1;
941         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
942         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
943         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
944         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
945         loadmodel->sortedmodelsurfaces[0] = 0;
946
947         loadmodel->numskins = LittleLong(pinmodel->numskins);
948         BOUNDI(loadmodel->numskins,0,65536);
949         skinwidth = LittleLong (pinmodel->skinwidth);
950         BOUNDI(skinwidth,0,65536);
951         skinheight = LittleLong (pinmodel->skinheight);
952         BOUNDI(skinheight,0,65536);
953         numverts = LittleLong(pinmodel->numverts);
954         BOUNDI(numverts,0,65536);
955         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
956         BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
957         loadmodel->numframes = LittleLong(pinmodel->numframes);
958         BOUNDI(loadmodel->numframes,0,65536);
959         loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
960         BOUNDI((int)loadmodel->synctype,0,2);
961         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
962         i = LittleLong (pinmodel->flags);
963         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
964
965         for (i = 0;i < 3;i++)
966         {
967                 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
968                 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
969         }
970
971         startskins = datapointer;
972         totalskins = 0;
973         for (i = 0;i < loadmodel->numskins;i++)
974         {
975                 pinskintype = (daliasskintype_t *)datapointer;
976                 datapointer += sizeof(daliasskintype_t);
977                 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
978                         groupskins = 1;
979                 else
980                 {
981                         pinskingroup = (daliasskingroup_t *)datapointer;
982                         datapointer += sizeof(daliasskingroup_t);
983                         groupskins = LittleLong(pinskingroup->numskins);
984                         datapointer += sizeof(daliasskininterval_t) * groupskins;
985                 }
986
987                 for (j = 0;j < groupskins;j++)
988                 {
989                         datapointer += skinwidth * skinheight;
990                         totalskins++;
991                 }
992         }
993
994         pinstverts = (stvert_t *)datapointer;
995         datapointer += sizeof(stvert_t) * numverts;
996
997         pintriangles = (dtriangle_t *)datapointer;
998         datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
999
1000         startframes = datapointer;
1001         loadmodel->surfmesh.num_morphframes = 0;
1002         for (i = 0;i < loadmodel->numframes;i++)
1003         {
1004                 pinframetype = (daliasframetype_t *)datapointer;
1005                 datapointer += sizeof(daliasframetype_t);
1006                 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1007                         groupframes = 1;
1008                 else
1009                 {
1010                         pinframegroup = (daliasgroup_t *)datapointer;
1011                         datapointer += sizeof(daliasgroup_t);
1012                         groupframes = LittleLong(pinframegroup->numframes);
1013                         datapointer += sizeof(daliasinterval_t) * groupframes;
1014                 }
1015
1016                 for (j = 0;j < groupframes;j++)
1017                 {
1018                         datapointer += sizeof(daliasframe_t);
1019                         datapointer += sizeof(trivertx_t) * numverts;
1020                         loadmodel->surfmesh.num_morphframes++;
1021                 }
1022         }
1023         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1024
1025         // store texture coordinates into temporary array, they will be stored
1026         // after usage is determined (triangle data)
1027         vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1028         vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1029         vertonseam = vertremap + numverts * 2;
1030
1031         scales = 1.0 / skinwidth;
1032         scalet = 1.0 / skinheight;
1033         for (i = 0;i < numverts;i++)
1034         {
1035                 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1036                 vertst[i*2+0] = (LittleLong(pinstverts[i].s) + 0.5) * scales;
1037                 vertst[i*2+1] = (LittleLong(pinstverts[i].t) + 0.5) * scalet;
1038                 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1039                 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1040         }
1041
1042 // load triangle data
1043         loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1044
1045         // read the triangle elements
1046         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1047                 for (j = 0;j < 3;j++)
1048                         loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1049         // validate (note numverts is used because this is the original data)
1050         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1051         // now butcher the elements according to vertonseam and tri->facesfront
1052         // and then compact the vertex set to remove duplicates
1053         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1054                 if (!LittleLong(pintriangles[i].facesfront)) // backface
1055                         for (j = 0;j < 3;j++)
1056                                 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1057                                         loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1058         // count the usage
1059         // (this uses vertremap to count usage to save some memory)
1060         for (i = 0;i < numverts*2;i++)
1061                 vertremap[i] = 0;
1062         for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1063                 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1064         // build remapping table and compact array
1065         loadmodel->surfmesh.num_vertices = 0;
1066         for (i = 0;i < numverts*2;i++)
1067         {
1068                 if (vertremap[i])
1069                 {
1070                         vertremap[i] = loadmodel->surfmesh.num_vertices;
1071                         vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1072                         vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1073                         loadmodel->surfmesh.num_vertices++;
1074                 }
1075                 else
1076                         vertremap[i] = -1; // not used at all
1077         }
1078         // remap the elements to the new vertex set
1079         for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1080                 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1081         // store the texture coordinates
1082         loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1083         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1084         {
1085                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1086                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1087         }
1088
1089         // generate ushort elements array if possible
1090         if (loadmodel->surfmesh.num_vertices <= 65536)
1091                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1092         if (loadmodel->surfmesh.data_element3s)
1093                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1094                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1095
1096 // load the frames
1097         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1098         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1099         loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1100         Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1101         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1102         Mod_Alias_CalculateBoundingBox();
1103         Mod_Alias_MorphMesh_CompileFrames();
1104
1105         Mem_Free(vertst);
1106         Mem_Free(vertremap);
1107
1108         // load the skins
1109         skinfiles = Mod_LoadSkinFiles();
1110         if (skinfiles)
1111         {
1112                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1113                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1114                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1115                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1116                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1117                 Mod_FreeSkinFiles(skinfiles);
1118                 for (i = 0;i < loadmodel->numskins;i++)
1119                 {
1120                         loadmodel->skinscenes[i].firstframe = i;
1121                         loadmodel->skinscenes[i].framecount = 1;
1122                         loadmodel->skinscenes[i].loop = true;
1123                         loadmodel->skinscenes[i].framerate = 10;
1124                 }
1125         }
1126         else
1127         {
1128                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1129                 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1130                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1131                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1132                 totalskins = 0;
1133                 datapointer = startskins;
1134                 for (i = 0;i < loadmodel->numskins;i++)
1135                 {
1136                         pinskintype = (daliasskintype_t *)datapointer;
1137                         datapointer += sizeof(daliasskintype_t);
1138
1139                         if (pinskintype->type == ALIAS_SKIN_SINGLE)
1140                         {
1141                                 groupskins = 1;
1142                                 interval = 0.1f;
1143                         }
1144                         else
1145                         {
1146                                 pinskingroup = (daliasskingroup_t *)datapointer;
1147                                 datapointer += sizeof(daliasskingroup_t);
1148
1149                                 groupskins = LittleLong (pinskingroup->numskins);
1150
1151                                 pinskinintervals = (daliasskininterval_t *)datapointer;
1152                                 datapointer += sizeof(daliasskininterval_t) * groupskins;
1153
1154                                 interval = LittleFloat(pinskinintervals[0].interval);
1155                                 if (interval < 0.01f)
1156                                 {
1157                                         Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1158                                         interval = 0.1f;
1159                                 }
1160                         }
1161
1162                         dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1163                         loadmodel->skinscenes[i].firstframe = totalskins;
1164                         loadmodel->skinscenes[i].framecount = groupskins;
1165                         loadmodel->skinscenes[i].framerate = 1.0f / interval;
1166                         loadmodel->skinscenes[i].loop = true;
1167
1168                         for (j = 0;j < groupskins;j++)
1169                         {
1170                                 if (groupskins > 1)
1171                                         dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1172                                 else
1173                                         dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1174                                 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))
1175                                         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));
1176                                 datapointer += skinwidth * skinheight;
1177                                 totalskins++;
1178                         }
1179                 }
1180                 // check for skins that don't exist in the model, but do exist as external images
1181                 // (this was added because yummyluv kept pestering me about support for it)
1182                 // TODO: support shaders here?
1183                 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)))
1184                 {
1185                         // expand the arrays to make room
1186                         tempskinscenes = loadmodel->skinscenes;
1187                         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1188                         memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1189                         Mem_Free(tempskinscenes);
1190
1191                         tempaliasskins = loadmodel->data_textures;
1192                         loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1193                         memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1194                         Mem_Free(tempaliasskins);
1195
1196                         // store the info about the new skin
1197                         Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
1198                         strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1199                         loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1200                         loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1201                         loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1202                         loadmodel->skinscenes[loadmodel->numskins].loop = true;
1203
1204                         //increase skin counts
1205                         loadmodel->numskins++;
1206                         totalskins++;
1207
1208                         // fix up the pointers since they are pointing at the old textures array
1209                         // FIXME: this is a hack!
1210                         for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1211                                 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1212                 }
1213         }
1214
1215         surface = loadmodel->data_surfaces;
1216         surface->texture = loadmodel->data_textures;
1217         surface->num_firsttriangle = 0;
1218         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1219         surface->num_firstvertex = 0;
1220         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1221
1222         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1223
1224         if (!loadmodel->surfmesh.isanimated)
1225         {
1226                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1227                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1228                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1229                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1230                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1231                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1232         }
1233 }
1234
1235 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1236 {
1237         int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1238         float iskinwidth, iskinheight;
1239         unsigned char *data;
1240         msurface_t *surface;
1241         md2_t *pinmodel;
1242         unsigned char *base, *datapointer;
1243         md2frame_t *pinframe;
1244         char *inskin;
1245         md2triangle_t *intri;
1246         unsigned short *inst;
1247         struct md2verthash_s
1248         {
1249                 struct md2verthash_s *next;
1250                 unsigned short xyz;
1251                 unsigned short st;
1252         }
1253         *hash, **md2verthash, *md2verthashdata;
1254         skinfile_t *skinfiles;
1255
1256         pinmodel = (md2_t *)buffer;
1257         base = (unsigned char *)buffer;
1258
1259         version = LittleLong (pinmodel->version);
1260         if (version != MD2ALIAS_VERSION)
1261                 Host_Error ("%s has wrong version number (%i should be %i)",
1262                         loadmodel->name, version, MD2ALIAS_VERSION);
1263
1264         loadmodel->modeldatatypestring = "MD2";
1265
1266         loadmodel->type = mod_alias;
1267         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1268         loadmodel->DrawSky = NULL;
1269         loadmodel->DrawAddWaterPlanes = NULL;
1270         loadmodel->Draw = R_Q1BSP_Draw;
1271         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1272         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1273         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1274         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1275         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1276         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1277         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1278         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1279         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1280         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1281         loadmodel->PointSuperContents = NULL;
1282
1283         if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1284                 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1285         if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1286                 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1287         if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1288                 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1289         if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1290                 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1291
1292         end = LittleLong(pinmodel->ofs_end);
1293         if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1294                 Host_Error ("%s is not a valid model", loadmodel->name);
1295         if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1296                 Host_Error ("%s is not a valid model", loadmodel->name);
1297         if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1298                 Host_Error ("%s is not a valid model", loadmodel->name);
1299         if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1300                 Host_Error ("%s is not a valid model", loadmodel->name);
1301         if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1302                 Host_Error ("%s is not a valid model", loadmodel->name);
1303
1304         loadmodel->numskins = LittleLong(pinmodel->num_skins);
1305         numxyz = LittleLong(pinmodel->num_xyz);
1306         numst = LittleLong(pinmodel->num_st);
1307         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1308         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1309         loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1310         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1311         skinwidth = LittleLong(pinmodel->skinwidth);
1312         skinheight = LittleLong(pinmodel->skinheight);
1313         iskinwidth = 1.0f / skinwidth;
1314         iskinheight = 1.0f / skinheight;
1315
1316         loadmodel->num_surfaces = 1;
1317         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1318         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]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1319         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1320         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1321         loadmodel->sortedmodelsurfaces[0] = 0;
1322         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1323         loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1324         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1325         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1326
1327         loadmodel->synctype = ST_RAND;
1328
1329         // load the skins
1330         inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1331         skinfiles = Mod_LoadSkinFiles();
1332         if (skinfiles)
1333         {
1334                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1335                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1336                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1337                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1338                 Mod_FreeSkinFiles(skinfiles);
1339         }
1340         else if (loadmodel->numskins)
1341         {
1342                 // skins found (most likely not a player model)
1343                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1344                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1345                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1346                 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1347                         Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
1348         }
1349         else
1350         {
1351                 // no skins (most likely a player model)
1352                 loadmodel->numskins = 1;
1353                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1354                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1355                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1356                 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL);
1357         }
1358
1359         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1360         for (i = 0;i < loadmodel->numskins;i++)
1361         {
1362                 loadmodel->skinscenes[i].firstframe = i;
1363                 loadmodel->skinscenes[i].framecount = 1;
1364                 loadmodel->skinscenes[i].loop = true;
1365                 loadmodel->skinscenes[i].framerate = 10;
1366         }
1367
1368         // load the triangles and stvert data
1369         inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1370         intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1371         md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1372         md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1373         // swap the triangle list
1374         loadmodel->surfmesh.num_vertices = 0;
1375         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1376         {
1377                 for (j = 0;j < 3;j++)
1378                 {
1379                         xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1380                         st = (unsigned short) LittleShort (intri[i].index_st[j]);
1381                         if (xyz >= numxyz)
1382                         {
1383                                 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1384                                 xyz = 0;
1385                         }
1386                         if (st >= numst)
1387                         {
1388                                 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1389                                 st = 0;
1390                         }
1391                         hashindex = (xyz * 256 + st) & 65535;
1392                         for (hash = md2verthash[hashindex];hash;hash = hash->next)
1393                                 if (hash->xyz == xyz && hash->st == st)
1394                                         break;
1395                         if (hash == NULL)
1396                         {
1397                                 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1398                                 hash->xyz = xyz;
1399                                 hash->st = st;
1400                                 hash->next = md2verthash[hashindex];
1401                                 md2verthash[hashindex] = hash;
1402                         }
1403                         loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1404                 }
1405         }
1406
1407         vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1408         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));
1409         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1410         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1411         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1412         {
1413                 int sts, stt;
1414                 hash = md2verthashdata + i;
1415                 vertremap[i] = hash->xyz;
1416                 sts = LittleShort(inst[hash->st*2+0]);
1417                 stt = LittleShort(inst[hash->st*2+1]);
1418                 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1419                 {
1420                         Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1421                         sts = 0;
1422                         stt = 0;
1423                 }
1424                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1425                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1426         }
1427
1428         Mem_Free(md2verthash);
1429         Mem_Free(md2verthashdata);
1430
1431         // generate ushort elements array if possible
1432         if (loadmodel->surfmesh.num_vertices <= 65536)
1433                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1434         if (loadmodel->surfmesh.data_element3s)
1435                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1436                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1437
1438         // load the frames
1439         datapointer = (base + LittleLong(pinmodel->ofs_frames));
1440         for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1441         {
1442                 int k;
1443                 trivertx_t *v;
1444                 trivertx_t *out;
1445                 pinframe = (md2frame_t *)datapointer;
1446                 datapointer += sizeof(md2frame_t);
1447                 // store the frame scale/translate into the appropriate array
1448                 for (j = 0;j < 3;j++)
1449                 {
1450                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1451                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1452                 }
1453                 // convert the vertices
1454                 v = (trivertx_t *)datapointer;
1455                 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1456                 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1457                         out[k] = v[vertremap[k]];
1458                 datapointer += numxyz * sizeof(trivertx_t);
1459
1460                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1461                 loadmodel->animscenes[i].firstframe = i;
1462                 loadmodel->animscenes[i].framecount = 1;
1463                 loadmodel->animscenes[i].framerate = 10;
1464                 loadmodel->animscenes[i].loop = true;
1465         }
1466
1467         Mem_Free(vertremap);
1468
1469         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1470         Mod_Alias_CalculateBoundingBox();
1471         Mod_Alias_MorphMesh_CompileFrames();
1472
1473         surface = loadmodel->data_surfaces;
1474         surface->texture = loadmodel->data_textures;
1475         surface->num_firsttriangle = 0;
1476         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1477         surface->num_firstvertex = 0;
1478         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1479
1480         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1481
1482         if (!loadmodel->surfmesh.isanimated)
1483         {
1484                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1485                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1486                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1487                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1488                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1489                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1490         }
1491 }
1492
1493 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1494 {
1495         int i, j, k, version, meshvertices, meshtriangles;
1496         unsigned char *data;
1497         msurface_t *surface;
1498         md3modelheader_t *pinmodel;
1499         md3frameinfo_t *pinframe;
1500         md3mesh_t *pinmesh;
1501         md3tag_t *pintag;
1502         skinfile_t *skinfiles;
1503
1504         pinmodel = (md3modelheader_t *)buffer;
1505
1506         if (memcmp(pinmodel->identifier, "IDP3", 4))
1507                 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1508         version = LittleLong (pinmodel->version);
1509         if (version != MD3VERSION)
1510                 Host_Error ("%s has wrong version number (%i should be %i)",
1511                         loadmodel->name, version, MD3VERSION);
1512
1513         skinfiles = Mod_LoadSkinFiles();
1514         if (loadmodel->numskins < 1)
1515                 loadmodel->numskins = 1;
1516
1517         loadmodel->modeldatatypestring = "MD3";
1518
1519         loadmodel->type = mod_alias;
1520         loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1521         loadmodel->DrawSky = NULL;
1522         loadmodel->DrawAddWaterPlanes = NULL;
1523         loadmodel->Draw = R_Q1BSP_Draw;
1524         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1525         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1526         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1527         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1528         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1529         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1530         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1531         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1532         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1533         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1534         loadmodel->PointSuperContents = NULL;
1535         loadmodel->synctype = ST_RAND;
1536         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1537         i = LittleLong (pinmodel->flags);
1538         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1539
1540         // set up some global info about the model
1541         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1542         loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1543
1544         // make skinscenes for the skins (no groups)
1545         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1546         for (i = 0;i < loadmodel->numskins;i++)
1547         {
1548                 loadmodel->skinscenes[i].firstframe = i;
1549                 loadmodel->skinscenes[i].framecount = 1;
1550                 loadmodel->skinscenes[i].loop = true;
1551                 loadmodel->skinscenes[i].framerate = 10;
1552         }
1553
1554         // load frameinfo
1555         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1556         for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1557         {
1558                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1559                 loadmodel->animscenes[i].firstframe = i;
1560                 loadmodel->animscenes[i].framecount = 1;
1561                 loadmodel->animscenes[i].framerate = 10;
1562                 loadmodel->animscenes[i].loop = true;
1563         }
1564
1565         // load tags
1566         loadmodel->num_tagframes = loadmodel->numframes;
1567         loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1568         loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1569         for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1570         {
1571                 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1572                 for (j = 0;j < 9;j++)
1573                         loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1574                 for (j = 0;j < 3;j++)
1575                         loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1576                 //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);
1577         }
1578
1579         // load meshes
1580         meshvertices = 0;
1581         meshtriangles = 0;
1582         for (i = 0, pinmesh = (md3mesh_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_meshes));i < loadmodel->num_surfaces;i++, pinmesh = (md3mesh_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_end)))
1583         {
1584                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1585                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1586                 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1587                         Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1588                 meshvertices += LittleLong(pinmesh->num_vertices);
1589                 meshtriangles += LittleLong(pinmesh->num_triangles);
1590         }
1591
1592         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1593         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1594         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1595         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]) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[2]) + meshvertices * loadmodel->numframes * sizeof(md3vertex_t));
1596         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1597         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1598         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1599         loadmodel->surfmesh.num_vertices = meshvertices;
1600         loadmodel->surfmesh.num_triangles = meshtriangles;
1601         loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1602         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1603         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1604         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1605         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1606         loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1607         if (meshvertices <= 65536)
1608                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1609
1610         meshvertices = 0;
1611         meshtriangles = 0;
1612         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)))
1613         {
1614                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1615                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1616                 loadmodel->sortedmodelsurfaces[i] = i;
1617                 surface = loadmodel->data_surfaces + i;
1618                 surface->texture = loadmodel->data_textures + i;
1619                 surface->num_firsttriangle = meshtriangles;
1620                 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1621                 surface->num_firstvertex = meshvertices;
1622                 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1623                 meshvertices += surface->num_vertices;
1624                 meshtriangles += surface->num_triangles;
1625
1626                 for (j = 0;j < surface->num_triangles * 3;j++)
1627                         loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1628                 for (j = 0;j < surface->num_vertices;j++)
1629                 {
1630                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1631                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1632                 }
1633                 for (j = 0;j < loadmodel->numframes;j++)
1634                 {
1635                         const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1636                         md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1637                         for (k = 0;k < surface->num_vertices;k++, in++, out++)
1638                         {
1639                                 out->origin[0] = LittleShort(in->origin[0]);
1640                                 out->origin[1] = LittleShort(in->origin[1]);
1641                                 out->origin[2] = LittleShort(in->origin[2]);
1642                                 out->pitch = in->pitch;
1643                                 out->yaw = in->yaw;
1644                         }
1645                 }
1646
1647                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1648
1649                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1650         }
1651         if (loadmodel->surfmesh.data_element3s)
1652                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1653                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1654         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1655         Mod_Alias_MorphMesh_CompileFrames();
1656         Mod_Alias_CalculateBoundingBox();
1657         Mod_FreeSkinFiles(skinfiles);
1658         Mod_MakeSortedSurfaces(loadmodel);
1659
1660         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1
1661              || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
1662
1663         if (!loadmodel->surfmesh.isanimated)
1664         {
1665                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1666                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1667                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1668                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1669                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1670                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1671         }
1672 }
1673
1674 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1675 {
1676         zymtype1header_t *pinmodel, *pheader;
1677         unsigned char *pbase;
1678         int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1679         float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1680         zymvertex_t *verts, *vertdata;
1681         zymscene_t *scene;
1682         zymbone_t *bone;
1683         char *shadername;
1684         skinfile_t *skinfiles;
1685         unsigned char *data;
1686         msurface_t *surface;
1687
1688         pinmodel = (zymtype1header_t *)buffer;
1689         pbase = (unsigned char *)buffer;
1690         if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1691                 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1692         if (BigLong(pinmodel->type) != 1)
1693                 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1694
1695         loadmodel->modeldatatypestring = "ZYM";
1696
1697         loadmodel->type = mod_alias;
1698         loadmodel->synctype = ST_RAND;
1699
1700         // byteswap header
1701         pheader = pinmodel;
1702         pheader->type = BigLong(pinmodel->type);
1703         pheader->filesize = BigLong(pinmodel->filesize);
1704         pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1705         pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1706         pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1707         pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1708         pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1709         pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1710         pheader->radius = BigFloat(pinmodel->radius);
1711         pheader->numverts = BigLong(pinmodel->numverts);
1712         pheader->numtris = BigLong(pinmodel->numtris);
1713         pheader->numshaders = BigLong(pinmodel->numshaders);
1714         pheader->numbones = BigLong(pinmodel->numbones);
1715         pheader->numscenes = BigLong(pinmodel->numscenes);
1716         pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1717         pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1718         pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1719         pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1720         pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1721         pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1722         pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1723         pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1724         pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1725         pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1726         pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1727         pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1728         pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1729         pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1730         pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1731         pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1732         pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1733         pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1734
1735         if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1736         {
1737                 Con_Printf("%s has no geometry\n", loadmodel->name);
1738                 return;
1739         }
1740         if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1741         {
1742                 Con_Printf("%s has no animations\n", loadmodel->name);
1743                 return;
1744         }
1745
1746         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1747         loadmodel->DrawSky = NULL;
1748         loadmodel->DrawAddWaterPlanes = NULL;
1749         loadmodel->Draw = R_Q1BSP_Draw;
1750         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1751         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1752         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1753         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1754         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1755         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1756         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1757         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1758         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1759         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1760         loadmodel->PointSuperContents = NULL;
1761
1762         loadmodel->numframes = pheader->numscenes;
1763         loadmodel->num_surfaces = pheader->numshaders;
1764
1765         skinfiles = Mod_LoadSkinFiles();
1766         if (loadmodel->numskins < 1)
1767                 loadmodel->numskins = 1;
1768
1769         // make skinscenes for the skins (no groups)
1770         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1771         for (i = 0;i < loadmodel->numskins;i++)
1772         {
1773                 loadmodel->skinscenes[i].firstframe = i;
1774                 loadmodel->skinscenes[i].framecount = 1;
1775                 loadmodel->skinscenes[i].loop = true;
1776                 loadmodel->skinscenes[i].framerate = 10;
1777         }
1778
1779         // model bbox
1780         modelradius = pheader->radius;
1781         for (i = 0;i < 3;i++)
1782         {
1783                 loadmodel->normalmins[i] = pheader->mins[i];
1784                 loadmodel->normalmaxs[i] = pheader->maxs[i];
1785                 loadmodel->rotatedmins[i] = -modelradius;
1786                 loadmodel->rotatedmaxs[i] = modelradius;
1787         }
1788         corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1789         corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1790         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1791         if (loadmodel->yawmaxs[0] > modelradius)
1792                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1793         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1794         loadmodel->yawmins[2] = loadmodel->normalmins[2];
1795         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1796         loadmodel->radius = modelradius;
1797         loadmodel->radius2 = modelradius * modelradius;
1798
1799         // go through the lumps, swapping things
1800
1801         //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1802         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1803         scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1804         numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1805         for (i = 0;i < pheader->numscenes;i++)
1806         {
1807                 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1808                 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1809                 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1810                 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1811                 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1812                 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1813                         Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1814                 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1815                         Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1816                 if (loadmodel->animscenes[i].framerate < 0)
1817                         Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1818                 scene++;
1819         }
1820
1821         //zymlump_t lump_bones; // zymbone_t bone[numbones];
1822         loadmodel->num_bones = pheader->numbones;
1823         loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1824         bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1825         for (i = 0;i < pheader->numbones;i++)
1826         {
1827                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1828                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1829                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1830                 if (loadmodel->data_bones[i].parent >= i)
1831                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1832         }
1833
1834         //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1835         vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1836         bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1837         for (i = 0;i < pheader->numverts;i++)
1838         {
1839                 vertbonecounts[i] = BigLong(bonecount[i]);
1840                 if (vertbonecounts[i] != 1)
1841                         Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1842         }
1843
1844         loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1845
1846         meshvertices = pheader->numverts;
1847         meshtriangles = pheader->numtris;
1848
1849         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1850         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1851         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1852         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]) + meshtriangles * sizeof(int[3]) + (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]));
1853         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1854         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1855         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1856         loadmodel->surfmesh.num_vertices = meshvertices;
1857         loadmodel->surfmesh.num_triangles = meshtriangles;
1858         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1859         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1860         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1861         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1862         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1863         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1864         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1865         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1866         loadmodel->surfmesh.num_blends = 0;
1867         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
1868         if (loadmodel->surfmesh.num_vertices <= 65536)
1869                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1870         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
1871         loadmodel->surfmesh.data_blendweights = NULL;
1872
1873         //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1874         poses = (float *) (pheader->lump_poses.start + pbase);
1875         // figure out scale of model from root bone, for compatibility with old zmodel versions
1876         tempvec[0] = BigFloat(poses[0]);
1877         tempvec[1] = BigFloat(poses[1]);
1878         tempvec[2] = BigFloat(poses[2]);
1879         modelscale = VectorLength(tempvec);
1880         biggestorigin = 0;
1881         for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
1882         {
1883                 f = fabs(BigFloat(poses[i]));
1884                 biggestorigin = max(biggestorigin, f);
1885         }
1886         loadmodel->num_posescale = biggestorigin / 32767.0f;
1887         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
1888         for (i = 0;i < numposes;i++)
1889         {
1890                 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
1891                 for (j = 0;j < loadmodel->num_bones;j++)
1892                 {
1893                         float pose[12];
1894                         matrix4x4_t posematrix;
1895                         for (k = 0;k < 12;k++)
1896                                 pose[k] = BigFloat(frameposes[j*12+k]);
1897                         //if (j < loadmodel->num_bones)
1898                         //      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));
1899                         // scale child bones to match the root scale
1900                         if (loadmodel->data_bones[j].parent >= 0)
1901                         {
1902                                 pose[3] *= modelscale;
1903                                 pose[7] *= modelscale;
1904                                 pose[11] *= modelscale;
1905                         }
1906                         // normalize rotation matrix
1907                         VectorNormalize(pose + 0);
1908                         VectorNormalize(pose + 4);
1909                         VectorNormalize(pose + 8);
1910                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
1911                         Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*(i*loadmodel->num_bones+j));
1912                 }
1913         }
1914
1915         //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
1916         verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
1917         vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
1918         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
1919         // (converting from weight-blending skeletal animation to
1920         //  deformation-based skeletal animation)
1921         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
1922         for (i = 0;i < loadmodel->num_bones;i++)
1923         {
1924                 float m[12];
1925                 for (k = 0;k < 12;k++)
1926                         m[k] = BigFloat(poses[i*12+k]);
1927                 if (loadmodel->data_bones[i].parent >= 0)
1928                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
1929                 else
1930                         for (k = 0;k < 12;k++)
1931                                 bonepose[12*i+k] = m[k];
1932         }
1933         for (j = 0;j < pheader->numverts;j++)
1934         {
1935                 // this format really should have had a per vertexweight weight value...
1936                 // but since it does not, the weighting is completely ignored and
1937                 // only one weight is allowed per vertex
1938                 int boneindex = BigLong(vertdata[j].bonenum);
1939                 const float *m = bonepose + 12 * boneindex;
1940                 float relativeorigin[3];
1941                 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
1942                 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
1943                 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
1944                 // transform the vertex bone weight into the base mesh
1945                 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
1946                 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
1947                 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
1948                 // store the weight as the primary weight on this vertex
1949                 loadmodel->surfmesh.blends[j] = boneindex;
1950         }
1951         Z_Free(bonepose);
1952         // normals and tangents are calculated after elements are loaded
1953
1954         //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
1955         outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
1956         intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
1957         for (i = 0;i < pheader->numverts;i++)
1958         {
1959                 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
1960                 // flip T coordinate for OpenGL
1961                 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
1962         }
1963
1964         //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
1965         //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
1966         //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
1967
1968         //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
1969         //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)
1970         // byteswap, validate, and swap winding order of tris
1971         count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
1972         if (pheader->lump_render.length != count)
1973                 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
1974         renderlist = (int *) (pheader->lump_render.start + pbase);
1975         renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
1976         meshtriangles = 0;
1977         for (i = 0;i < loadmodel->num_surfaces;i++)
1978         {
1979                 int firstvertex, lastvertex;
1980                 if (renderlist >= renderlistend)
1981                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
1982                 count = BigLong(*renderlist);renderlist++;
1983                 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
1984                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
1985
1986                 loadmodel->sortedmodelsurfaces[i] = i;
1987                 surface = loadmodel->data_surfaces + i;
1988                 surface->texture = loadmodel->data_textures + i;
1989                 surface->num_firsttriangle = meshtriangles;
1990                 surface->num_triangles = count;
1991                 meshtriangles += surface->num_triangles;
1992
1993                 // load the elements
1994                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1995                 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
1996                 {
1997                         outelements[j*3+2] = BigLong(renderlist[0]);
1998                         outelements[j*3+1] = BigLong(renderlist[1]);
1999                         outelements[j*3+0] = BigLong(renderlist[2]);
2000                 }
2001                 // validate the elements and find the used vertex range
2002                 firstvertex = meshvertices;
2003                 lastvertex = 0;
2004                 for (j = 0;j < surface->num_triangles * 3;j++)
2005                 {
2006                         if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2007                                 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2008                         firstvertex = min(firstvertex, outelements[j]);
2009                         lastvertex = max(lastvertex, outelements[j]);
2010                 }
2011                 surface->num_firstvertex = firstvertex;
2012                 surface->num_vertices = lastvertex + 1 - firstvertex;
2013
2014                 // since zym models do not have named sections, reuse their shader
2015                 // name as the section name
2016                 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2017                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2018         }
2019         Mod_FreeSkinFiles(skinfiles);
2020         Mem_Free(vertbonecounts);
2021         Mem_Free(verts);
2022         Mod_MakeSortedSurfaces(loadmodel);
2023
2024         // compute all the mesh information that was not loaded from the file
2025         if (loadmodel->surfmesh.data_element3s)
2026                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2027                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2028         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2029         Mod_BuildBaseBonePoses();
2030         Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true);
2031         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, true);
2032         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2033
2034         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
2035
2036         if (!loadmodel->surfmesh.isanimated)
2037         {
2038                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2039                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2040                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2041                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2042                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2043                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2044         }
2045 }
2046
2047 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2048 {
2049         dpmheader_t *pheader;
2050         dpmframe_t *frames;
2051         dpmbone_t *bone;
2052         dpmmesh_t *dpmmesh;
2053         unsigned char *pbase;
2054         int i, j, k, meshvertices, meshtriangles;
2055         skinfile_t *skinfiles;
2056         unsigned char *data;
2057         float *bonepose;
2058         float biggestorigin, tempvec[3], modelscale;
2059         float f;
2060         float *poses;
2061
2062         pheader = (dpmheader_t *)buffer;
2063         pbase = (unsigned char *)buffer;
2064         if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2065                 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2066         if (BigLong(pheader->type) != 2)
2067                 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2068
2069         loadmodel->modeldatatypestring = "DPM";
2070
2071         loadmodel->type = mod_alias;
2072         loadmodel->synctype = ST_RAND;
2073
2074         // byteswap header
2075         pheader->type = BigLong(pheader->type);
2076         pheader->filesize = BigLong(pheader->filesize);
2077         pheader->mins[0] = BigFloat(pheader->mins[0]);
2078         pheader->mins[1] = BigFloat(pheader->mins[1]);
2079         pheader->mins[2] = BigFloat(pheader->mins[2]);
2080         pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2081         pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2082         pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2083         pheader->yawradius = BigFloat(pheader->yawradius);
2084         pheader->allradius = BigFloat(pheader->allradius);
2085         pheader->num_bones = BigLong(pheader->num_bones);
2086         pheader->num_meshs = BigLong(pheader->num_meshs);
2087         pheader->num_frames = BigLong(pheader->num_frames);
2088         pheader->ofs_bones = BigLong(pheader->ofs_bones);
2089         pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2090         pheader->ofs_frames = BigLong(pheader->ofs_frames);
2091
2092         if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2093         {
2094                 Con_Printf("%s has no geometry\n", loadmodel->name);
2095                 return;
2096         }
2097         if (pheader->num_frames < 1)
2098         {
2099                 Con_Printf("%s has no frames\n", loadmodel->name);
2100                 return;
2101         }
2102
2103         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2104         loadmodel->DrawSky = NULL;
2105         loadmodel->DrawAddWaterPlanes = NULL;
2106         loadmodel->Draw = R_Q1BSP_Draw;
2107         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2108         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2109         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2110         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2111         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2112         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2113         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2114         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2115         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2116         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2117         loadmodel->PointSuperContents = NULL;
2118
2119         // model bbox
2120         for (i = 0;i < 3;i++)
2121         {
2122                 loadmodel->normalmins[i] = pheader->mins[i];
2123                 loadmodel->normalmaxs[i] = pheader->maxs[i];
2124                 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2125                 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2126                 loadmodel->rotatedmins[i] = -pheader->allradius;
2127                 loadmodel->rotatedmaxs[i] = pheader->allradius;
2128         }
2129         loadmodel->radius = pheader->allradius;
2130         loadmodel->radius2 = pheader->allradius * pheader->allradius;
2131
2132         // load external .skin files if present
2133         skinfiles = Mod_LoadSkinFiles();
2134         if (loadmodel->numskins < 1)
2135                 loadmodel->numskins = 1;
2136
2137         meshvertices = 0;
2138         meshtriangles = 0;
2139
2140         // gather combined statistics from the meshes
2141         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2142         for (i = 0;i < (int)pheader->num_meshs;i++)
2143         {
2144                 int numverts = BigLong(dpmmesh->num_verts);
2145                 meshvertices += numverts;
2146                 meshtriangles += BigLong(dpmmesh->num_tris);
2147                 dpmmesh++;
2148         }
2149
2150         loadmodel->numframes = pheader->num_frames;
2151         loadmodel->num_bones = pheader->num_bones;
2152         loadmodel->num_poses = loadmodel->numframes;
2153         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2154         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2155         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2156         // do most allocations as one merged chunk
2157         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) + meshtriangles * sizeof(int[3]) + 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));
2158         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2159         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2160         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2161         loadmodel->surfmesh.num_vertices = meshvertices;
2162         loadmodel->surfmesh.num_triangles = meshtriangles;
2163         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2164         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2165         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2166         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2167         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2168         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2169         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2170         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2171         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2172         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2173         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2174         loadmodel->surfmesh.num_blends = 0;
2175         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2176         if (meshvertices <= 65536)
2177                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2178         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
2179         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2180
2181         for (i = 0;i < loadmodel->numskins;i++)
2182         {
2183                 loadmodel->skinscenes[i].firstframe = i;
2184                 loadmodel->skinscenes[i].framecount = 1;
2185                 loadmodel->skinscenes[i].loop = true;
2186                 loadmodel->skinscenes[i].framerate = 10;
2187         }
2188
2189         // load the bone info
2190         bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2191         for (i = 0;i < loadmodel->num_bones;i++)
2192         {
2193                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2194                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2195                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2196                 if (loadmodel->data_bones[i].parent >= i)
2197                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2198         }
2199
2200         // load the frames
2201         frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2202         // figure out scale of model from root bone, for compatibility with old dpmodel versions
2203         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2204         tempvec[0] = BigFloat(poses[0]);
2205         tempvec[1] = BigFloat(poses[1]);
2206         tempvec[2] = BigFloat(poses[2]);
2207         modelscale = VectorLength(tempvec);
2208         biggestorigin = 0;
2209         for (i = 0;i < loadmodel->numframes;i++)
2210         {
2211                 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2212                 loadmodel->animscenes[i].firstframe = i;
2213                 loadmodel->animscenes[i].framecount = 1;
2214                 loadmodel->animscenes[i].loop = true;
2215                 loadmodel->animscenes[i].framerate = 10;
2216                 // load the bone poses for this frame
2217                 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2218                 for (j = 0;j < loadmodel->num_bones*12;j++)
2219                 {
2220                         f = fabs(BigFloat(poses[j]));
2221                         biggestorigin = max(biggestorigin, f);
2222                 }
2223                 // stuff not processed here: mins, maxs, yawradius, allradius
2224         }
2225         loadmodel->num_posescale = biggestorigin / 32767.0f;
2226         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2227         for (i = 0;i < loadmodel->numframes;i++)
2228         {
2229                 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2230                 for (j = 0;j < loadmodel->num_bones;j++)
2231                 {
2232                         float pose[12];
2233                         matrix4x4_t posematrix;
2234                         for (k = 0;k < 12;k++)
2235                                 pose[k] = BigFloat(frameposes[j*12+k]);
2236                         // scale child bones to match the root scale
2237                         if (loadmodel->data_bones[j].parent >= 0)
2238                         {
2239                                 pose[3] *= modelscale;
2240                                 pose[7] *= modelscale;
2241                                 pose[11] *= modelscale;
2242                         }
2243                         // normalize rotation matrix
2244                         VectorNormalize(pose + 0);
2245                         VectorNormalize(pose + 4);
2246                         VectorNormalize(pose + 8);
2247                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2248                         Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*(i*loadmodel->num_bones+j));
2249                 }
2250         }
2251
2252         // load the meshes now
2253         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2254         meshvertices = 0;
2255         meshtriangles = 0;
2256         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2257         // (converting from weight-blending skeletal animation to
2258         //  deformation-based skeletal animation)
2259         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2260         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2261         for (i = 0;i < loadmodel->num_bones;i++)
2262         {
2263                 float m[12];
2264                 for (k = 0;k < 12;k++)
2265                         m[k] = BigFloat(poses[i*12+k]);
2266                 if (loadmodel->data_bones[i].parent >= 0)
2267                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2268                 else
2269                         for (k = 0;k < 12;k++)
2270                                 bonepose[12*i+k] = m[k];
2271         }
2272         for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2273         {
2274                 const int *inelements;
2275                 int *outelements;
2276                 const float *intexcoord;
2277                 msurface_t *surface;
2278
2279                 loadmodel->sortedmodelsurfaces[i] = i;
2280                 surface = loadmodel->data_surfaces + i;
2281                 surface->texture = loadmodel->data_textures + i;
2282                 surface->num_firsttriangle = meshtriangles;
2283                 surface->num_triangles = BigLong(dpmmesh->num_tris);
2284                 surface->num_firstvertex = meshvertices;
2285                 surface->num_vertices = BigLong(dpmmesh->num_verts);
2286                 meshvertices += surface->num_vertices;
2287                 meshtriangles += surface->num_triangles;
2288
2289                 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2290                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2291                 for (j = 0;j < surface->num_triangles;j++)
2292                 {
2293                         // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2294                         outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2295                         outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2296                         outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2297                         inelements += 3;
2298                         outelements += 3;
2299                 }
2300
2301                 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2302                 for (j = 0;j < surface->num_vertices*2;j++)
2303                         loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2304
2305                 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2306                 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2307                 {
2308                         int weightindex[4] = { 0, 0, 0, 0 };
2309                         float weightinfluence[4] = { 0, 0, 0, 0 };
2310                         int l;
2311                         int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2312                         data += sizeof(dpmvertex_t);
2313                         for (k = 0;k < numweights;k++)
2314                         {
2315                                 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2316                                 int boneindex = BigLong(vert->bonenum);
2317                                 const float *m = bonepose + 12 * boneindex;
2318                                 float influence = BigFloat(vert->influence);
2319                                 float relativeorigin[3], relativenormal[3];
2320                                 relativeorigin[0] = BigFloat(vert->origin[0]);
2321                                 relativeorigin[1] = BigFloat(vert->origin[1]);
2322                                 relativeorigin[2] = BigFloat(vert->origin[2]);
2323                                 relativenormal[0] = BigFloat(vert->normal[0]);
2324                                 relativenormal[1] = BigFloat(vert->normal[1]);
2325                                 relativenormal[2] = BigFloat(vert->normal[2]);
2326                                 // blend the vertex bone weights into the base mesh
2327                                 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2328                                 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2329                                 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2330                                 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2331                                 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2332                                 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2333                                 if (!k)
2334                                 {
2335                                         // store the first (and often only) weight
2336                                         weightinfluence[0] = influence;
2337                                         weightindex[0] = boneindex;
2338                                 }
2339                                 else
2340                                 {
2341                                         // sort the new weight into this vertex's weight table
2342                                         // (which only accepts up to 4 bones per vertex)
2343                                         for (l = 0;l < 4;l++)
2344                                         {
2345                                                 if (weightinfluence[l] < influence)
2346                                                 {
2347                                                         // move weaker influence weights out of the way first
2348                                                         int l2;
2349                                                         for (l2 = 3;l2 > l;l2--)
2350                                                         {
2351                                                                 weightinfluence[l2] = weightinfluence[l2-1];
2352                                                                 weightindex[l2] = weightindex[l2-1];
2353                                                         }
2354                                                         // store the new weight
2355                                                         weightinfluence[l] = influence;
2356                                                         weightindex[l] = boneindex;
2357                                                         break;
2358                                                 }
2359                                         }
2360                                 }
2361                                 data += sizeof(dpmbonevert_t);
2362                         }
2363                         loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2364                 }
2365
2366                 // since dpm models do not have named sections, reuse their shader name as the section name
2367                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2368
2369                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2370         }
2371         if (loadmodel->surfmesh.num_blends < meshvertices)
2372                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2373         Z_Free(bonepose);
2374         Mod_FreeSkinFiles(skinfiles);
2375         Mod_MakeSortedSurfaces(loadmodel);
2376
2377         // compute all the mesh information that was not loaded from the file
2378         if (loadmodel->surfmesh.data_element3s)
2379                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2380                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2381         Mod_BuildBaseBonePoses();
2382         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, true);
2383         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2384
2385         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
2386
2387         if (!loadmodel->surfmesh.isanimated)
2388         {
2389                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2390                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2391                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2392                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2393                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2394                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2395         }
2396 }
2397
2398 // no idea why PSK/PSA files contain weird quaternions but they do...
2399 #define PSKQUATNEGATIONS
2400 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2401 {
2402         int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2403         int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2404         fs_offset_t filesize;
2405         pskpnts_t *pnts;
2406         pskvtxw_t *vtxw;
2407         pskface_t *faces;
2408         pskmatt_t *matts;
2409         pskboneinfo_t *bones;
2410         pskrawweights_t *rawweights;
2411         //pskboneinfo_t *animbones;
2412         pskaniminfo_t *anims;
2413         pskanimkeys_t *animkeys;
2414         void *animfilebuffer, *animbuffer, *animbufferend;
2415         unsigned char *data;
2416         pskchunk_t *pchunk;
2417         skinfile_t *skinfiles;
2418         char animname[MAX_QPATH];
2419         size_t size;
2420         float biggestorigin;
2421
2422         pchunk = (pskchunk_t *)buffer;
2423         if (strcmp(pchunk->id, "ACTRHEAD"))
2424                 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2425
2426         loadmodel->modeldatatypestring = "PSK";
2427
2428         loadmodel->type = mod_alias;
2429         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2430         loadmodel->DrawSky = NULL;
2431         loadmodel->DrawAddWaterPlanes = NULL;
2432         loadmodel->Draw = R_Q1BSP_Draw;
2433         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2434         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2435         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2436         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2437         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2438         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2439         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2440         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2441         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2442         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2443         loadmodel->PointSuperContents = NULL;
2444         loadmodel->synctype = ST_RAND;
2445
2446         FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2447         strlcat(animname, ".psa", sizeof(animname));
2448         animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2449         animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2450         if (animbuffer == NULL)
2451                 Host_Error("%s: can't find .psa file (%s)", loadmodel->name, animname);
2452
2453         numpnts = 0;
2454         pnts = NULL;
2455         numvtxw = 0;
2456         vtxw = NULL;
2457         numfaces = 0;
2458         faces = NULL;
2459         nummatts = 0;
2460         matts = NULL;
2461         numbones = 0;
2462         bones = NULL;
2463         numrawweights = 0;
2464         rawweights = NULL;
2465         numanims = 0;
2466         anims = NULL;
2467         numanimkeys = 0;
2468         animkeys = NULL;
2469
2470         while (buffer < bufferend)
2471         {
2472                 pchunk = (pskchunk_t *)buffer;
2473                 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2474                 version = LittleLong(pchunk->version);
2475                 recordsize = LittleLong(pchunk->recordsize);
2476                 numrecords = LittleLong(pchunk->numrecords);
2477                 if (developer_extra.integer)
2478                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2479                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2480                         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);
2481                 if (!strcmp(pchunk->id, "ACTRHEAD"))
2482                 {
2483                         // nothing to do
2484                 }
2485                 else if (!strcmp(pchunk->id, "PNTS0000"))
2486                 {
2487                         pskpnts_t *p;
2488                         if (recordsize != sizeof(*p))
2489                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2490                         // byteswap in place and keep the pointer
2491                         numpnts = numrecords;
2492                         pnts = (pskpnts_t *)buffer;
2493                         for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2494                         {
2495                                 p->origin[0] = LittleFloat(p->origin[0]);
2496                                 p->origin[1] = LittleFloat(p->origin[1]);
2497                                 p->origin[2] = LittleFloat(p->origin[2]);
2498                         }
2499                         buffer = p;
2500                 }
2501                 else if (!strcmp(pchunk->id, "VTXW0000"))
2502                 {
2503                         pskvtxw_t *p;
2504                         if (recordsize != sizeof(*p))
2505                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2506                         // byteswap in place and keep the pointer
2507                         numvtxw = numrecords;
2508                         vtxw = (pskvtxw_t *)buffer;
2509                         for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2510                         {
2511                                 p->pntsindex = LittleShort(p->pntsindex);
2512                                 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2513                                 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2514                                 if (p->pntsindex >= numpnts)
2515                                 {
2516                                         Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2517                                         p->pntsindex = 0;
2518                                 }
2519                         }
2520                         buffer = p;
2521                 }
2522                 else if (!strcmp(pchunk->id, "FACE0000"))
2523                 {
2524                         pskface_t *p;
2525                         if (recordsize != sizeof(*p))
2526                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2527                         // byteswap in place and keep the pointer
2528                         numfaces = numrecords;
2529                         faces = (pskface_t *)buffer;
2530                         for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2531                         {
2532                                 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2533                                 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2534                                 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2535                                 p->group = LittleLong(p->group);
2536                                 if (p->vtxwindex[0] >= numvtxw)
2537                                 {
2538                                         Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2539                                         p->vtxwindex[0] = 0;
2540                                 }
2541                                 if (p->vtxwindex[1] >= numvtxw)
2542                                 {
2543                                         Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2544                                         p->vtxwindex[1] = 0;
2545                                 }
2546                                 if (p->vtxwindex[2] >= numvtxw)
2547                                 {
2548                                         Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2549                                         p->vtxwindex[2] = 0;
2550                                 }
2551                         }
2552                         buffer = p;
2553                 }
2554                 else if (!strcmp(pchunk->id, "MATT0000"))
2555                 {
2556                         pskmatt_t *p;
2557                         if (recordsize != sizeof(*p))
2558                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2559                         // byteswap in place and keep the pointer
2560                         nummatts = numrecords;
2561                         matts = (pskmatt_t *)buffer;
2562                         for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2563                         {
2564                                 // nothing to do
2565                         }
2566                         buffer = p;
2567                 }
2568                 else if (!strcmp(pchunk->id, "REFSKELT"))
2569                 {
2570                         pskboneinfo_t *p;
2571                         if (recordsize != sizeof(*p))
2572                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2573                         // byteswap in place and keep the pointer
2574                         numbones = numrecords;
2575                         bones = (pskboneinfo_t *)buffer;
2576                         for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2577                         {
2578                                 p->numchildren = LittleLong(p->numchildren);
2579                                 p->parent = LittleLong(p->parent);
2580                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2581                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2582                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2583                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2584                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2585                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2586                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2587                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2588                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2589                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2590                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2591 #ifdef PSKQUATNEGATIONS
2592                                 if (index)
2593                                 {
2594                                         p->basepose.quat[0] *= -1;
2595                                         p->basepose.quat[1] *= -1;
2596                                         p->basepose.quat[2] *= -1;
2597                                 }
2598                                 else
2599                                 {
2600                                         p->basepose.quat[0] *=  1;
2601                                         p->basepose.quat[1] *= -1;
2602                                         p->basepose.quat[2] *=  1;
2603                                 }
2604 #endif
2605                                 if (p->parent < 0 || p->parent >= numbones)
2606                                 {
2607                                         Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2608                                         p->parent = 0;
2609                                 }
2610                         }
2611                         buffer = p;
2612                 }
2613                 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2614                 {
2615                         pskrawweights_t *p;
2616                         if (recordsize != sizeof(*p))
2617                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2618                         // byteswap in place and keep the pointer
2619                         numrawweights = numrecords;
2620                         rawweights = (pskrawweights_t *)buffer;
2621                         for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2622                         {
2623                                 p->weight = LittleFloat(p->weight);
2624                                 p->pntsindex = LittleLong(p->pntsindex);
2625                                 p->boneindex = LittleLong(p->boneindex);
2626                                 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2627                                 {
2628                                         Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2629                                         p->pntsindex = 0;
2630                                 }
2631                                 if (p->boneindex < 0 || p->boneindex >= numbones)
2632                                 {
2633                                         Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2634                                         p->boneindex = 0;
2635                                 }
2636                         }
2637                         buffer = p;
2638                 }
2639         }
2640
2641         while (animbuffer < animbufferend)
2642         {
2643                 pchunk = (pskchunk_t *)animbuffer;
2644                 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2645                 version = LittleLong(pchunk->version);
2646                 recordsize = LittleLong(pchunk->recordsize);
2647                 numrecords = LittleLong(pchunk->numrecords);
2648                 if (developer_extra.integer)
2649                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2650                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2651                         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);
2652                 if (!strcmp(pchunk->id, "ANIMHEAD"))
2653                 {
2654                         // nothing to do
2655                 }
2656                 else if (!strcmp(pchunk->id, "BONENAMES"))
2657                 {
2658                         pskboneinfo_t *p;
2659                         if (recordsize != sizeof(*p))
2660                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2661                         // byteswap in place and keep the pointer
2662                         numanimbones = numrecords;
2663                         //animbones = (pskboneinfo_t *)animbuffer;
2664                         // NOTE: supposedly psa does not need to match the psk model, the
2665                         // bones missing from the psa would simply use their base
2666                         // positions from the psk, but this is hard for me to implement
2667                         // and people can easily make animations that match.
2668                         if (numanimbones != numbones)
2669                                 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2670                         for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2671                         {
2672                                 p->numchildren = LittleLong(p->numchildren);
2673                                 p->parent = LittleLong(p->parent);
2674                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2675                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2676                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2677                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2678                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2679                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2680                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2681                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2682                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2683                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2684                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2685 #ifdef PSKQUATNEGATIONS
2686                                 if (index)
2687                                 {
2688                                         p->basepose.quat[0] *= -1;
2689                                         p->basepose.quat[1] *= -1;
2690                                         p->basepose.quat[2] *= -1;
2691                                 }
2692                                 else
2693                                 {
2694                                         p->basepose.quat[0] *=  1;
2695                                         p->basepose.quat[1] *= -1;
2696                                         p->basepose.quat[2] *=  1;
2697                                 }
2698 #endif
2699                                 if (p->parent < 0 || p->parent >= numanimbones)
2700                                 {
2701                                         Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2702                                         p->parent = 0;
2703                                 }
2704                                 // check that bones are the same as in the base
2705                                 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2706                                         Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2707                         }
2708                         animbuffer = p;
2709                 }
2710                 else if (!strcmp(pchunk->id, "ANIMINFO"))
2711                 {
2712                         pskaniminfo_t *p;
2713                         if (recordsize != sizeof(*p))
2714                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2715                         // byteswap in place and keep the pointer
2716                         numanims = numrecords;
2717                         anims = (pskaniminfo_t *)animbuffer;
2718                         for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2719                         {
2720                                 p->numbones = LittleLong(p->numbones);
2721                                 p->playtime = LittleFloat(p->playtime);
2722                                 p->fps = LittleFloat(p->fps);
2723                                 p->firstframe = LittleLong(p->firstframe);
2724                                 p->numframes = LittleLong(p->numframes);
2725                                 if (p->numbones != numbones)
2726                                         Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2727                         }
2728                         animbuffer = p;
2729                 }
2730                 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2731                 {
2732                         pskanimkeys_t *p;
2733                         if (recordsize != sizeof(*p))
2734                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2735                         numanimkeys = numrecords;
2736                         animkeys = (pskanimkeys_t *)animbuffer;
2737                         for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2738                         {
2739                                 p->origin[0] = LittleFloat(p->origin[0]);
2740                                 p->origin[1] = LittleFloat(p->origin[1]);
2741                                 p->origin[2] = LittleFloat(p->origin[2]);
2742                                 p->quat[0] = LittleFloat(p->quat[0]);
2743                                 p->quat[1] = LittleFloat(p->quat[1]);
2744                                 p->quat[2] = LittleFloat(p->quat[2]);
2745                                 p->quat[3] = LittleFloat(p->quat[3]);
2746                                 p->frametime = LittleFloat(p->frametime);
2747 #ifdef PSKQUATNEGATIONS
2748                                 if (index % numbones)
2749                                 {
2750                                         p->quat[0] *= -1;
2751                                         p->quat[1] *= -1;
2752                                         p->quat[2] *= -1;
2753                                 }
2754                                 else
2755                                 {
2756                                         p->quat[0] *=  1;
2757                                         p->quat[1] *= -1;
2758                                         p->quat[2] *=  1;
2759                                 }
2760 #endif
2761                         }
2762                         animbuffer = p;
2763                         // TODO: allocate bonepose stuff
2764                 }
2765                 else
2766                         Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2767         }
2768
2769         if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights || !numanims || !anims || !numanimkeys || !animkeys)
2770                 Host_Error("%s: missing required chunks", loadmodel->name);
2771
2772         loadmodel->numframes = 0;
2773         for (index = 0;index < numanims;index++)
2774                 loadmodel->numframes += anims[index].numframes;
2775
2776         if (numanimkeys != numbones * loadmodel->numframes)
2777                 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2778
2779         meshvertices = numvtxw;
2780         meshtriangles = numfaces;
2781
2782         // load external .skin files if present
2783         skinfiles = Mod_LoadSkinFiles();
2784         if (loadmodel->numskins < 1)
2785                 loadmodel->numskins = 1;
2786         loadmodel->num_bones = numbones;
2787         loadmodel->num_poses = loadmodel->numframes;
2788         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2789         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2790         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2791         loadmodel->surfmesh.num_vertices = meshvertices;
2792         loadmodel->surfmesh.num_triangles = meshtriangles;
2793         // do most allocations as one merged chunk
2794         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]) + loadmodel->surfmesh.num_triangles * sizeof(int[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[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);
2795         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2796         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2797         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2798         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2799         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2800         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2801         loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2802         loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2803         loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2804         loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2805         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2806         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2807         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2808         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2809         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2810         loadmodel->surfmesh.num_blends = 0;
2811         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2812         if (loadmodel->surfmesh.num_vertices <= 65536)
2813                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2814         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
2815         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2816
2817         for (i = 0;i < loadmodel->numskins;i++)
2818         {
2819                 loadmodel->skinscenes[i].firstframe = i;
2820                 loadmodel->skinscenes[i].framecount = 1;
2821                 loadmodel->skinscenes[i].loop = true;
2822                 loadmodel->skinscenes[i].framerate = 10;
2823         }
2824
2825         // create surfaces
2826         for (index = 0, i = 0;index < nummatts;index++)
2827         {
2828                 // since psk models do not have named sections, reuse their shader name as the section name
2829                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2830                 loadmodel->sortedmodelsurfaces[index] = index;
2831                 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2832                 loadmodel->data_surfaces[index].num_firstvertex = 0;
2833                 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2834         }
2835
2836         // copy over the vertex locations and texcoords
2837         for (index = 0;index < numvtxw;index++)
2838         {
2839                 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2840                 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2841                 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2842                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2843                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
2844         }
2845
2846         // loading the faces is complicated because we need to sort them into surfaces by mattindex
2847         for (index = 0;index < numfaces;index++)
2848                 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
2849         for (index = 0, i = 0;index < nummatts;index++)
2850         {
2851                 loadmodel->data_surfaces[index].num_firsttriangle = i;
2852                 i += loadmodel->data_surfaces[index].num_triangles;
2853                 loadmodel->data_surfaces[index].num_triangles = 0;
2854         }
2855         for (index = 0;index < numfaces;index++)
2856         {
2857                 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
2858                 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
2859                 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
2860                 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
2861         }
2862
2863         // copy over the bones
2864         for (index = 0;index < numbones;index++)
2865         {
2866                 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
2867                 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
2868                 if (loadmodel->data_bones[index].parent >= index)
2869                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
2870         }
2871
2872         // sort the psk point weights into the vertex weight tables
2873         // (which only accept up to 4 bones per vertex)
2874         for (index = 0;index < numvtxw;index++)
2875         {
2876                 int weightindex[4] = { 0, 0, 0, 0 };
2877                 float weightinfluence[4] = { 0, 0, 0, 0 };
2878                 int l;
2879                 for (j = 0;j < numrawweights;j++)
2880                 {
2881                         if (rawweights[j].pntsindex == vtxw[index].pntsindex)
2882                         {
2883                                 int boneindex = rawweights[j].boneindex;
2884                                 float influence = rawweights[j].weight;
2885                                 for (l = 0;l < 4;l++)
2886                                 {
2887                                         if (weightinfluence[l] < influence)
2888                                         {
2889                                                 // move lower influence weights out of the way first
2890                                                 int l2;
2891                                                 for (l2 = 3;l2 > l;l2--)
2892                                                 {
2893                                                         weightinfluence[l2] = weightinfluence[l2-1];
2894                                                         weightindex[l2] = weightindex[l2-1];
2895                                                 }
2896                                                 // store the new weight
2897                                                 weightinfluence[l] = influence;
2898                                                 weightindex[l] = boneindex;
2899                                                 break;
2900                                         }
2901                                 }
2902                         }
2903                 }
2904                 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2905         }
2906         if (loadmodel->surfmesh.num_b