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