]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - model_alias.c
Offsetmapping: new "Bias" parameter that sets a custom "null point" instead of always...
[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_DEFAULT;
789         texture->offsetscale = 1;
790         texture->offsetbias = 0;
791         texture->specularscalemod = 1;
792         texture->specularpowermod = 1;
793         texture->surfaceflags = 0;
794         texture->supercontents = SUPERCONTENTS_SOLID;
795         if (!(texture->basematerialflags & MATERIALFLAG_BLENDED))
796                 texture->supercontents |= SUPERCONTENTS_OPAQUE;
797 }
798
799 void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
800 {
801         int i;
802         static char stripbuf[MAX_QPATH];
803         skinfileitem_t *skinfileitem;
804         if(developer_extra.integer)
805                 Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername);
806         if (skinfile)
807         {
808                 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
809                 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
810                 {
811                         memset(skin, 0, sizeof(*skin));
812                         // see if a mesh
813                         for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
814                         {
815                                 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
816                                 if (!strcmp(skinfileitem->name, meshname))
817                                 {
818                                         Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
819                                         if(developer_extra.integer)
820                                                 Con_DPrintf("--> got %s from skin file\n", stripbuf);
821                                         Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
822                                         break;
823                                 }
824                         }
825                         if (!skinfileitem)
826                         {
827                                 // don't render unmentioned meshes
828                                 Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
829                                 if(developer_extra.integer)
830                                         Con_DPrintf("--> skipping\n");
831                                 skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
832                         }
833                 }
834         }
835         else
836         {
837                 if(developer_extra.integer)
838                         Con_DPrintf("--> using default\n");
839                 Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
840                 Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
841         }
842 }
843
844 #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);
845 #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);
846 void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
847 {
848         int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
849         float scales, scalet, interval;
850         msurface_t *surface;
851         unsigned char *data;
852         mdl_t *pinmodel;
853         stvert_t *pinstverts;
854         dtriangle_t *pintriangles;
855         daliasskintype_t *pinskintype;
856         daliasskingroup_t *pinskingroup;
857         daliasskininterval_t *pinskinintervals;
858         daliasframetype_t *pinframetype;
859         daliasgroup_t *pinframegroup;
860         unsigned char *datapointer, *startframes, *startskins;
861         char name[MAX_QPATH];
862         skinframe_t *tempskinframe;
863         animscene_t *tempskinscenes;
864         texture_t *tempaliasskins;
865         float *vertst;
866         int *vertonseam, *vertremap;
867         skinfile_t *skinfiles;
868
869         datapointer = (unsigned char *)buffer;
870         pinmodel = (mdl_t *)datapointer;
871         datapointer += sizeof(mdl_t);
872
873         version = LittleLong (pinmodel->version);
874         if (version != ALIAS_VERSION)
875                 Host_Error ("%s has wrong version number (%i should be %i)",
876                                  loadmodel->name, version, ALIAS_VERSION);
877
878         loadmodel->modeldatatypestring = "MDL";
879
880         loadmodel->type = mod_alias;
881         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
882         loadmodel->DrawSky = NULL;
883         loadmodel->DrawAddWaterPlanes = NULL;
884         loadmodel->Draw = R_Q1BSP_Draw;
885         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
886         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
887         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
888         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
889         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
890         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
891         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
892         loadmodel->DrawLight = R_Q1BSP_DrawLight;
893         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
894         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
895         // FIXME add TraceBrush!
896         loadmodel->PointSuperContents = NULL;
897
898         loadmodel->num_surfaces = 1;
899         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
900         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
901         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
902         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
903         loadmodel->sortedmodelsurfaces[0] = 0;
904
905         loadmodel->numskins = LittleLong(pinmodel->numskins);
906         BOUNDI(loadmodel->numskins,0,65536);
907         skinwidth = LittleLong (pinmodel->skinwidth);
908         BOUNDI(skinwidth,0,65536);
909         skinheight = LittleLong (pinmodel->skinheight);
910         BOUNDI(skinheight,0,65536);
911         numverts = LittleLong(pinmodel->numverts);
912         BOUNDI(numverts,0,65536);
913         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
914         BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
915         loadmodel->numframes = LittleLong(pinmodel->numframes);
916         BOUNDI(loadmodel->numframes,0,65536);
917         loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
918         BOUNDI((int)loadmodel->synctype,0,2);
919         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
920         i = LittleLong (pinmodel->flags);
921         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
922
923         for (i = 0;i < 3;i++)
924         {
925                 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
926                 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
927         }
928
929         startskins = datapointer;
930         totalskins = 0;
931         for (i = 0;i < loadmodel->numskins;i++)
932         {
933                 pinskintype = (daliasskintype_t *)datapointer;
934                 datapointer += sizeof(daliasskintype_t);
935                 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
936                         groupskins = 1;
937                 else
938                 {
939                         pinskingroup = (daliasskingroup_t *)datapointer;
940                         datapointer += sizeof(daliasskingroup_t);
941                         groupskins = LittleLong(pinskingroup->numskins);
942                         datapointer += sizeof(daliasskininterval_t) * groupskins;
943                 }
944
945                 for (j = 0;j < groupskins;j++)
946                 {
947                         datapointer += skinwidth * skinheight;
948                         totalskins++;
949                 }
950         }
951
952         pinstverts = (stvert_t *)datapointer;
953         datapointer += sizeof(stvert_t) * numverts;
954
955         pintriangles = (dtriangle_t *)datapointer;
956         datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
957
958         startframes = datapointer;
959         loadmodel->surfmesh.num_morphframes = 0;
960         for (i = 0;i < loadmodel->numframes;i++)
961         {
962                 pinframetype = (daliasframetype_t *)datapointer;
963                 datapointer += sizeof(daliasframetype_t);
964                 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
965                         groupframes = 1;
966                 else
967                 {
968                         pinframegroup = (daliasgroup_t *)datapointer;
969                         datapointer += sizeof(daliasgroup_t);
970                         groupframes = LittleLong(pinframegroup->numframes);
971                         datapointer += sizeof(daliasinterval_t) * groupframes;
972                 }
973
974                 for (j = 0;j < groupframes;j++)
975                 {
976                         datapointer += sizeof(daliasframe_t);
977                         datapointer += sizeof(trivertx_t) * numverts;
978                         loadmodel->surfmesh.num_morphframes++;
979                 }
980         }
981         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
982
983         // store texture coordinates into temporary array, they will be stored
984         // after usage is determined (triangle data)
985         vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
986         vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
987         vertonseam = vertremap + numverts * 2;
988
989         scales = 1.0 / skinwidth;
990         scalet = 1.0 / skinheight;
991         for (i = 0;i < numverts;i++)
992         {
993                 vertonseam[i] = LittleLong(pinstverts[i].onseam);
994                 vertst[i*2+0] = (LittleLong(pinstverts[i].s) + 0.5) * scales;
995                 vertst[i*2+1] = (LittleLong(pinstverts[i].t) + 0.5) * scalet;
996                 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
997                 vertst[(i+numverts)*2+1] = vertst[i*2+1];
998         }
999
1000 // load triangle data
1001         loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1002
1003         // read the triangle elements
1004         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1005                 for (j = 0;j < 3;j++)
1006                         loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1007         // validate (note numverts is used because this is the original data)
1008         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1009         // now butcher the elements according to vertonseam and tri->facesfront
1010         // and then compact the vertex set to remove duplicates
1011         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1012                 if (!LittleLong(pintriangles[i].facesfront)) // backface
1013                         for (j = 0;j < 3;j++)
1014                                 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1015                                         loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1016         // count the usage
1017         // (this uses vertremap to count usage to save some memory)
1018         for (i = 0;i < numverts*2;i++)
1019                 vertremap[i] = 0;
1020         for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1021                 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1022         // build remapping table and compact array
1023         loadmodel->surfmesh.num_vertices = 0;
1024         for (i = 0;i < numverts*2;i++)
1025         {
1026                 if (vertremap[i])
1027                 {
1028                         vertremap[i] = loadmodel->surfmesh.num_vertices;
1029                         vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1030                         vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1031                         loadmodel->surfmesh.num_vertices++;
1032                 }
1033                 else
1034                         vertremap[i] = -1; // not used at all
1035         }
1036         // remap the elements to the new vertex set
1037         for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1038                 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1039         // store the texture coordinates
1040         loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1041         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1042         {
1043                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1044                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1045         }
1046
1047         // generate ushort elements array if possible
1048         if (loadmodel->surfmesh.num_vertices <= 65536)
1049                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1050         if (loadmodel->surfmesh.data_element3s)
1051                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1052                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1053
1054 // load the frames
1055         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1056         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1057         if (r_enableshadowvolumes.integer)
1058         {
1059                 loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1060         }
1061         Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1062         if (loadmodel->surfmesh.data_neighbor3i)
1063                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1064         Mod_Alias_CalculateBoundingBox();
1065         Mod_Alias_MorphMesh_CompileFrames();
1066
1067         Mem_Free(vertst);
1068         Mem_Free(vertremap);
1069
1070         // load the skins
1071         skinfiles = Mod_LoadSkinFiles();
1072         if (skinfiles)
1073         {
1074                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1075                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1076                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1077                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1078                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1079                 Mod_FreeSkinFiles(skinfiles);
1080                 for (i = 0;i < loadmodel->numskins;i++)
1081                 {
1082                         loadmodel->skinscenes[i].firstframe = i;
1083                         loadmodel->skinscenes[i].framecount = 1;
1084                         loadmodel->skinscenes[i].loop = true;
1085                         loadmodel->skinscenes[i].framerate = 10;
1086                 }
1087         }
1088         else
1089         {
1090                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1091                 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1092                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1093                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1094                 totalskins = 0;
1095                 datapointer = startskins;
1096                 for (i = 0;i < loadmodel->numskins;i++)
1097                 {
1098                         pinskintype = (daliasskintype_t *)datapointer;
1099                         datapointer += sizeof(daliasskintype_t);
1100
1101                         if (pinskintype->type == ALIAS_SKIN_SINGLE)
1102                         {
1103                                 groupskins = 1;
1104                                 interval = 0.1f;
1105                         }
1106                         else
1107                         {
1108                                 pinskingroup = (daliasskingroup_t *)datapointer;
1109                                 datapointer += sizeof(daliasskingroup_t);
1110
1111                                 groupskins = LittleLong (pinskingroup->numskins);
1112
1113                                 pinskinintervals = (daliasskininterval_t *)datapointer;
1114                                 datapointer += sizeof(daliasskininterval_t) * groupskins;
1115
1116                                 interval = LittleFloat(pinskinintervals[0].interval);
1117                                 if (interval < 0.01f)
1118                                 {
1119                                         Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1120                                         interval = 0.1f;
1121                                 }
1122                         }
1123
1124                         dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1125                         loadmodel->skinscenes[i].firstframe = totalskins;
1126                         loadmodel->skinscenes[i].framecount = groupskins;
1127                         loadmodel->skinscenes[i].framerate = 1.0f / interval;
1128                         loadmodel->skinscenes[i].loop = true;
1129
1130                         for (j = 0;j < groupskins;j++)
1131                         {
1132                                 if (groupskins > 1)
1133                                         dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1134                                 else
1135                                         dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1136                                 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))
1137                                         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));
1138                                 datapointer += skinwidth * skinheight;
1139                                 totalskins++;
1140                         }
1141                 }
1142                 // check for skins that don't exist in the model, but do exist as external images
1143                 // (this was added because yummyluv kept pestering me about support for it)
1144                 // TODO: support shaders here?
1145                 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)))
1146                 {
1147                         // expand the arrays to make room
1148                         tempskinscenes = loadmodel->skinscenes;
1149                         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1150                         memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1151                         Mem_Free(tempskinscenes);
1152
1153                         tempaliasskins = loadmodel->data_textures;
1154                         loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1155                         memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1156                         Mem_Free(tempaliasskins);
1157
1158                         // store the info about the new skin
1159                         Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
1160                         strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1161                         loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1162                         loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1163                         loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1164                         loadmodel->skinscenes[loadmodel->numskins].loop = true;
1165
1166                         //increase skin counts
1167                         loadmodel->numskins++;
1168                         totalskins++;
1169
1170                         // fix up the pointers since they are pointing at the old textures array
1171                         // FIXME: this is a hack!
1172                         for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1173                                 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1174                 }
1175         }
1176
1177         surface = loadmodel->data_surfaces;
1178         surface->texture = loadmodel->data_textures;
1179         surface->num_firsttriangle = 0;
1180         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1181         surface->num_firstvertex = 0;
1182         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1183
1184         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1185
1186         if (!loadmodel->surfmesh.isanimated)
1187         {
1188                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1189                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1190                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1191                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1192                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1193                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1194         }
1195 }
1196
1197 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1198 {
1199         int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1200         float iskinwidth, iskinheight;
1201         unsigned char *data;
1202         msurface_t *surface;
1203         md2_t *pinmodel;
1204         unsigned char *base, *datapointer;
1205         md2frame_t *pinframe;
1206         char *inskin;
1207         md2triangle_t *intri;
1208         unsigned short *inst;
1209         struct md2verthash_s
1210         {
1211                 struct md2verthash_s *next;
1212                 unsigned short xyz;
1213                 unsigned short st;
1214         }
1215         *hash, **md2verthash, *md2verthashdata;
1216         skinfile_t *skinfiles;
1217
1218         pinmodel = (md2_t *)buffer;
1219         base = (unsigned char *)buffer;
1220
1221         version = LittleLong (pinmodel->version);
1222         if (version != MD2ALIAS_VERSION)
1223                 Host_Error ("%s has wrong version number (%i should be %i)",
1224                         loadmodel->name, version, MD2ALIAS_VERSION);
1225
1226         loadmodel->modeldatatypestring = "MD2";
1227
1228         loadmodel->type = mod_alias;
1229         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1230         loadmodel->DrawSky = NULL;
1231         loadmodel->DrawAddWaterPlanes = NULL;
1232         loadmodel->Draw = R_Q1BSP_Draw;
1233         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1234         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1235         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1236         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1237         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1238         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1239         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1240         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1241         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1242         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1243         loadmodel->PointSuperContents = NULL;
1244
1245         if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1246                 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1247         if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1248                 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1249         if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1250                 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1251         if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1252                 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1253
1254         end = LittleLong(pinmodel->ofs_end);
1255         if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1256                 Host_Error ("%s is not a valid model", loadmodel->name);
1257         if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1258                 Host_Error ("%s is not a valid model", loadmodel->name);
1259         if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1260                 Host_Error ("%s is not a valid model", loadmodel->name);
1261         if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1262                 Host_Error ("%s is not a valid model", loadmodel->name);
1263         if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1264                 Host_Error ("%s is not a valid model", loadmodel->name);
1265
1266         loadmodel->numskins = LittleLong(pinmodel->num_skins);
1267         numxyz = LittleLong(pinmodel->num_xyz);
1268         numst = LittleLong(pinmodel->num_st);
1269         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1270         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1271         loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1272         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1273         skinwidth = LittleLong(pinmodel->skinwidth);
1274         skinheight = LittleLong(pinmodel->skinheight);
1275         iskinwidth = 1.0f / skinwidth;
1276         iskinheight = 1.0f / skinheight;
1277
1278         loadmodel->num_surfaces = 1;
1279         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1280         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));
1281         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1282         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1283         loadmodel->sortedmodelsurfaces[0] = 0;
1284         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1285         loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1286         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1287         if (r_enableshadowvolumes.integer)
1288         {
1289                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1290         }
1291
1292         loadmodel->synctype = ST_RAND;
1293
1294         // load the skins
1295         inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1296         skinfiles = Mod_LoadSkinFiles();
1297         if (skinfiles)
1298         {
1299                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1300                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1301                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1302                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1303                 Mod_FreeSkinFiles(skinfiles);
1304         }
1305         else if (loadmodel->numskins)
1306         {
1307                 // skins found (most likely not a player model)
1308                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1309                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1310                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1311                 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1312                         Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
1313         }
1314         else
1315         {
1316                 // no skins (most likely a player model)
1317                 loadmodel->numskins = 1;
1318                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1319                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1320                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1321                 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL);
1322         }
1323
1324         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1325         for (i = 0;i < loadmodel->numskins;i++)
1326         {
1327                 loadmodel->skinscenes[i].firstframe = i;
1328                 loadmodel->skinscenes[i].framecount = 1;
1329                 loadmodel->skinscenes[i].loop = true;
1330                 loadmodel->skinscenes[i].framerate = 10;
1331         }
1332
1333         // load the triangles and stvert data
1334         inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1335         intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1336         md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1337         md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1338         // swap the triangle list
1339         loadmodel->surfmesh.num_vertices = 0;
1340         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1341         {
1342                 for (j = 0;j < 3;j++)
1343                 {
1344                         xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1345                         st = (unsigned short) LittleShort (intri[i].index_st[j]);
1346                         if (xyz >= numxyz)
1347                         {
1348                                 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1349                                 xyz = 0;
1350                         }
1351                         if (st >= numst)
1352                         {
1353                                 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1354                                 st = 0;
1355                         }
1356                         hashindex = (xyz * 256 + st) & 65535;
1357                         for (hash = md2verthash[hashindex];hash;hash = hash->next)
1358                                 if (hash->xyz == xyz && hash->st == st)
1359                                         break;
1360                         if (hash == NULL)
1361                         {
1362                                 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1363                                 hash->xyz = xyz;
1364                                 hash->st = st;
1365                                 hash->next = md2verthash[hashindex];
1366                                 md2verthash[hashindex] = hash;
1367                         }
1368                         loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1369                 }
1370         }
1371
1372         vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1373         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));
1374         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1375         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1376         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1377         {
1378                 int sts, stt;
1379                 hash = md2verthashdata + i;
1380                 vertremap[i] = hash->xyz;
1381                 sts = LittleShort(inst[hash->st*2+0]);
1382                 stt = LittleShort(inst[hash->st*2+1]);
1383                 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1384                 {
1385                         Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1386                         sts = 0;
1387                         stt = 0;
1388                 }
1389                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1390                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1391         }
1392
1393         Mem_Free(md2verthash);
1394         Mem_Free(md2verthashdata);
1395
1396         // generate ushort elements array if possible
1397         if (loadmodel->surfmesh.num_vertices <= 65536)
1398                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1399         if (loadmodel->surfmesh.data_element3s)
1400                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1401                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1402
1403         // load the frames
1404         datapointer = (base + LittleLong(pinmodel->ofs_frames));
1405         for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1406         {
1407                 int k;
1408                 trivertx_t *v;
1409                 trivertx_t *out;
1410                 pinframe = (md2frame_t *)datapointer;
1411                 datapointer += sizeof(md2frame_t);
1412                 // store the frame scale/translate into the appropriate array
1413                 for (j = 0;j < 3;j++)
1414                 {
1415                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1416                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1417                 }
1418                 // convert the vertices
1419                 v = (trivertx_t *)datapointer;
1420                 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1421                 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1422                         out[k] = v[vertremap[k]];
1423                 datapointer += numxyz * sizeof(trivertx_t);
1424
1425                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1426                 loadmodel->animscenes[i].firstframe = i;
1427                 loadmodel->animscenes[i].framecount = 1;
1428                 loadmodel->animscenes[i].framerate = 10;
1429                 loadmodel->animscenes[i].loop = true;
1430         }
1431
1432         Mem_Free(vertremap);
1433
1434         if (loadmodel->surfmesh.data_neighbor3i)
1435                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1436         Mod_Alias_CalculateBoundingBox();
1437         Mod_Alias_MorphMesh_CompileFrames();
1438
1439         surface = loadmodel->data_surfaces;
1440         surface->texture = loadmodel->data_textures;
1441         surface->num_firsttriangle = 0;
1442         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1443         surface->num_firstvertex = 0;
1444         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1445
1446         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1447
1448         if (!loadmodel->surfmesh.isanimated)
1449         {
1450                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1451                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1452                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1453                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1454                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1455                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1456         }
1457 }
1458
1459 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1460 {
1461         int i, j, k, version, meshvertices, meshtriangles;
1462         unsigned char *data;
1463         msurface_t *surface;
1464         md3modelheader_t *pinmodel;
1465         md3frameinfo_t *pinframe;
1466         md3mesh_t *pinmesh;
1467         md3tag_t *pintag;
1468         skinfile_t *skinfiles;
1469
1470         pinmodel = (md3modelheader_t *)buffer;
1471
1472         if (memcmp(pinmodel->identifier, "IDP3", 4))
1473                 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1474         version = LittleLong (pinmodel->version);
1475         if (version != MD3VERSION)
1476                 Host_Error ("%s has wrong version number (%i should be %i)",
1477                         loadmodel->name, version, MD3VERSION);
1478
1479         skinfiles = Mod_LoadSkinFiles();
1480         if (loadmodel->numskins < 1)
1481                 loadmodel->numskins = 1;
1482
1483         loadmodel->modeldatatypestring = "MD3";
1484
1485         loadmodel->type = mod_alias;
1486         loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1487         loadmodel->DrawSky = NULL;
1488         loadmodel->DrawAddWaterPlanes = NULL;
1489         loadmodel->Draw = R_Q1BSP_Draw;
1490         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1491         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1492         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1493         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1494         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1495         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1496         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1497         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1498         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1499         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1500         loadmodel->PointSuperContents = NULL;
1501         loadmodel->synctype = ST_RAND;
1502         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1503         i = LittleLong (pinmodel->flags);
1504         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1505
1506         // set up some global info about the model
1507         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1508         loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1509
1510         // make skinscenes for the skins (no groups)
1511         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1512         for (i = 0;i < loadmodel->numskins;i++)
1513         {
1514                 loadmodel->skinscenes[i].firstframe = i;
1515                 loadmodel->skinscenes[i].framecount = 1;
1516                 loadmodel->skinscenes[i].loop = true;
1517                 loadmodel->skinscenes[i].framerate = 10;
1518         }
1519
1520         // load frameinfo
1521         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1522         for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1523         {
1524                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1525                 loadmodel->animscenes[i].firstframe = i;
1526                 loadmodel->animscenes[i].framecount = 1;
1527                 loadmodel->animscenes[i].framerate = 10;
1528                 loadmodel->animscenes[i].loop = true;
1529         }
1530
1531         // load tags
1532         loadmodel->num_tagframes = loadmodel->numframes;
1533         loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1534         loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1535         for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1536         {
1537                 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1538                 for (j = 0;j < 9;j++)
1539                         loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1540                 for (j = 0;j < 3;j++)
1541                         loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1542                 //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);
1543         }
1544
1545         // load meshes
1546         meshvertices = 0;
1547         meshtriangles = 0;
1548         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)))
1549         {
1550                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1551                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1552                 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1553                         Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1554                 meshvertices += LittleLong(pinmesh->num_vertices);
1555                 meshtriangles += LittleLong(pinmesh->num_triangles);
1556         }
1557
1558         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1559         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1560         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1561         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));
1562         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1563         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1564         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1565         loadmodel->surfmesh.num_vertices = meshvertices;
1566         loadmodel->surfmesh.num_triangles = meshtriangles;
1567         loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1568         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1569         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1570         if (r_enableshadowvolumes.integer)
1571         {
1572                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1573         }
1574         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1575         loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1576         if (meshvertices <= 65536)
1577         {
1578                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1579         }
1580
1581         meshvertices = 0;
1582         meshtriangles = 0;
1583         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)))
1584         {
1585                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1586                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1587                 loadmodel->sortedmodelsurfaces[i] = i;
1588                 surface = loadmodel->data_surfaces + i;
1589                 surface->texture = loadmodel->data_textures + i;
1590                 surface->num_firsttriangle = meshtriangles;
1591                 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1592                 surface->num_firstvertex = meshvertices;
1593                 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1594                 meshvertices += surface->num_vertices;
1595                 meshtriangles += surface->num_triangles;
1596
1597                 for (j = 0;j < surface->num_triangles * 3;j++)
1598                         loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1599                 for (j = 0;j < surface->num_vertices;j++)
1600                 {
1601                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1602                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1603                 }
1604                 for (j = 0;j < loadmodel->numframes;j++)
1605                 {
1606                         const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1607                         md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1608                         for (k = 0;k < surface->num_vertices;k++, in++, out++)
1609                         {
1610                                 out->origin[0] = LittleShort(in->origin[0]);
1611                                 out->origin[1] = LittleShort(in->origin[1]);
1612                                 out->origin[2] = LittleShort(in->origin[2]);
1613                                 out->pitch = in->pitch;
1614                                 out->yaw = in->yaw;
1615                         }
1616                 }
1617
1618                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1619
1620                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1621         }
1622         if (loadmodel->surfmesh.data_element3s)
1623                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1624                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1625         if (loadmodel->surfmesh.data_neighbor3i)
1626                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1627         Mod_Alias_MorphMesh_CompileFrames();
1628         Mod_Alias_CalculateBoundingBox();
1629         Mod_FreeSkinFiles(skinfiles);
1630         Mod_MakeSortedSurfaces(loadmodel);
1631
1632         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1
1633              || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
1634
1635         if (!loadmodel->surfmesh.isanimated)
1636         {
1637                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1638                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1639                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1640                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1641                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1642                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1643         }
1644 }
1645
1646 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1647 {
1648         zymtype1header_t *pinmodel, *pheader;
1649         unsigned char *pbase;
1650         int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1651         float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1652         zymvertex_t *verts, *vertdata;
1653         zymscene_t *scene;
1654         zymbone_t *bone;
1655         char *shadername;
1656         skinfile_t *skinfiles;
1657         unsigned char *data;
1658         msurface_t *surface;
1659
1660         pinmodel = (zymtype1header_t *)buffer;
1661         pbase = (unsigned char *)buffer;
1662         if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1663                 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1664         if (BigLong(pinmodel->type) != 1)
1665                 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1666
1667         loadmodel->modeldatatypestring = "ZYM";
1668
1669         loadmodel->type = mod_alias;
1670         loadmodel->synctype = ST_RAND;
1671
1672         // byteswap header
1673         pheader = pinmodel;
1674         pheader->type = BigLong(pinmodel->type);
1675         pheader->filesize = BigLong(pinmodel->filesize);
1676         pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1677         pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1678         pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1679         pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1680         pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1681         pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1682         pheader->radius = BigFloat(pinmodel->radius);
1683         pheader->numverts = BigLong(pinmodel->numverts);
1684         pheader->numtris = BigLong(pinmodel->numtris);
1685         pheader->numshaders = BigLong(pinmodel->numshaders);
1686         pheader->numbones = BigLong(pinmodel->numbones);
1687         pheader->numscenes = BigLong(pinmodel->numscenes);
1688         pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1689         pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1690         pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1691         pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1692         pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1693         pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1694         pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1695         pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1696         pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1697         pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1698         pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1699         pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1700         pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1701         pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1702         pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1703         pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1704         pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1705         pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1706
1707         if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1708         {
1709                 Con_Printf("%s has no geometry\n", loadmodel->name);
1710                 return;
1711         }
1712         if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1713         {
1714                 Con_Printf("%s has no animations\n", loadmodel->name);
1715                 return;
1716         }
1717
1718         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1719         loadmodel->DrawSky = NULL;
1720         loadmodel->DrawAddWaterPlanes = NULL;
1721         loadmodel->Draw = R_Q1BSP_Draw;
1722         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1723         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1724         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1725         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1726         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1727         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1728         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1729         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1730         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1731         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1732         loadmodel->PointSuperContents = NULL;
1733
1734         loadmodel->numframes = pheader->numscenes;
1735         loadmodel->num_surfaces = pheader->numshaders;
1736
1737         skinfiles = Mod_LoadSkinFiles();
1738         if (loadmodel->numskins < 1)
1739                 loadmodel->numskins = 1;
1740
1741         // make skinscenes for the skins (no groups)
1742         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1743         for (i = 0;i < loadmodel->numskins;i++)
1744         {
1745                 loadmodel->skinscenes[i].firstframe = i;
1746                 loadmodel->skinscenes[i].framecount = 1;
1747                 loadmodel->skinscenes[i].loop = true;
1748                 loadmodel->skinscenes[i].framerate = 10;
1749         }
1750
1751         // model bbox
1752         modelradius = pheader->radius;
1753         for (i = 0;i < 3;i++)
1754         {
1755                 loadmodel->normalmins[i] = pheader->mins[i];
1756                 loadmodel->normalmaxs[i] = pheader->maxs[i];
1757                 loadmodel->rotatedmins[i] = -modelradius;
1758                 loadmodel->rotatedmaxs[i] = modelradius;
1759         }
1760         corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1761         corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1762         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1763         if (loadmodel->yawmaxs[0] > modelradius)
1764                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1765         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1766         loadmodel->yawmins[2] = loadmodel->normalmins[2];
1767         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1768         loadmodel->radius = modelradius;
1769         loadmodel->radius2 = modelradius * modelradius;
1770
1771         // go through the lumps, swapping things
1772
1773         //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1774         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1775         scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1776         numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1777         for (i = 0;i < pheader->numscenes;i++)
1778         {
1779                 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1780                 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1781                 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1782                 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1783                 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1784                 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1785                         Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1786                 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1787                         Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1788                 if (loadmodel->animscenes[i].framerate < 0)
1789                         Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1790                 scene++;
1791         }
1792
1793         //zymlump_t lump_bones; // zymbone_t bone[numbones];
1794         loadmodel->num_bones = pheader->numbones;
1795         loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1796         bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1797         for (i = 0;i < pheader->numbones;i++)
1798         {
1799                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1800                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1801                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1802                 if (loadmodel->data_bones[i].parent >= i)
1803                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1804         }
1805
1806         //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1807         vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1808         bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1809         for (i = 0;i < pheader->numverts;i++)
1810         {
1811                 vertbonecounts[i] = BigLong(bonecount[i]);
1812                 if (vertbonecounts[i] != 1)
1813                         Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1814         }
1815
1816         loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1817
1818         meshvertices = pheader->numverts;
1819         meshtriangles = pheader->numtris;
1820
1821         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1822         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1823         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1824         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]));
1825         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1826         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1827         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1828         loadmodel->surfmesh.num_vertices = meshvertices;
1829         loadmodel->surfmesh.num_triangles = meshtriangles;
1830         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1831         if (r_enableshadowvolumes.integer)
1832         {
1833                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1834         }
1835         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1836         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1837         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1838         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1839         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1840         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1841         loadmodel->surfmesh.num_blends = 0;
1842         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
1843         if (loadmodel->surfmesh.num_vertices <= 65536)
1844         {
1845                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1846         }
1847         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
1848         loadmodel->surfmesh.data_blendweights = NULL;
1849
1850         //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1851         poses = (float *) (pheader->lump_poses.start + pbase);
1852         // figure out scale of model from root bone, for compatibility with old zmodel versions
1853         tempvec[0] = BigFloat(poses[0]);
1854         tempvec[1] = BigFloat(poses[1]);
1855         tempvec[2] = BigFloat(poses[2]);
1856         modelscale = VectorLength(tempvec);
1857         biggestorigin = 0;
1858         for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
1859         {
1860                 f = fabs(BigFloat(poses[i]));
1861                 biggestorigin = max(biggestorigin, f);
1862         }
1863         loadmodel->num_posescale = biggestorigin / 32767.0f;
1864         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
1865         for (i = 0;i < numposes;i++)
1866         {
1867                 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
1868                 for (j = 0;j < loadmodel->num_bones;j++)
1869                 {
1870                         float pose[12];
1871                         matrix4x4_t posematrix;
1872                         for (k = 0;k < 12;k++)
1873                                 pose[k] = BigFloat(frameposes[j*12+k]);
1874                         //if (j < loadmodel->num_bones)
1875                         //      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));
1876                         // scale child bones to match the root scale
1877                         if (loadmodel->data_bones[j].parent >= 0)
1878                         {
1879                                 pose[3] *= modelscale;
1880                                 pose[7] *= modelscale;
1881                                 pose[11] *= modelscale;
1882                         }
1883                         // normalize rotation matrix
1884                         VectorNormalize(pose + 0);
1885                         VectorNormalize(pose + 4);
1886                         VectorNormalize(pose + 8);
1887                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
1888                         Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*(i*loadmodel->num_bones+j));
1889                 }
1890         }
1891
1892         //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
1893         verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
1894         vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
1895         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
1896         // (converting from weight-blending skeletal animation to
1897         //  deformation-based skeletal animation)
1898         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
1899         for (i = 0;i < loadmodel->num_bones;i++)
1900         {
1901                 float m[12];
1902                 for (k = 0;k < 12;k++)
1903                         m[k] = BigFloat(poses[i*12+k]);
1904                 if (loadmodel->data_bones[i].parent >= 0)
1905                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
1906                 else
1907                         for (k = 0;k < 12;k++)
1908                                 bonepose[12*i+k] = m[k];
1909         }
1910         for (j = 0;j < pheader->numverts;j++)
1911         {
1912                 // this format really should have had a per vertexweight weight value...
1913                 // but since it does not, the weighting is completely ignored and
1914                 // only one weight is allowed per vertex
1915                 int boneindex = BigLong(vertdata[j].bonenum);
1916                 const float *m = bonepose + 12 * boneindex;
1917                 float relativeorigin[3];
1918                 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
1919                 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
1920                 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
1921                 // transform the vertex bone weight into the base mesh
1922                 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
1923                 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
1924                 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
1925                 // store the weight as the primary weight on this vertex
1926                 loadmodel->surfmesh.blends[j] = boneindex;
1927         }
1928         Z_Free(bonepose);
1929         // normals and tangents are calculated after elements are loaded
1930
1931         //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
1932         outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
1933         intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
1934         for (i = 0;i < pheader->numverts;i++)
1935         {
1936                 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
1937                 // flip T coordinate for OpenGL
1938                 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
1939         }
1940
1941         //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
1942         //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
1943         //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
1944
1945         //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
1946         //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)
1947         // byteswap, validate, and swap winding order of tris
1948         count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
1949         if (pheader->lump_render.length != count)
1950                 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
1951         renderlist = (int *) (pheader->lump_render.start + pbase);
1952         renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
1953         meshtriangles = 0;
1954         for (i = 0;i < loadmodel->num_surfaces;i++)
1955         {
1956                 int firstvertex, lastvertex;
1957                 if (renderlist >= renderlistend)
1958                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
1959                 count = BigLong(*renderlist);renderlist++;
1960                 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
1961                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
1962
1963                 loadmodel->sortedmodelsurfaces[i] = i;
1964                 surface = loadmodel->data_surfaces + i;
1965                 surface->texture = loadmodel->data_textures + i;
1966                 surface->num_firsttriangle = meshtriangles;
1967                 surface->num_triangles = count;
1968                 meshtriangles += surface->num_triangles;
1969
1970                 // load the elements
1971                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1972                 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
1973                 {
1974                         outelements[j*3+2] = BigLong(renderlist[0]);
1975                         outelements[j*3+1] = BigLong(renderlist[1]);
1976                         outelements[j*3+0] = BigLong(renderlist[2]);
1977                 }
1978                 // validate the elements and find the used vertex range
1979                 firstvertex = meshvertices;
1980                 lastvertex = 0;
1981                 for (j = 0;j < surface->num_triangles * 3;j++)
1982                 {
1983                         if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
1984                                 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
1985                         firstvertex = min(firstvertex, outelements[j]);
1986                         lastvertex = max(lastvertex, outelements[j]);
1987                 }
1988                 surface->num_firstvertex = firstvertex;
1989                 surface->num_vertices = lastvertex + 1 - firstvertex;
1990
1991                 // since zym models do not have named sections, reuse their shader
1992                 // name as the section name
1993                 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
1994                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
1995         }
1996         Mod_FreeSkinFiles(skinfiles);
1997         Mem_Free(vertbonecounts);
1998         Mem_Free(verts);
1999         Mod_MakeSortedSurfaces(loadmodel);
2000
2001         // compute all the mesh information that was not loaded from the file
2002         if (loadmodel->surfmesh.data_element3s)
2003                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2004                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2005         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2006         Mod_BuildBaseBonePoses();
2007         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);
2008         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);
2009         if (loadmodel->surfmesh.data_neighbor3i)
2010                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2011
2012         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
2013
2014         if (!loadmodel->surfmesh.isanimated)
2015         {
2016                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2017                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2018                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2019                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2020                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2021                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2022         }
2023 }
2024
2025 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2026 {
2027         dpmheader_t *pheader;
2028         dpmframe_t *frames;
2029         dpmbone_t *bone;
2030         dpmmesh_t *dpmmesh;
2031         unsigned char *pbase;
2032         int i, j, k, meshvertices, meshtriangles;
2033         skinfile_t *skinfiles;
2034         unsigned char *data;
2035         float *bonepose;
2036         float biggestorigin, tempvec[3], modelscale;
2037         float f;
2038         float *poses;
2039
2040         pheader = (dpmheader_t *)buffer;
2041         pbase = (unsigned char *)buffer;
2042         if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2043                 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2044         if (BigLong(pheader->type) != 2)
2045                 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2046
2047         loadmodel->modeldatatypestring = "DPM";
2048
2049         loadmodel->type = mod_alias;
2050         loadmodel->synctype = ST_RAND;
2051
2052         // byteswap header
2053         pheader->type = BigLong(pheader->type);
2054         pheader->filesize = BigLong(pheader->filesize);
2055         pheader->mins[0] = BigFloat(pheader->mins[0]);
2056         pheader->mins[1] = BigFloat(pheader->mins[1]);
2057         pheader->mins[2] = BigFloat(pheader->mins[2]);
2058         pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2059         pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2060         pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2061         pheader->yawradius = BigFloat(pheader->yawradius);
2062         pheader->allradius = BigFloat(pheader->allradius);
2063         pheader->num_bones = BigLong(pheader->num_bones);
2064         pheader->num_meshs = BigLong(pheader->num_meshs);
2065         pheader->num_frames = BigLong(pheader->num_frames);
2066         pheader->ofs_bones = BigLong(pheader->ofs_bones);
2067         pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2068         pheader->ofs_frames = BigLong(pheader->ofs_frames);
2069
2070         if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2071         {
2072                 Con_Printf("%s has no geometry\n", loadmodel->name);
2073                 return;
2074         }
2075         if (pheader->num_frames < 1)
2076         {
2077                 Con_Printf("%s has no frames\n", loadmodel->name);
2078                 return;
2079         }
2080
2081         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2082         loadmodel->DrawSky = NULL;
2083         loadmodel->DrawAddWaterPlanes = NULL;
2084         loadmodel->Draw = R_Q1BSP_Draw;
2085         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2086         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2087         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2088         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2089         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2090         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2091         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2092         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2093         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2094         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2095         loadmodel->PointSuperContents = NULL;
2096
2097         // model bbox
2098         for (i = 0;i < 3;i++)
2099         {
2100                 loadmodel->normalmins[i] = pheader->mins[i];
2101                 loadmodel->normalmaxs[i] = pheader->maxs[i];
2102                 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2103                 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2104                 loadmodel->rotatedmins[i] = -pheader->allradius;
2105                 loadmodel->rotatedmaxs[i] = pheader->allradius;
2106         }
2107         loadmodel->radius = pheader->allradius;
2108         loadmodel->radius2 = pheader->allradius * pheader->allradius;
2109
2110         // load external .skin files if present
2111         skinfiles = Mod_LoadSkinFiles();
2112         if (loadmodel->numskins < 1)
2113                 loadmodel->numskins = 1;
2114
2115         meshvertices = 0;
2116         meshtriangles = 0;
2117
2118         // gather combined statistics from the meshes
2119         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2120         for (i = 0;i < (int)pheader->num_meshs;i++)
2121         {
2122                 int numverts = BigLong(dpmmesh->num_verts);
2123                 meshvertices += numverts;
2124                 meshtriangles += BigLong(dpmmesh->num_tris);
2125                 dpmmesh++;
2126         }
2127
2128         loadmodel->numframes = pheader->num_frames;
2129         loadmodel->num_bones = pheader->num_bones;
2130         loadmodel->num_poses = loadmodel->numframes;
2131         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2132         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2133         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2134         // do most allocations as one merged chunk
2135         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));
2136         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2137         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2138         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2139         loadmodel->surfmesh.num_vertices = meshvertices;
2140         loadmodel->surfmesh.num_triangles = meshtriangles;
2141         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2142         if (r_enableshadowvolumes.integer)
2143         {
2144                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2145         }
2146         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2147         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2148         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2149         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2150         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2151         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2152         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2153         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2154         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2155         loadmodel->surfmesh.num_blends = 0;
2156         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2157         if (meshvertices <= 65536)
2158         {
2159                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2160         }
2161         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
2162         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2163
2164         for (i = 0;i < loadmodel->numskins;i++)
2165         {
2166                 loadmodel->skinscenes[i].firstframe = i;
2167                 loadmodel->skinscenes[i].framecount = 1;
2168                 loadmodel->skinscenes[i].loop = true;
2169                 loadmodel->skinscenes[i].framerate = 10;
2170         }
2171
2172         // load the bone info
2173         bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2174         for (i = 0;i < loadmodel->num_bones;i++)
2175         {
2176                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2177                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2178                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2179                 if (loadmodel->data_bones[i].parent >= i)
2180                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2181         }
2182
2183         // load the frames
2184         frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2185         // figure out scale of model from root bone, for compatibility with old dpmodel versions
2186         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2187         tempvec[0] = BigFloat(poses[0]);
2188         tempvec[1] = BigFloat(poses[1]);
2189         tempvec[2] = BigFloat(poses[2]);
2190         modelscale = VectorLength(tempvec);
2191         biggestorigin = 0;
2192         for (i = 0;i < loadmodel->numframes;i++)
2193         {
2194                 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2195                 loadmodel->animscenes[i].firstframe = i;
2196                 loadmodel->animscenes[i].framecount = 1;
2197                 loadmodel->animscenes[i].loop = true;
2198                 loadmodel->animscenes[i].framerate = 10;
2199                 // load the bone poses for this frame
2200                 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2201                 for (j = 0;j < loadmodel->num_bones*12;j++)
2202                 {
2203                         f = fabs(BigFloat(poses[j]));
2204                         biggestorigin = max(biggestorigin, f);
2205                 }
2206                 // stuff not processed here: mins, maxs, yawradius, allradius
2207         }
2208         loadmodel->num_posescale = biggestorigin / 32767.0f;
2209         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2210         for (i = 0;i < loadmodel->numframes;i++)
2211         {
2212                 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2213                 for (j = 0;j < loadmodel->num_bones;j++)
2214                 {
2215                         float pose[12];
2216                         matrix4x4_t posematrix;
2217                         for (k = 0;k < 12;k++)
2218                                 pose[k] = BigFloat(frameposes[j*12+k]);
2219                         // scale child bones to match the root scale
2220                         if (loadmodel->data_bones[j].parent >= 0)
2221                         {
2222                                 pose[3] *= modelscale;
2223                                 pose[7] *= modelscale;
2224                                 pose[11] *= modelscale;
2225                         }
2226                         // normalize rotation matrix
2227                         VectorNormalize(pose + 0);
2228                         VectorNormalize(pose + 4);
2229                         VectorNormalize(pose + 8);
2230                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2231                         Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*(i*loadmodel->num_bones+j));
2232                 }
2233         }
2234
2235         // load the meshes now
2236         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2237         meshvertices = 0;
2238         meshtriangles = 0;
2239         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2240         // (converting from weight-blending skeletal animation to
2241         //  deformation-based skeletal animation)
2242         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2243         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2244         for (i = 0;i < loadmodel->num_bones;i++)
2245         {
2246                 float m[12];
2247                 for (k = 0;k < 12;k++)
2248                         m[k] = BigFloat(poses[i*12+k]);
2249                 if (loadmodel->data_bones[i].parent >= 0)
2250                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2251                 else
2252                         for (k = 0;k < 12;k++)
2253                                 bonepose[12*i+k] = m[k];
2254         }
2255         for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2256         {
2257                 const int *inelements;
2258                 int *outelements;
2259                 const float *intexcoord;
2260                 msurface_t *surface;
2261
2262                 loadmodel->sortedmodelsurfaces[i] = i;
2263                 surface = loadmodel->data_surfaces + i;
2264                 surface->texture = loadmodel->data_textures + i;
2265                 surface->num_firsttriangle = meshtriangles;
2266                 surface->num_triangles = BigLong(dpmmesh->num_tris);
2267                 surface->num_firstvertex = meshvertices;
2268                 surface->num_vertices = BigLong(dpmmesh->num_verts);
2269                 meshvertices += surface->num_vertices;
2270                 meshtriangles += surface->num_triangles;
2271
2272                 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2273                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2274                 for (j = 0;j < surface->num_triangles;j++)
2275                 {
2276                         // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2277                         outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2278                         outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2279                         outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2280                         inelements += 3;
2281                         outelements += 3;
2282                 }
2283
2284                 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2285                 for (j = 0;j < surface->num_vertices*2;j++)
2286                         loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2287
2288                 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2289                 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2290                 {
2291                         int weightindex[4] = { 0, 0, 0, 0 };
2292                         float weightinfluence[4] = { 0, 0, 0, 0 };
2293                         int l;
2294                         int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2295                         data += sizeof(dpmvertex_t);
2296                         for (k = 0;k < numweights;k++)
2297                         {
2298                                 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2299                                 int boneindex = BigLong(vert->bonenum);
2300                                 const float *m = bonepose + 12 * boneindex;
2301                                 float influence = BigFloat(vert->influence);
2302                                 float relativeorigin[3], relativenormal[3];
2303                                 relativeorigin[0] = BigFloat(vert->origin[0]);
2304                                 relativeorigin[1] = BigFloat(vert->origin[1]);
2305                                 relativeorigin[2] = BigFloat(vert->origin[2]);
2306                                 relativenormal[0] = BigFloat(vert->normal[0]);
2307                                 relativenormal[1] = BigFloat(vert->normal[1]);
2308                                 relativenormal[2] = BigFloat(vert->normal[2]);
2309                                 // blend the vertex bone weights into the base mesh
2310                                 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2311                                 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2312                                 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2313                                 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2314                                 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2315                                 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2316                                 if (!k)
2317                                 {
2318                                         // store the first (and often only) weight
2319                                         weightinfluence[0] = influence;
2320                                         weightindex[0] = boneindex;
2321                                 }
2322                                 else
2323                                 {
2324                                         // sort the new weight into this vertex's weight table
2325                                         // (which only accepts up to 4 bones per vertex)
2326                                         for (l = 0;l < 4;l++)
2327                                         {
2328                                                 if (weightinfluence[l] < influence)
2329                                                 {
2330                                                         // move weaker influence weights out of the way first
2331                                                         int l2;
2332                                                         for (l2 = 3;l2 > l;l2--)
2333                                                         {
2334                                                                 weightinfluence[l2] = weightinfluence[l2-1];
2335                                                                 weightindex[l2] = weightindex[l2-1];
2336                                                         }
2337                                                         // store the new weight
2338                                                         weightinfluence[l] = influence;
2339                                                         weightindex[l] = boneindex;
2340                                                         break;
2341                                                 }
2342                                         }
2343                                 }
2344                                 data += sizeof(dpmbonevert_t);
2345                         }
2346                         loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2347                 }
2348
2349                 // since dpm models do not have named sections, reuse their shader name as the section name
2350                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2351
2352                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2353         }
2354         if (loadmodel->surfmesh.num_blends < meshvertices)
2355                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2356         Z_Free(bonepose);
2357         Mod_FreeSkinFiles(skinfiles);
2358         Mod_MakeSortedSurfaces(loadmodel);
2359
2360         // compute all the mesh information that was not loaded from the file
2361         if (loadmodel->surfmesh.data_element3s)
2362                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2363                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2364         Mod_BuildBaseBonePoses();
2365         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);
2366         if (loadmodel->surfmesh.data_neighbor3i)
2367                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2368
2369         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
2370
2371         if (!loadmodel->surfmesh.isanimated)
2372         {
2373                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2374                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2375                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2376                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2377                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2378                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2379         }
2380 }
2381
2382 // no idea why PSK/PSA files contain weird quaternions but they do...
2383 #define PSKQUATNEGATIONS
2384 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2385 {
2386         int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2387         int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2388         fs_offset_t filesize;
2389         pskpnts_t *pnts;
2390         pskvtxw_t *vtxw;
2391         pskface_t *faces;
2392         pskmatt_t *matts;
2393         pskboneinfo_t *bones;
2394         pskrawweights_t *rawweights;
2395         //pskboneinfo_t *animbones;
2396         pskaniminfo_t *anims;
2397         pskanimkeys_t *animkeys;
2398         void *animfilebuffer, *animbuffer, *animbufferend;
2399         unsigned char *data;
2400         pskchunk_t *pchunk;
2401         skinfile_t *skinfiles;
2402         char animname[MAX_QPATH];
2403         size_t size;
2404         float biggestorigin;
2405
2406         pchunk = (pskchunk_t *)buffer;
2407         if (strcmp(pchunk->id, "ACTRHEAD"))
2408                 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2409
2410         loadmodel->modeldatatypestring = "PSK";
2411
2412         loadmodel->type = mod_alias;
2413         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2414         loadmodel->DrawSky = NULL;
2415         loadmodel->DrawAddWaterPlanes = NULL;
2416         loadmodel->Draw = R_Q1BSP_Draw;
2417         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2418         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2419         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2420         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2421         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2422         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2423         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2424         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2425         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2426         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2427         loadmodel->PointSuperContents = NULL;
2428         loadmodel->synctype = ST_RAND;
2429
2430         FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2431         strlcat(animname, ".psa", sizeof(animname));
2432         animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2433         animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2434         if (animbuffer == NULL)
2435                 Host_Error("%s: can't find .psa file (%s)", loadmodel->name, animname);
2436
2437         numpnts = 0;
2438         pnts = NULL;
2439         numvtxw = 0;
2440         vtxw = NULL;
2441         numfaces = 0;
2442         faces = NULL;
2443         nummatts = 0;
2444         matts = NULL;
2445         numbones = 0;
2446         bones = NULL;
2447         numrawweights = 0;
2448         rawweights = NULL;
2449         numanims = 0;
2450         anims = NULL;
2451         numanimkeys = 0;
2452         animkeys = NULL;
2453
2454         while (buffer < bufferend)
2455         {
2456                 pchunk = (pskchunk_t *)buffer;
2457                 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2458                 version = LittleLong(pchunk->version);
2459                 recordsize = LittleLong(pchunk->recordsize);
2460                 numrecords = LittleLong(pchunk->numrecords);
2461                 if (developer_extra.integer)
2462                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2463                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2464                         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);
2465                 if (!strcmp(pchunk->id, "ACTRHEAD"))
2466                 {
2467                         // nothing to do
2468                 }
2469                 else if (!strcmp(pchunk->id, "PNTS0000"))
2470                 {
2471                         pskpnts_t *p;
2472                         if (recordsize != sizeof(*p))
2473                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2474                         // byteswap in place and keep the pointer
2475                         numpnts = numrecords;
2476                         pnts = (pskpnts_t *)buffer;
2477                         for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2478                         {
2479                                 p->origin[0] = LittleFloat(p->origin[0]);
2480                                 p->origin[1] = LittleFloat(p->origin[1]);
2481                                 p->origin[2] = LittleFloat(p->origin[2]);
2482                         }
2483                         buffer = p;
2484                 }
2485                 else if (!strcmp(pchunk->id, "VTXW0000"))
2486                 {
2487                         pskvtxw_t *p;
2488                         if (recordsize != sizeof(*p))
2489                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2490                         // byteswap in place and keep the pointer
2491                         numvtxw = numrecords;
2492                         vtxw = (pskvtxw_t *)buffer;
2493                         for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2494                         {
2495                                 p->pntsindex = LittleShort(p->pntsindex);
2496                                 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2497                                 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2498                                 if (p->pntsindex >= numpnts)
2499                                 {
2500                                         Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2501                                         p->pntsindex = 0;
2502                                 }
2503                         }
2504                         buffer = p;
2505                 }
2506                 else if (!strcmp(pchunk->id, "FACE0000"))
2507                 {
2508                         pskface_t *p;
2509                         if (recordsize != sizeof(*p))
2510                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2511                         // byteswap in place and keep the pointer
2512                         numfaces = numrecords;
2513                         faces = (pskface_t *)buffer;
2514                         for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2515                         {
2516                                 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2517                                 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2518                                 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2519                                 p->group = LittleLong(p->group);
2520                                 if (p->vtxwindex[0] >= numvtxw)
2521                                 {
2522                                         Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2523                                         p->vtxwindex[0] = 0;
2524                                 }
2525                                 if (p->vtxwindex[1] >= numvtxw)
2526                                 {
2527                                         Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2528                                         p->vtxwindex[1] = 0;
2529                                 }
2530                                 if (p->vtxwindex[2] >= numvtxw)
2531                                 {
2532                                         Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2533                                         p->vtxwindex[2] = 0;
2534                                 }
2535                         }
2536                         buffer = p;
2537                 }
2538                 else if (!strcmp(pchunk->id, "MATT0000"))
2539                 {
2540                         pskmatt_t *p;
2541                         if (recordsize != sizeof(*p))
2542                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2543                         // byteswap in place and keep the pointer
2544                         nummatts = numrecords;
2545                         matts = (pskmatt_t *)buffer;
2546                         for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2547                         {
2548                                 // nothing to do
2549                         }
2550                         buffer = p;
2551                 }
2552                 else if (!strcmp(pchunk->id, "REFSKELT"))
2553                 {
2554                         pskboneinfo_t *p;
2555                         if (recordsize != sizeof(*p))
2556                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2557                         // byteswap in place and keep the pointer
2558                         numbones = numrecords;
2559                         bones = (pskboneinfo_t *)buffer;
2560                         for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2561                         {
2562                                 p->numchildren = LittleLong(p->numchildren);
2563                                 p->parent = LittleLong(p->parent);
2564                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2565                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2566                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2567                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2568                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2569                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2570                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2571                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2572                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2573                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2574                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2575 #ifdef PSKQUATNEGATIONS
2576                                 if (index)
2577                                 {
2578                                         p->basepose.quat[0] *= -1;
2579                                         p->basepose.quat[1] *= -1;
2580                                         p->basepose.quat[2] *= -1;
2581                                 }
2582                                 else
2583                                 {
2584                                         p->basepose.quat[0] *=  1;
2585                                         p->basepose.quat[1] *= -1;
2586                                         p->basepose.quat[2] *=  1;
2587                                 }
2588 #endif
2589                                 if (p->parent < 0 || p->parent >= numbones)
2590                                 {
2591                                         Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2592                                         p->parent = 0;
2593                                 }
2594                         }
2595                         buffer = p;
2596                 }
2597                 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2598                 {
2599                         pskrawweights_t *p;
2600                         if (recordsize != sizeof(*p))
2601                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2602                         // byteswap in place and keep the pointer
2603                         numrawweights = numrecords;
2604                         rawweights = (pskrawweights_t *)buffer;
2605                         for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2606                         {
2607                                 p->weight = LittleFloat(p->weight);
2608                                 p->pntsindex = LittleLong(p->pntsindex);
2609                                 p->boneindex = LittleLong(p->boneindex);
2610                                 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2611                                 {
2612                                         Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2613                                         p->pntsindex = 0;
2614                                 }
2615                                 if (p->boneindex < 0 || p->boneindex >= numbones)
2616                                 {
2617                                         Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2618                                         p->boneindex = 0;
2619                                 }
2620                         }
2621                         buffer = p;
2622                 }
2623         }
2624
2625         while (animbuffer < animbufferend)
2626         {
2627                 pchunk = (pskchunk_t *)animbuffer;
2628                 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2629                 version = LittleLong(pchunk->version);
2630                 recordsize = LittleLong(pchunk->recordsize);
2631                 numrecords = LittleLong(pchunk->numrecords);
2632                 if (developer_extra.integer)
2633                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2634                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2635                         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);
2636                 if (!strcmp(pchunk->id, "ANIMHEAD"))
2637                 {
2638                         // nothing to do
2639                 }
2640                 else if (!strcmp(pchunk->id, "BONENAMES"))
2641                 {
2642                         pskboneinfo_t *p;
2643                         if (recordsize != sizeof(*p))
2644                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2645                         // byteswap in place and keep the pointer
2646                         numanimbones = numrecords;
2647                         //animbones = (pskboneinfo_t *)animbuffer;
2648                         // NOTE: supposedly psa does not need to match the psk model, the
2649                         // bones missing from the psa would simply use their base
2650                         // positions from the psk, but this is hard for me to implement
2651                         // and people can easily make animations that match.
2652                         if (numanimbones != numbones)
2653                                 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2654                         for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2655                         {
2656                                 p->numchildren = LittleLong(p->numchildren);
2657                                 p->parent = LittleLong(p->parent);
2658                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2659                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2660                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2661                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2662                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2663                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2664                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2665                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2666                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2667                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2668                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2669 #ifdef PSKQUATNEGATIONS
2670                                 if (index)
2671                                 {
2672                                         p->basepose.quat[0] *= -1;
2673                                         p->basepose.quat[1] *= -1;
2674                                         p->basepose.quat[2] *= -1;
2675                                 }
2676                                 else
2677                                 {
2678                                         p->basepose.quat[0] *=  1;
2679                                         p->basepose.quat[1] *= -1;
2680                                         p->basepose.quat[2] *=  1;
2681                                 }
2682 #endif
2683                                 if (p->parent < 0 || p->parent >= numanimbones)
2684                                 {
2685                                         Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2686                                         p->parent = 0;
2687                                 }
2688                                 // check that bones are the same as in the base
2689                                 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2690                                         Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2691                         }
2692                         animbuffer = p;
2693                 }
2694                 else if (!strcmp(pchunk->id, "ANIMINFO"))
2695                 {
2696                         pskaniminfo_t *p;
2697                         if (recordsize != sizeof(*p))
2698                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2699                         // byteswap in place and keep the pointer
2700                         numanims = numrecords;
2701                         anims = (pskaniminfo_t *)animbuffer;
2702                         for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2703                         {
2704                                 p->numbones = LittleLong(p->numbones);
2705                                 p->playtime = LittleFloat(p->playtime);
2706                                 p->fps = LittleFloat(p->fps);
2707                                 p->firstframe = LittleLong(p->firstframe);
2708                                 p->numframes = LittleLong(p->numframes);
2709                                 if (p->numbones != numbones)
2710                                         Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2711                         }
2712                         animbuffer = p;
2713                 }
2714                 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2715                 {
2716                         pskanimkeys_t *p;
2717                         if (recordsize != sizeof(*p))
2718                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2719                         numanimkeys = numrecords;
2720                         animkeys = (pskanimkeys_t *)animbuffer;
2721                         for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2722                         {
2723                                 p->origin[0] = LittleFloat(p->origin[0]);
2724                                 p->origin[1] = LittleFloat(p->origin[1]);
2725                                 p->origin[2] = LittleFloat(p->origin[2]);
2726                                 p->quat[0] = LittleFloat(p->quat[0]);
2727                                 p->quat[1] = LittleFloat(p->quat[1]);
2728                                 p->quat[2] = LittleFloat(p->quat[2]);
2729                                 p->quat[3] = LittleFloat(p->quat[3]);
2730                                 p->frametime = LittleFloat(p->frametime);
2731 #ifdef PSKQUATNEGATIONS
2732                                 if (index % numbones)
2733                                 {
2734                                         p->quat[0] *= -1;
2735                                         p->quat[1] *= -1;
2736                                         p->quat[2] *= -1;
2737                                 }
2738                                 else
2739                                 {
2740                                         p->quat[0] *=  1;
2741                                         p->quat[1] *= -1;
2742                                         p->quat[2] *=  1;
2743                                 }
2744 #endif
2745                         }
2746                         animbuffer = p;
2747                         // TODO: allocate bonepose stuff
2748                 }
2749                 else
2750                         Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2751         }
2752
2753         if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights || !numanims || !anims || !numanimkeys || !animkeys)
2754                 Host_Error("%s: missing required chunks", loadmodel->name);
2755
2756         loadmodel->numframes = 0;
2757         for (index = 0;index < numanims;index++)
2758                 loadmodel->numframes += anims[index].numframes;
2759
2760         if (numanimkeys != numbones * loadmodel->numframes)
2761                 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2762
2763         meshvertices = numvtxw;
2764         meshtriangles = numfaces;
2765
2766         // load external .skin files if present
2767         skinfiles = Mod_LoadSkinFiles();
2768         if (loadmodel->numskins < 1)
2769                 loadmodel->numskins = 1;
2770         loadmodel->num_bones = numbones;
2771         loadmodel->num_poses = loadmodel->numframes;
2772         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2773         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2774         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2775         loadmodel->surfmesh.num_vertices = meshvertices;
2776         loadmodel->surfmesh.num_triangles = meshtriangles;
2777         // do most allocations as one merged chunk
2778         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);
2779         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2780         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2781         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2782         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2783         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2784         if (r_enableshadowvolumes.integer)
2785         {
2786                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2787         }
2788         loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2789         loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2790         loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2791         loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2792         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2793         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2794         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2795         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2796         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2797         loadmodel->surfmesh.num_blends = 0;
2798         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2799         if (loadmodel->surfmesh.num_vertices <= 65536)
2800         {
2801                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2802         }
2803         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
2804         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2805
2806         for (i = 0;i < loadmodel->numskins;i++)
2807         {
2808                 loadmodel->skinscenes[i].firstframe = i;
2809                 loadmodel->skinscenes[i].framecount = 1;
2810                 loadmodel->skinscenes[i].loop = true;
2811                 loadmodel->skinscenes[i].framerate = 10;
2812         }
2813
2814         // create surfaces
2815         for (index = 0, i = 0;index < nummatts;index++)
2816         {
2817                 // since psk models do not have named sections, reuse their shader name as the section name
2818                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2819                 loadmodel->sortedmodelsurfaces[index] = index;
2820                 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2821                 loadmodel->data_surfaces[index].num_firstvertex = 0;
2822                 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2823         }
2824
2825         // copy over the vertex locations and texcoords
2826         for (index = 0;index < numvtxw;index++)
2827         {
2828                 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2829                 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2830                 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2831                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2832                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
2833         }
2834
2835         // loading the faces is complicated because we need to sort them into surfaces by mattindex
2836         for (index = 0;index < numfaces;index++)
2837                 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
2838         for (index = 0, i = 0;index < nummatts;index++)
2839         {
2840                 loadmodel->data_surfaces[index].num_firsttriangle = i;
2841                 i += loadmodel->data_surfaces[index].num_triangles;
2842                 loadmodel->data_surfaces[index].num_triangles = 0;
2843         }
2844         for (index = 0;index < numfaces;index++)
2845         {
2846                 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
2847                 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
2848                 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
2849                 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
2850         }
2851
2852         // copy over the bones
2853         for (index = 0;index < numbones;index++)
2854         {
2855                 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
2856                 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
2857                 if (loadmodel->data_bones[index].parent >= index)
2858                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
2859         }
2860
2861         // sort the psk point weights into the vertex weight tables
2862         // (which only accept up to 4 bones per vertex)
2863         for (index = 0;index < numvtxw;index++)
2864         {
2865                 int weightindex[4] = { 0, 0, 0, 0 };
2866                 float weightinfluence[4] = { 0, 0, 0, 0 };
2867                 int l;
2868                 for (j = 0;j < numrawweights;j++)
2869                 {
2870                         if (rawweights[j].pntsindex == vtxw[index].pntsindex)
2871                         {
2872                                 int boneindex = rawweights[j].boneindex;
2873                                 float influence = rawweights[j].weight;
2874                                 for (l = 0;l < 4;l++)
2875                                 {
2876                                         if (weightinfluence[l] < influence)
2877                                         {
2878                                                 // move lower influence weights out of the way first
2879                                                 int l2;
2880                                                 for (l2 = 3;l2 > l;l2--)
2881                                                 {
2882                                                         weightinfluence[l2] = weightinfluence[l2-1];
2883                                                         weightindex[l2] = weightindex[l2-1];
2884                                                 }
2885                                                 // store the new weight
2886                                                 weightinfluence[l] = influence;
2887                                                 weightindex[l] = boneindex;
2888                                                 break;
2889                                         }
2890                                 }
2891                         }
2892                 }
2893                 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2894         }
2895         if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
2896                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2897
2898         // set up the animscenes based on the anims
2899         for (index = 0, i = 0;index < numanims;index++)
2900         {
2901                 for (j = 0;j < anims[index].numframes;j++, i++)
2902                 {
2903                         dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
2904                         loadmodel->animscenes[i].firstframe = i;
2905                         loadmodel->animscenes[i].framecount = 1;
2906                         loadmodel->animscenes[i].loop = true;
2907                         loadmodel->animscenes[i].framerate = anims[index].fps;
2908                 }
2909         }
2910
2911         // calculate the scaling value for bone origins so they can be compressed to short
2912         biggestorigin = 0;
2913         for (index = 0;index < numanimkeys;index++)
2914         {
2915                 pskanimkeys_t *k = animkeys + index;
2916                 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
2917                 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
2918                 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
2919         }
2920         loadmodel->num_posescale = biggestorigin / 32767.0f;
2921         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2922
2923         // load the poses from the animkeys
2924         for (index = 0;index < numanimkeys;index++)
2925         {
2926                 pskanimkeys_t *k = animkeys + index;
2927                 float quat[4];
2928                 Vector4Copy(k->quat, quat);
2929                 if (quat[3] > 0)
2930                         Vector4Negate(quat, quat);
2931                 Vector4Normalize2(quat, quat);
2932                 // compress poses to the short[6] format for longterm storage
2933                 loadmodel->data_poses6s[index*6+0] = k->origin[0] * loadmodel->num_poseinvscale;
2934                 loadmodel->data_poses6s[index*6+1] = k->origin[1] * loadmodel->num_poseinvscale;
2935                 loadmodel->data_poses6s[index*6+2] = k->origin[2] * loadmodel->num_poseinvscale;
2936                 loadmodel->data_poses6s[index*6+3] = quat[0] * 32767.0f;
2937                 loadmodel->data_poses6s[index*6+4] = quat[1] * 32767.0f;
2938                 loadmodel->data_poses6s[index*6+5] = quat[2] * 32767.0f;
2939         }
2940         Mod_FreeSkinFiles(skinfiles);
2941         Mem_Free(animfilebuffer);
2942         Mod_MakeSortedSurfaces(loadmodel);
2943
2944         // compute all the mesh information that was not loaded from the file
2945         // TODO: honor smoothing groups somehow?
2946         if (loadmodel->surfmesh.data_element3s)
2947                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2948                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2949         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2950         Mod_BuildBaseBonePoses();
2951         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);
2952         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);
2953         if (loadmodel->surfmesh.data_neighbor3i)
2954                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2955         Mod_Alias_CalculateBoundingBox();
2956
2957         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
2958
2959         if (!loadmodel->surfmesh.isanimated)
2960         {
2961                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2962                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2963                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2964                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2965                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2966                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2967         }
2968 }
2969
2970 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2971 {
2972         unsigned char *data;
2973         const char *text;
2974         const unsigned char *pbase, *pend;
2975         iqmheader_t header;
2976         skinfile_t *skinfiles;
2977         int i, j, k, meshvertices, meshtriangles;
2978         float biggestorigin;
2979         const unsigned int *inelements;
2980         int *outelements;
2981         const int *inneighbors;
2982         int *outneighbors;
2983         float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector;
2984         // this pointers into the file data are read only through Little* functions so they can be unaligned memory
2985         const float *vnormal = NULL;
2986         const float *vposition = NULL;
2987         const float *vtangent = NULL;
2988         const float *vtexcoord = NULL;
2989         const unsigned char *vblendindexes = NULL;
2990         const unsigned char *vblendweights = NULL;
2991         const unsigned short *framedata = NULL;
2992         // temporary memory allocations (because the data in the file may be misaligned)
2993         iqmanim_t *anims = NULL;
2994         iqmbounds_t *bounds = NULL;
2995         iqmjoint1_t *joint1 = NULL;
2996         iqmjoint_t *joint = NULL;
2997         iqmmesh_t *meshes = NULL;
2998         iqmpose1_t *pose1 = NULL;
2999         iqmpose_t *pose = NULL;
3000         iqmvertexarray_t *vas = NULL;
3001
3002         pbase = (unsigned char *)buffer;
3003         pend = (unsigned char *)bufferend;
3004
3005         if (pbase + sizeof(iqmheader_t) > pend)
3006                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3007
3008         // copy struct (otherwise it may be misaligned)
3009         // LordHavoc: okay it's definitely not misaligned here, but for consistency...
3010         memcpy(&header, pbase, sizeof(iqmheader_t));
3011
3012         if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3013                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3014         if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3015                 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3016
3017         loadmodel->modeldatatypestring = "IQM";
3018
3019         loadmodel->type = mod_alias;
3020         loadmodel->synctype = ST_RAND;
3021
3022         // byteswap header
3023         header.version = LittleLong(header.version);
3024         header.filesize = LittleLong(header.filesize);
3025         header.flags = LittleLong(header.flags);
3026         header.num_text = LittleLong(header.num_text);
3027         header.ofs_text = LittleLong(header.ofs_text);
3028         header.num_meshes = LittleLong(header.num_meshes);
3029         header.ofs_meshes = LittleLong(header.ofs_meshes);
3030         header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3031         header.num_vertexes = LittleLong(header.num_vertexes);
3032         header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3033         header.num_triangles = LittleLong(header.num_triangles);
3034         header.ofs_triangles = LittleLong(header.ofs_triangles);
3035         header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3036         header.num_joints = LittleLong(header.num_joints);
3037         header.ofs_joints = LittleLong(header.ofs_joints);
3038         header.num_poses = LittleLong(header.num_poses);
3039         header.ofs_poses = LittleLong(header.ofs_poses);
3040         header.num_anims = LittleLong(header.num_anims);
3041         header.ofs_anims = LittleLong(header.ofs_anims);
3042         header.num_frames = LittleLong(header.num_frames);
3043         header.num_framechannels = LittleLong(header.num_framechannels);
3044         header.ofs_frames = LittleLong(header.ofs_frames);
3045         header.ofs_bounds = LittleLong(header.ofs_bounds);
3046         header.num_comment = LittleLong(header.num_comment);
3047         header.ofs_comment = LittleLong(header.ofs_comment);
3048         header.num_extensions = LittleLong(header.num_extensions);
3049         header.ofs_extensions = LittleLong(header.ofs_extensions);
3050
3051         if (header.num_triangles < 1 || header.num_vertexes < 3 || header.num_vertexarrays < 1 || header.num_meshes < 1)
3052         {
3053                 Con_Printf("%s has no geometry\n", loadmodel->name);
3054                 return;
3055         }
3056
3057         if (header.version == 1)
3058         {
3059                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3060                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3061                 {
3062                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3063                         return;
3064                 }
3065         }
3066         else
3067         {
3068                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3069                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3070                 {
3071                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3072                         return;
3073                 }
3074         }
3075         if (pbase + header.ofs_text + header.num_text > pend ||
3076                 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3077                 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3078                 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3079                 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3080                 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3081                 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3082                 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3083                 pbase + header.ofs_comment + header.num_comment > pend)
3084         {
3085                 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3086                 return;
3087         }
3088
3089         // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3090         if (header.num_vertexarrays)
3091                 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3092         if (header.num_anims)
3093                 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3094         if (header.ofs_bounds)
3095                 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3096         if (header.num_meshes)
3097                 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3098
3099         for (i = 0;i < (int)header.num_vertexarrays;i++)
3100         {
3101                 iqmvertexarray_t va;
3102                 size_t vsize;
3103                 va.type = LittleLong(vas[i].type);
3104                 va.flags = LittleLong(vas[i].flags);
3105                 va.format = LittleLong(vas[i].format);
3106                 va.size = LittleLong(vas[i].size);
3107                 va.offset = LittleLong(vas[i].offset);
3108                 vsize = header.num_vertexes*va.size;
3109                 switch (va.format)
3110                 { 
3111                 case IQM_FLOAT: vsize *= sizeof(float); break;
3112                 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3113                 default: continue;
3114                 }
3115                 if (pbase + va.offset + vsize > pend)
3116                         continue;
3117                 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3118                 switch (va.type)
3119                 {
3120                 case IQM_POSITION:
3121                         if (va.format == IQM_FLOAT && va.size == 3)
3122                                 vposition = (const float *)(pbase + va.offset);
3123                         break;
3124                 case IQM_TEXCOORD:
3125                         if (va.format == IQM_FLOAT && va.size == 2)
3126                                 vtexcoord = (const float *)(pbase + va.offset);
3127                         break;
3128                 case IQM_NORMAL:
3129                         if (va.format == IQM_FLOAT && va.size == 3)
3130                                 vnormal = (const float *)(pbase + va.offset);
3131                         break;
3132                 case IQM_TANGENT:
3133                         if (va.format == IQM_FLOAT && va.size == 4)
3134                                 vtangent = (const float *)(pbase + va.offset);
3135                         break;
3136                 case IQM_BLENDINDEXES:
3137                         if (va.format == IQM_UBYTE && va.size == 4)
3138                                 vblendindexes = (const unsigned char *)(pbase + va.offset);
3139                         break;
3140                 case IQM_BLENDWEIGHTS:
3141                         if (va.format == IQM_UBYTE && va.size == 4)
3142                                 vblendweights = (const unsigned char *)(pbase + va.offset);
3143                         break;
3144                 }
3145         }
3146         if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3147         {
3148                 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3149                 return;
3150         }
3151
3152         text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3153
3154         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3155         loadmodel->DrawSky = NULL;
3156         loadmodel->DrawAddWaterPlanes = NULL;
3157         loadmodel->Draw = R_Q1BSP_Draw;
3158         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
3159         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
3160         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
3161         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
3162         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
3163         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
3164         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
3165         loadmodel->DrawLight = R_Q1BSP_DrawLight;
3166         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3167         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3168         loadmodel->PointSuperContents = NULL;
3169
3170         // load external .skin files if present
3171         skinfiles = Mod_LoadSkinFiles();
3172         if (loadmodel->numskins < 1)
3173                 loadmodel->numskins = 1;
3174
3175         loadmodel->numframes = max(header.num_anims, 1);
3176         loadmodel->num_bones = header.num_joints;
3177         loadmodel->num_poses = max(header.num_frames, 1);
3178         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
3179         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3180         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3181
3182         meshvertices = header.num_vertexes;
3183         meshtriangles = header.num_triangles;
3184
3185         // do most allocations as one merged chunk
3186         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]) + (vblendindexes && vblendweights ? meshvertices * sizeof(unsigned short) : 0) + 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));
3187         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3188         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3189         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3190         loadmodel->surfmesh.num_vertices = meshvertices;
3191         loadmodel->surfmesh.num_triangles = meshtriangles;
3192         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3193         if (r_enableshadowvolumes.integer)
3194         {
3195                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3196         }
3197         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3198         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3199         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3200         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3201         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3202         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3203         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3204         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3205         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3206         if (vblendindexes && vblendweights)
3207         {
3208                 loadmodel->surfmesh.num_blends = 0;
3209                 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3210         }
3211         if (meshvertices <= 65536)
3212         {
3213                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3214         }
3215         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
3216         if (vblendindexes && vblendweights)
3217                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3218
3219         for (i = 0;i < loadmodel->numskins;i++)
3220         {
3221                 loadmodel->skinscenes[i].firstframe = i;
3222                 loadmodel->skinscenes[i].framecount = 1;
3223                 loadmodel->skinscenes[i].loop = true;
3224                 loadmodel->skinscenes[i].framerate = 10;
3225         }
3226
3227         // load the bone info
3228         if (header.version == 1)
3229         {
3230                 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3231                 if (loadmodel->num_bones)
3232                         joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3233                 for (i = 0;i < loadmodel->num_bones;i++)
3234                 {
3235                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3236                         joint1[i].name = LittleLong(injoint1[i].name);
3237                         joint1[i].parent = LittleLong(injoint1[i].parent);
3238                         for (j = 0;j < 3;j++)
3239                         {
3240                                 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3241                                 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3242                                 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3243                         }
3244                         strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3245                         loadmodel->data_bones[i].parent = joint1[i].parent;
3246                         if (loadmodel->data_bones[i].parent >= i)
3247                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3248                         Matrix4x4_FromDoom3Joint(&relbase, joint1[i].origin[0], joint1[i].origin[1], joint1[i].origin[2], joint1[i].rotation[0], joint1[i].rotation[1], joint1[i].rotation[2]);
3249                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3250                         if (loadmodel->data_bones[i].parent >= 0)
3251                         {
3252                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3253                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3254                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3255                         }
3256                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3257                 }
3258         }
3259         else
3260         {
3261                 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3262                 if (header.num_joints)
3263                         joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3264                 for (i = 0;i < loadmodel->num_bones;i++)
3265                 {
3266                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3267                         joint[i].name = LittleLong(injoint[i].name);
3268                         joint[i].parent = LittleLong(injoint[i].parent);
3269                         for (j = 0;j < 3;j++)
3270                         {
3271                                 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3272                                 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3273                                 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3274                         }
3275                         joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3276                         strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3277                         loadmodel->data_bones[i].parent = joint[i].parent;
3278                         if (loadmodel->data_bones[i].parent >= i)
3279                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3280                         if (joint[i].rotation[3] > 0)
3281                                 Vector4Negate(joint[i].rotation, joint[i].rotation);
3282                         Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3283                         Matrix4x4_FromDoom3Joint(&relbase, joint[i].origin[0], joint[i].origin[1], joint[i].origin[2], joint[i].rotation[0], joint[i].rotation[1], joint[i].rotation[2]);
3284                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3285                         if (loadmodel->data_bones[i].parent >= 0)
3286                         {
3287                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3288                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3289                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3290                         }       
3291                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3292                 }
3293         }
3294
3295         // set up the animscenes based on the anims
3296         for (i = 0;i < (int)header.num_anims;i++)
3297         {
3298                 iqmanim_t anim;
3299                 anim.name = LittleLong(anims[i].name);
3300                 anim.first_frame = LittleLong(anims[i].first_frame);
3301                 anim.num_frames = LittleLong(anims[i].num_frames);
3302                 anim.framerate = LittleFloat(anims[i].framerate);
3303                 anim.flags = LittleLong(anims[i].flags);
3304                 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3305                 loadmodel->animscenes[i].firstframe = anim.first_frame;
3306                 loadmodel->animscenes[i].framecount = anim.num_frames;
3307                 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3308                 loadmodel->animscenes[i].framerate = anim.framerate;
3309         }
3310         if (header.num_anims <= 0)
3311         {
3312                 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3313                 loadmodel->animscenes[0].firstframe = 0;
3314                 loadmodel->animscenes[0].framecount = 1;
3315                 loadmodel->animscenes[0].loop = true;
3316                 loadmodel->animscenes[0].framerate = 10;
3317         }
3318
3319         biggestorigin = 0;
3320         if (header.version == 1)
3321         {
3322                 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3323                 if (header.num_poses)
3324                         pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3325                 for (i = 0;i < (int)header.num_poses;i++)
3326                 {
3327                         float f;
3328                         pose1[i].parent = LittleLong(inpose1[i].parent);
3329                         pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3330                         for (j = 0;j < 9;j++)
3331                         {
3332                                 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3333                                 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3334                         }
3335                         f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3336                         f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3337                         f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3338                         f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3339                         f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3340                         f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3341                 }
3342                 if (header.num_frames <= 0)
3343                 {
3344                         for (i = 0;i < loadmodel->num_bones;i++)
3345                         {
3346                                 float f;
3347                                 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3348                                 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3349                                 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3350                         }
3351                 }
3352         }
3353         else
3354         {
3355                 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3356                 if (header.num_poses)
3357                         pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3358                 for (i = 0;i < (int)header.num_poses;i++)
3359                 {
3360                         float f;
3361                         pose[i].parent = LittleLong(inpose[i].parent);
3362                         pose[i].channelmask = LittleLong(inpose[i].channelmask);
3363                         for (j = 0;j < 10;j++)
3364                         {
3365                                 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3366                                 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3367                         }
3368                         f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3369                         f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3370                         f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3371                         f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3372                         f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3373                         f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3374                 }
3375                 if (header.num_frames <= 0)
3376                 {
3377                         for (i = 0;i < loadmodel->num_bones;i++)
3378                         {
3379                                 float f;
3380                                 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3381                                 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3382                                 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3383                         }
3384                 }
3385         }
3386         loadmodel->num_posescale = biggestorigin / 32767.0f;
3387         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3388
3389         // load the pose data
3390         // this unaligned memory access is safe (LittleShort reads as bytes)
3391         framedata = (const unsigned short *)(pbase + header.ofs_frames);
3392         if (header.version == 1)
3393         {
3394                 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3395                 {
3396                         for (j = 0;j < (int)header.num_poses;j++, k++)
3397                         {
3398                                 loadmodel->data_poses6s[k*6 + 0] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[0] + (pose1[j].channelmask&1 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[0] : 0));
3399                                 loadmodel->data_poses6s[k*6 + 1] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[1] + (pose1[j].channelmask&2 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[1] : 0));
3400                                 loadmodel->data_poses6s[k*6 + 2] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[2] + (pose1[j].channelmask&4 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[2] : 0));
3401                                 loadmodel->data_poses6s[k*6 + 3] = 32767.0f * (pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0));
3402                                 loadmodel->data_poses6s[k*6 + 4] = 32767.0f * (pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0));
3403                                 loadmodel->data_poses6s[k*6 + 5] = 32767.0f * (pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0));
3404                                 // skip scale data for now
3405                                 if(pose1[j].channelmask&64) framedata++;
3406                                 if(pose1[j].channelmask&128) framedata++;
3407                                 if(pose1[j].channelmask&256) framedata++;
3408                         }
3409                 }
3410                 if (header.num_frames <= 0)
3411                 {
3412                         for (i = 0;i < loadmodel->num_bones;i++)
3413                         {
3414                                 loadmodel->data_poses6s[i*6 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3415                                 loadmodel->data_poses6s[i*6 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3416                                 loadmodel->data_poses6s[i*6 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3417                                 loadmodel->data_poses6s[i*6 + 3] = 32767.0f * joint1[i].rotation[0];
3418                                 loadmodel->data_poses6s[i*6 + 4] = 32767.0f * joint1[i].rotation[1];
3419                                 loadmodel->data_poses6s[i*6 + 5] = 32767.0f * joint1[i].rotation[2];
3420                         }
3421                 }
3422         }
3423         else
3424         {
3425                 for (i = 0, k = 0;i < (int)header.num_frames;i++)       
3426                 {
3427                         for (j = 0;j < (int)header.num_poses;j++, k++)
3428                         {
3429                                 float rot[4];
3430                                 loadmodel->data_poses6s[k*6 + 0] = loadmodel->num_poseinvscale * (pose[j].channeloffset[0] + (pose[j].channelmask&1 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[0] : 0));
3431                                 loadmodel->data_poses6s[k*6 + 1] = loadmodel->num_poseinvscale * (pose[j].channeloffset[1] + (pose[j].channelmask&2 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[1] : 0));
3432                                 loadmodel->data_poses6s[k*6 + 2] = loadmodel->num_poseinvscale * (pose[j].channeloffset[2] + (pose[j].channelmask&4 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[2] : 0));
3433                                 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3434                                 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3435                                 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3436                                 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3437                                 if (rot[3] > 0)
3438                                         Vector4Negate(rot, rot);
3439                                 Vector4Normalize2(rot, rot);
3440                                 loadmodel->data_poses6s[k*6 + 3] = 32767.0f * rot[0];
3441                                 loadmodel->data_poses6s[k*6 + 4] = 32767.0f * rot[1];
3442                                 loadmodel->data_poses6s[k*6 + 5] = 32767.0f * rot[2];
3443                                 // skip scale data for now
3444                                 if(pose[j].channelmask&128) framedata++;
3445                                 if(pose[j].channelmask&256) framedata++;
3446                                 if(pose[j].channelmask&512) framedata++;
3447                         }
3448                 }
3449                 if (header.num_frames <= 0)
3450                 {
3451                         for (i = 0;i < loadmodel->num_bones;i++)
3452                         {
3453                                 loadmodel->data_poses6s[i*6 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3454                                 loadmodel->data_poses6s[i*6 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3455                                 loadmodel->data_poses6s[i*6 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3456                                 loadmodel->data_poses6s[i*6 + 3] = 32767.0f * joint[i].rotation[0];
3457                                 loadmodel->data_poses6s[i*6 + 4] = 32767.0f * joint[i].rotation[1];
3458                                 loadmodel->data_poses6s[i*6 + 5] = 32767.0f * joint[i].rotation[2];
3459                         }
3460                 }
3461         }
3462
3463         // load bounding box data
3464         if (header.ofs_bounds)
3465         {
3466                 float xyradius = 0, radius = 0;
3467                 VectorClear(loadmodel->normalmins);
3468                 VectorClear(loadmodel->normalmaxs);
3469                 for (i = 0; i < (int)header.num_frames;i++)
3470                 {
3471                         iqmbounds_t bound;
3472                         bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3473                         bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3474                         bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3475                         bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);                 
3476                         bound.maxs[1] = LittleFloat(bounds[i].maxs[1]); 
3477                         bound.maxs[2] = LittleFloat(bounds[i].maxs[2]); 
3478                         bound.xyradius = LittleFloat(bounds[i].xyradius);
3479                         bound.radius = LittleFloat(bounds[i].radius);
3480                         if (!i)
3481                         {
3482                                 VectorCopy(bound.mins, loadmodel->normalmins);
3483                                 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3484                         }
3485                         else
3486                         {
3487                                 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3488                                 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3489                                 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3490                                 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3491                                 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3492                                 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3493                         }
3494                         if (bound.xyradius > xyradius)
3495                                 xyradius = bound.xyradius;
3496                         if (bound.radius > radius)
3497                                 radius = bound.radius;
3498                 }
3499                 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3500                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3501                 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3502                 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3503                 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3504                 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3505                 loadmodel->radius = radius;
3506                 loadmodel->radius2 = radius * radius;
3507         }
3508
3509         // load triangle data
3510         // this unaligned memory access is safe (LittleLong reads as bytes)
3511         inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3512         outelements = loadmodel->surfmesh.data_element3i;
3513         for (i = 0;i < (int)header.num_triangles;i++)
3514         {
3515                 outelements[0] = LittleLong(inelements[0]);
3516                 outelements[1] = LittleLong(inelements[1]);
3517                 outelements[2] = LittleLong(inelements[2]);
3518                 outelements += 3;
3519                 inelements += 3;
3520         }
3521         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3522
3523         if (header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
3524         {
3525                 // this unaligned memory access is safe (LittleLong reads as bytes)
3526                 inneighbors = (const int *)(pbase + header.ofs_neighbors);
3527                 outneighbors = loadmodel->surfmesh.data_neighbor3i;
3528                 for (i = 0;i < (int)header.num_triangles;i++)
3529                 {
3530                         outneighbors[0] = LittleLong(inneighbors[0]);
3531                         outneighbors[1] = LittleLong(inneighbors[1]);
3532                         outneighbors[2] = LittleLong(inneighbors[2]);
3533                         outneighbors += 3;
3534                         inneighbors += 3;
3535                 }
3536         }
3537
3538         // load vertex data
3539         // this unaligned memory access is safe (LittleFloat reads as bytes)
3540         outvertex = loadmodel->surfmesh.data_vertex3f;
3541         for (i = 0;i < (int)header.num_vertexes;i++)
3542         {
3543                 outvertex[0] = LittleFloat(vposition[0]);
3544                 outvertex[1] = LittleFloat(vposition[1]);
3545                 outvertex[2] = LittleFloat(vposition[2]);
3546                 vposition += 3;
3547                 outvertex += 3;
3548         }
3549
3550         outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3551         // this unaligned memory access is safe (LittleFloat reads as bytes)
3552         for (i = 0;i < (int)header.num_vertexes;i++)
3553         {
3554                 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3555                 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3556                 vtexcoord += 2;
3557                 outtexcoord += 2;
3558         }
3559
3560         // this unaligned memory access is safe (LittleFloat reads as bytes)
3561         if(vnormal)
3562         {
3563                 outnormal = loadmodel->surfmesh.data_normal3f;
3564                 for (i = 0;i < (int)header.num_vertexes;i++)
3565                 {
3566                         outnormal[0] = LittleFloat(vnormal[0]);
3567                         outnormal[1] = LittleFloat(vnormal[1]);
3568                         outnormal[2] = LittleFloat(vnormal[2]);
3569                         vnormal += 3;
3570                         outnormal += 3;
3571                 }
3572         }
3573
3574         // this unaligned memory access is safe (LittleFloat reads as bytes)
3575         if(vnormal && vtangent)
3576         {
3577                 outnormal = loadmodel->surfmesh.data_normal3f;
3578                 outsvector = loadmodel->surfmesh.data_svector3f;
3579                 outtvector = loadmodel->surfmesh.data_tvector3f;
3580                 for (i = 0;i < (int)header.num_vertexes;i++)
3581                 {
3582                         outsvector[0] = LittleFloat(vtangent[0]);
3583                         outsvector[1] = LittleFloat(vtangent[1]);
3584                         outsvector[2] = LittleFloat(vtangent[2]);
3585                         if(LittleFloat(vtangent[3]) < 0)
3586                                 CrossProduct(outsvector, outnormal, outtvector);
3587                         else
3588                                 CrossProduct(outnormal, outsvector, outtvector);
3589                         vtangent += 4;
3590                         outnormal += 3;
3591                         outsvector += 3;
3592                         outtvector += 3;
3593                 }
3594         }
3595
3596         // this unaligned memory access is safe (all bytes)
3597         if (vblendindexes && vblendweights)
3598         {
3599                 for (i = 0; i < (int)header.num_vertexes;i++)
3600                 {
3601                         blendweights_t weights;
3602                         memcpy(weights.index, vblendindexes + i*4, 4);
3603                         memcpy(weights.influence, vblendweights + i*4, 4);
3604                         loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3605                 }
3606         }
3607
3608         // load meshes
3609         for (i = 0;i < (int)header.num_meshes;i++)
3610         {
3611                 iqmmesh_t mesh;
3612                 msurface_t *surface;
3613
3614                 mesh.name = LittleLong(meshes[i].name);
3615                 mesh.material = LittleLong(meshes[i].material);
3616                 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3617                 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3618                 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3619                 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3620
3621                 loadmodel->sortedmodelsurfaces[i] = i;
3622                 surface = loadmodel->data_surfaces + i;
3623                 surface->texture = loadmodel->data_textures + i;
3624                 surface->num_firsttriangle = mesh.first_triangle;
3625                 surface->num_triangles = mesh.num_triangles;
3626                 surface->num_firstvertex = mesh.first_vertex;
3627                 surface->num_vertices = mesh.num_vertexes;
3628
3629                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3630         }
3631
3632         Mod_FreeSkinFiles(skinfiles);
3633         Mod_MakeSortedSurfaces(loadmodel);
3634
3635         // compute all the mesh information that was not loaded from the file
3636         if (loadmodel->surfmesh.data_element3s)
3637                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3638                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3639         if (!vnormal)
3640                 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);
3641         if (!vnormal || !vtangent)
3642                 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);
3643         if (!header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
3644                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
3645         if (!header.ofs_bounds)
3646                 Mod_Alias_CalculateBoundingBox();
3647
3648         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
3649
3650         if (!loadmodel->surfmesh.isanimated)
3651         {
3652                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3653                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3654                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3655                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3656                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3657                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3658         }
3659
3660         if (joint        ) Mem_Free(joint        );joint         = NULL;
3661         if (joint1       ) Mem_Free(joint1       );joint1        = NULL;
3662         if (pose         ) Mem_Free(pose         );pose          = NULL;
3663         if (pose1        ) Mem_Free(pose1        );pose1         = NULL;
3664 }