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