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