]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - model_alias.c
allow .psk models to be loaded without a corresponding .psa file
[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_Skeletal_AnimateVertices_maxbonepose = 0;
44 static void *Mod_Skeletal_AnimateVertices_bonepose = NULL;
45 void Mod_Skeletal_FreeBuffers(void)
46 {
47         if(Mod_Skeletal_AnimateVertices_bonepose)
48                 Mem_Free(Mod_Skeletal_AnimateVertices_bonepose);
49         Mod_Skeletal_AnimateVertices_maxbonepose = 0;
50         Mod_Skeletal_AnimateVertices_bonepose = NULL;
51 }
52 void *Mod_Skeletal_AnimateVertices_AllocBuffers(size_t nbytes)
53 {
54         if(Mod_Skeletal_AnimateVertices_maxbonepose < nbytes)
55         {
56                 if(Mod_Skeletal_AnimateVertices_bonepose)
57                         Mem_Free(Mod_Skeletal_AnimateVertices_bonepose);
58                 Mod_Skeletal_AnimateVertices_bonepose = Z_Malloc(nbytes);
59                 Mod_Skeletal_AnimateVertices_maxbonepose = nbytes;
60         }
61         return Mod_Skeletal_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
67         if (!model->surfmesh.num_vertices)
68                 return;
69
70         if (!model->num_bones)
71         {
72                 if (vertex3f) memcpy(vertex3f, model->surfmesh.data_vertex3f, model->surfmesh.num_vertices*sizeof(float[3]));
73                 if (normal3f) memcpy(normal3f, model->surfmesh.data_normal3f, model->surfmesh.num_vertices*sizeof(float[3]));
74                 if (svector3f) memcpy(svector3f, model->surfmesh.data_svector3f, model->surfmesh.num_vertices*sizeof(float[3]));
75                 if (tvector3f) memcpy(tvector3f, model->surfmesh.data_tvector3f, model->surfmesh.num_vertices*sizeof(float[3]));
76                 return;
77         }
78
79 #ifdef SSE_POSSIBLE
80         if(r_skeletal_use_sse_defined)
81                 if(r_skeletal_use_sse.integer)
82                 {
83                         Mod_Skeletal_AnimateVertices_SSE(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
84                         return;
85                 }
86 #endif
87         Mod_Skeletal_AnimateVertices_Generic(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
88 }
89
90 void Mod_AliasInit (void)
91 {
92         int i;
93         Cvar_RegisterVariable(&r_skeletal_debugbone);
94         Cvar_RegisterVariable(&r_skeletal_debugbonecomponent);
95         Cvar_RegisterVariable(&r_skeletal_debugbonevalue);
96         Cvar_RegisterVariable(&r_skeletal_debugtranslatex);
97         Cvar_RegisterVariable(&r_skeletal_debugtranslatey);
98         Cvar_RegisterVariable(&r_skeletal_debugtranslatez);
99         Cvar_RegisterVariable(&mod_alias_supporttagscale);
100         for (i = 0;i < 320;i++)
101                 mod_md3_sin[i] = sin(i * M_PI * 2.0f / 256.0);
102 #ifdef SSE_POSSIBLE
103         if(Sys_HaveSSE())
104         {
105                 Con_Printf("Skeletal animation uses SSE code path\n");
106                 r_skeletal_use_sse_defined = true;
107                 Cvar_RegisterVariable(&r_skeletal_use_sse);
108         }
109         else
110                 Con_Printf("Skeletal animation uses generic code path (SSE disabled or not detected)\n");
111 #else
112         Con_Printf("Skeletal animation uses generic code path (SSE not compiled in)\n");
113 #endif
114 }
115
116 int Mod_Skeletal_AddBlend(dp_model_t *model, const blendweights_t *newweights)
117 {
118         int i;
119         blendweights_t *weights;
120         if(!newweights->influence[1])
121                 return newweights->index[0];
122         weights = model->surfmesh.data_blendweights;
123         for (i = 0;i < model->surfmesh.num_blends;i++, weights++)
124         {
125                 if (!memcmp(weights, newweights, sizeof(blendweights_t)))
126                         return model->num_bones + i;
127         }
128         model->surfmesh.num_blends++;
129         memcpy(weights, newweights, sizeof(blendweights_t));
130         return model->num_bones + i;
131 }
132
133 int Mod_Skeletal_CompressBlend(dp_model_t *model, const int *newindex, const float *newinfluence)
134 {
135         int i, total;
136         float scale;
137         blendweights_t newweights;
138         if(!newinfluence[1])
139                 return newindex[0];
140         scale = 0;
141         for (i = 0;i < 4;i++)
142                 scale += newinfluence[i];
143         scale = 255.0f / scale;
144         total = 0;
145         for (i = 0;i < 4;i++)
146         {
147                 newweights.index[i] = newindex[i];
148                 newweights.influence[i] = (unsigned char)(newinfluence[i] * scale);
149                 total += newweights.influence[i];
150         }       
151         while (total > 255)
152         {
153                 for (i = 0;i < 4;i++)
154                 {
155                         if(newweights.influence[i] > 0 && total > 255) 
156                         { 
157                                 newweights.influence[i]--;
158                                 total--; 
159                         }
160                 }
161         }
162         while (total < 255)
163         {
164                 for (i = 0; i < 4;i++)
165                 {
166                         if(newweights.influence[i] < 255 && total < 255) 
167                         { 
168                                 newweights.influence[i]++; 
169                                 total++; 
170                         }
171                 }
172         }
173         return Mod_Skeletal_AddBlend(model, &newweights);
174 }
175
176 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)
177 {
178         // vertex morph
179         int i, numblends, blendnum;
180         int numverts = model->surfmesh.num_vertices;
181         numblends = 0;
182         for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
183         {
184                 //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate);
185                 if (frameblend[blendnum].lerp > 0)
186                         numblends = blendnum + 1;
187         }
188         // special case for the first blend because it avoids some adds and the need to memset the arrays first
189         for (blendnum = 0;blendnum < numblends;blendnum++)
190         {
191                 const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].subframe;
192                 if (vertex3f)
193                 {
194                         float scale = frameblend[blendnum].lerp * (1.0f / 64.0f);
195                         if (blendnum == 0)
196                         {
197                                 for (i = 0;i < numverts;i++)
198                                 {
199                                         vertex3f[i * 3 + 0] = verts[i].origin[0] * scale;
200                                         vertex3f[i * 3 + 1] = verts[i].origin[1] * scale;
201                                         vertex3f[i * 3 + 2] = verts[i].origin[2] * scale;
202                                 }
203                         }
204                         else
205                         {
206                                 for (i = 0;i < numverts;i++)
207                                 {
208                                         vertex3f[i * 3 + 0] += verts[i].origin[0] * scale;
209                                         vertex3f[i * 3 + 1] += verts[i].origin[1] * scale;
210                                         vertex3f[i * 3 + 2] += verts[i].origin[2] * scale;
211                                 }
212                         }
213                 }
214                 // the yaw and pitch stored in md3 models are 8bit quantized angles
215                 // (0-255), and as such a lookup table is very well suited to
216                 // decoding them, and since cosine is equivalent to sine with an
217                 // extra 45 degree rotation, this uses one lookup table for both
218                 // sine and cosine with a +64 bias to get cosine.
219                 if (normal3f)
220                 {
221                         float lerp = frameblend[blendnum].lerp;
222                         if (blendnum == 0)
223                         {
224                                 for (i = 0;i < numverts;i++)
225                                 {
226                                         normal3f[i * 3 + 0] = mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch     ] * lerp;
227                                         normal3f[i * 3 + 1] = mod_md3_sin[verts[i].yaw     ] * mod_md3_sin[verts[i].pitch     ] * lerp;
228                                         normal3f[i * 3 + 2] =                                  mod_md3_sin[verts[i].pitch + 64] * lerp;
229                                 }
230                         }
231                         else
232                         {
233                                 for (i = 0;i < numverts;i++)
234                                 {
235                                         normal3f[i * 3 + 0] += mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch     ] * lerp;
236                                         normal3f[i * 3 + 1] += mod_md3_sin[verts[i].yaw     ] * mod_md3_sin[verts[i].pitch     ] * lerp;
237                                         normal3f[i * 3 + 2] +=                                  mod_md3_sin[verts[i].pitch + 64] * lerp;
238                                 }
239                         }
240                 }
241                 if (svector3f)
242                 {
243                         const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
244                         float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
245                         if (blendnum == 0)
246                         {
247                                 for (i = 0;i < numverts;i++, texvecvert++)
248                                 {
249                                         VectorScale(texvecvert->svec, f, svector3f + i*3);
250                                         VectorScale(texvecvert->tvec, f, tvector3f + i*3);
251                                 }
252                         }
253                         else
254                         {
255                                 for (i = 0;i < numverts;i++, texvecvert++)
256                                 {
257                                         VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
258                                         VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
259                                 }
260                         }
261                 }
262         }
263 }
264 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)
265 {
266         // vertex morph
267         int i, numblends, blendnum;
268         int numverts = model->surfmesh.num_vertices;
269         float translate[3];
270         VectorClear(translate);
271         numblends = 0;
272         // blend the frame translates to avoid redundantly doing so on each vertex
273         // (a bit of a brain twister but it works)
274         for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
275         {
276                 if (model->surfmesh.data_morphmd2framesize6f)
277                         VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6 + 3, translate);
278                 else
279                         VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate);
280                 if (frameblend[blendnum].lerp > 0)
281                         numblends = blendnum + 1;
282         }
283         // special case for the first blend because it avoids some adds and the need to memset the arrays first
284         for (blendnum = 0;blendnum < numblends;blendnum++)
285         {
286                 const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].subframe;
287                 if (vertex3f)
288                 {
289                         float scale[3];
290                         if (model->surfmesh.data_morphmd2framesize6f)
291                                 VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6, frameblend[blendnum].lerp, scale);
292                         else
293                                 VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale);
294                         if (blendnum == 0)
295                         {
296                                 for (i = 0;i < numverts;i++)
297                                 {
298                                         vertex3f[i * 3 + 0] = translate[0] + verts[i].v[0] * scale[0];
299                                         vertex3f[i * 3 + 1] = translate[1] + verts[i].v[1] * scale[1];
300                                         vertex3f[i * 3 + 2] = translate[2] + verts[i].v[2] * scale[2];
301                                 }
302                         }
303                         else
304                         {
305                                 for (i = 0;i < numverts;i++)
306                                 {
307                                         vertex3f[i * 3 + 0] += verts[i].v[0] * scale[0];
308                                         vertex3f[i * 3 + 1] += verts[i].v[1] * scale[1];
309                                         vertex3f[i * 3 + 2] += verts[i].v[2] * scale[2];
310                                 }
311                         }
312                 }
313                 // the vertex normals in mdl models are an index into a table of
314                 // 162 unique values, this very crude quantization reduces the
315                 // vertex normal to only one byte, which saves a lot of space but
316                 // also makes lighting pretty coarse
317                 if (normal3f)
318                 {
319                         float lerp = frameblend[blendnum].lerp;
320                         if (blendnum == 0)
321                         {
322                                 for (i = 0;i < numverts;i++)
323                                 {
324                                         const float *vn = m_bytenormals[verts[i].lightnormalindex];
325                                         VectorScale(vn, lerp, normal3f + i*3);
326                                 }
327                         }
328                         else
329                         {
330                                 for (i = 0;i < numverts;i++)
331                                 {
332                                         const float *vn = m_bytenormals[verts[i].lightnormalindex];
333                                         VectorMA(normal3f + i*3, lerp, vn, normal3f + i*3);
334                                 }
335                         }
336                 }
337                 if (svector3f)
338                 {
339                         const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
340                         float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
341                         if (blendnum == 0)
342                         {
343                                 for (i = 0;i < numverts;i++, texvecvert++)
344                                 {
345                                         VectorScale(texvecvert->svec, f, svector3f + i*3);
346                                         VectorScale(texvecvert->tvec, f, tvector3f + i*3);
347                                 }
348                         }
349                         else
350                         {
351                                 for (i = 0;i < numverts;i++, texvecvert++)
352                                 {
353                                         VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
354                                         VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
355                                 }
356                         }
357                 }
358         }
359 }
360
361 int Mod_Alias_GetTagMatrix(const dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, matrix4x4_t *outmatrix)
362 {
363         matrix4x4_t temp;
364         matrix4x4_t parentbonematrix;
365         matrix4x4_t tempbonematrix;
366         matrix4x4_t bonematrix;
367         matrix4x4_t blendmatrix;
368         int blendindex;
369         int parenttagindex;
370         int k;
371         float lerp;
372         const float *input;
373         float blendtag[12];
374         *outmatrix = identitymatrix;
375         if (skeleton && skeleton->relativetransforms)
376         {
377                 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
378                         return 4;
379                 *outmatrix = skeleton->relativetransforms[tagindex];
380                 while ((tagindex = model->data_bones[tagindex].parent) >= 0)
381                 {
382                         temp = *outmatrix;
383                         Matrix4x4_Concat(outmatrix, &skeleton->relativetransforms[tagindex], &temp);
384                 }
385         }
386         else if (model->num_bones)
387         {
388                 if (tagindex < 0 || tagindex >= model->num_bones)
389                         return 4;
390                 Matrix4x4_Clear(&blendmatrix);
391                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
392                 {
393                         lerp = frameblend[blendindex].lerp;
394                         Matrix4x4_FromBonePose6s(&bonematrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
395                         parenttagindex = tagindex;
396                         while ((parenttagindex = model->data_bones[parenttagindex].parent) >= 0)
397                         {
398                                 Matrix4x4_FromBonePose6s(&parentbonematrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + parenttagindex));
399                                 tempbonematrix = bonematrix;
400                                 Matrix4x4_Concat(&bonematrix, &parentbonematrix, &tempbonematrix);
401                         }
402                         Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
403                 }
404                 *outmatrix = blendmatrix;
405         }
406         else if (model->num_tags)
407         {
408                 if (tagindex < 0 || tagindex >= model->num_tags)
409                         return 4;
410                 for (k = 0;k < 12;k++)
411                         blendtag[k] = 0;
412                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
413                 {
414                         lerp = frameblend[blendindex].lerp;
415                         input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
416                         for (k = 0;k < 12;k++)
417                                 blendtag[k] += input[k] * lerp;
418                 }
419                 Matrix4x4_FromArray12FloatGL(outmatrix, blendtag);
420         }
421
422         if(!mod_alias_supporttagscale.integer)
423                 Matrix4x4_Normalize3(outmatrix, outmatrix);
424
425         return 0;
426 }
427
428 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)
429 {
430         int blendindex;
431         int k;
432         float lerp;
433         matrix4x4_t bonematrix;
434         matrix4x4_t blendmatrix;
435         const float *input;
436         float blendtag[12];
437
438         if (skeleton && skeleton->relativetransforms)
439         {
440                 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
441                         return 1;
442                 *parentindex = skeleton->model->data_bones[tagindex].parent;
443                 *tagname = skeleton->model->data_bones[tagindex].name;
444                 *tag_localmatrix = skeleton->relativetransforms[tagindex];
445                 return 0;
446         }
447         else if (model->num_bones)
448         {
449                 if (tagindex < 0 || tagindex >= model->num_bones)
450                         return 1;
451                 *parentindex = model->data_bones[tagindex].parent;
452                 *tagname = model->data_bones[tagindex].name;
453                 Matrix4x4_Clear(&blendmatrix);
454                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
455                 {
456                         lerp = frameblend[blendindex].lerp;
457                         Matrix4x4_FromBonePose6s(&bonematrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
458                         Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
459                 }
460                 *tag_localmatrix = blendmatrix;
461                 return 0;
462         }
463         else if (model->num_tags)
464         {
465                 if (tagindex < 0 || tagindex >= model->num_tags)
466                         return 1;
467                 *parentindex = -1;
468                 *tagname = model->data_tags[tagindex].name;
469                 for (k = 0;k < 12;k++)
470                         blendtag[k] = 0;
471                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
472                 {
473                         lerp = frameblend[blendindex].lerp;
474                         input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
475                         for (k = 0;k < 12;k++)
476                                 blendtag[k] += input[k] * lerp;
477                 }
478                 Matrix4x4_FromArray12FloatGL(tag_localmatrix, blendtag);
479                 return 0;
480         }
481
482         return 2;
483 }
484
485 int Mod_Alias_GetTagIndexForName(const dp_model_t *model, unsigned int skin, const char *tagname)
486 {
487         int i;
488         if(skin >= (unsigned int)model->numskins)
489                 skin = 0;
490         if (model->num_bones)
491                 for (i = 0;i < model->num_bones;i++)
492                         if (!strcasecmp(tagname, model->data_bones[i].name))
493                                 return i + 1;
494         if (model->num_tags)
495                 for (i = 0;i < model->num_tags;i++)
496                         if (!strcasecmp(tagname, model->data_tags[i].name))
497                                 return i + 1;
498         return 0;
499 }
500
501 static void Mod_BuildBaseBonePoses(void)
502 {
503         int boneindex;
504         matrix4x4_t *basebonepose;
505         float *outinvmatrix = loadmodel->data_baseboneposeinverse;
506         matrix4x4_t bonematrix;
507         matrix4x4_t tempbonematrix;
508         if (!loadmodel->num_bones)
509                 return;
510         basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
511         for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
512         {
513                 Matrix4x4_FromBonePose6s(&bonematrix, loadmodel->num_posescale, loadmodel->data_poses6s + 6 * boneindex);
514                 if (loadmodel->data_bones[boneindex].parent >= 0)
515                 {
516                         tempbonematrix = bonematrix;
517                         Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
518                 }
519                 basebonepose[boneindex] = bonematrix;
520                 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
521                 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
522         }
523         Mem_Free(basebonepose);
524 }
525
526 static void Mod_Alias_CalculateBoundingBox(void)
527 {
528         int vnum;
529         qboolean firstvertex = true;
530         float dist, yawradius, radius;
531         float *v;
532         VectorClear(loadmodel->normalmins);
533         VectorClear(loadmodel->normalmaxs);
534         yawradius = 0;
535         radius = 0;
536         if (loadmodel->AnimateVertices)
537         {
538                 float *vertex3f;
539                 frameblend_t frameblend[MAX_FRAMEBLENDS];
540                 memset(frameblend, 0, sizeof(frameblend));
541                 frameblend[0].lerp = 1;
542                 vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
543                 for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
544                 {
545                         loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL);
546                         for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
547                         {
548                                 if (firstvertex)
549                                 {
550                                         firstvertex = false;
551                                         VectorCopy(v, loadmodel->normalmins);
552                                         VectorCopy(v, loadmodel->normalmaxs);
553                                 }
554                                 else
555                                 {
556                                         if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
557                                         if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
558                                         if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
559                                         if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
560                                         if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
561                                         if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
562                                 }
563                                 dist = v[0] * v[0] + v[1] * v[1];
564                                 if (yawradius < dist)
565                                         yawradius = dist;
566                                 dist += v[2] * v[2];
567                                 if (radius < dist)
568                                         radius = dist;
569                         }
570                 }
571                 if (vertex3f)
572                         Mem_Free(vertex3f);
573         }
574         else
575         {
576                 for (vnum = 0, v = loadmodel->surfmesh.data_vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
577                 {
578                         if (firstvertex)
579                         {
580                                 firstvertex = false;
581                                 VectorCopy(v, loadmodel->normalmins);
582                                 VectorCopy(v, loadmodel->normalmaxs);
583                         }
584                         else
585                         {
586                                 if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
587                                 if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
588                                 if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
589                                 if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
590                                 if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
591                                 if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
592                         }
593                         dist = v[0] * v[0] + v[1] * v[1];
594                         if (yawradius < dist)
595                                 yawradius = dist;
596                         dist += v[2] * v[2];
597                         if (radius < dist)
598                                 radius = dist;
599                 }
600         }
601         radius = sqrt(radius);
602         yawradius = sqrt(yawradius);
603         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
604         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius;
605         loadmodel->yawmins[2] = loadmodel->normalmins[2];
606         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
607         loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
608         loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
609         loadmodel->radius = radius;
610         loadmodel->radius2 = radius * radius;
611 }
612
613 static void Mod_Alias_MorphMesh_CompileFrames(void)
614 {
615         int i, j;
616         frameblend_t frameblend[MAX_FRAMEBLENDS];
617         unsigned char *datapointer;
618         memset(frameblend, 0, sizeof(frameblend));
619         frameblend[0].lerp = 1;
620         datapointer = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * (sizeof(float[3]) * 4 + loadmodel->surfmesh.num_morphframes * sizeof(texvecvertex_t)));
621         loadmodel->surfmesh.data_vertex3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
622         loadmodel->surfmesh.data_svector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
623         loadmodel->surfmesh.data_tvector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
624         loadmodel->surfmesh.data_normal3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
625         loadmodel->surfmesh.data_morphtexvecvertex = (texvecvertex_t *)datapointer;datapointer += loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices * sizeof(texvecvertex_t);
626         // 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)
627         for (i = loadmodel->surfmesh.num_morphframes-1;i >= 0;i--)
628         {
629                 frameblend[0].subframe = i;
630                 loadmodel->AnimateVertices(loadmodel, frameblend, NULL, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL);
631                 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);
632                 // encode the svector and tvector in 3 byte format for permanent storage
633                 for (j = 0;j < loadmodel->surfmesh.num_vertices;j++)
634                 {
635                         VectorScaleCast(loadmodel->surfmesh.data_svector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].svec);
636                         VectorScaleCast(loadmodel->surfmesh.data_tvector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].tvec);
637                 }
638         }
639 }
640
641 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)
642 {
643         int i;
644         float segmentmins[3], segmentmaxs[3];
645         msurface_t *surface;
646         static int maxvertices = 0;
647         static float *vertex3f = NULL;
648         memset(trace, 0, sizeof(*trace));
649         trace->fraction = 1;
650         trace->realfraction = 1;
651         trace->hitsupercontentsmask = hitsupercontentsmask;
652         if (maxvertices < model->surfmesh.num_vertices)
653         {
654                 if (vertex3f)
655                         Z_Free(vertex3f);
656                 maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
657                 vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3]));
658         }
659         segmentmins[0] = min(start[0], end[0]) - 1;
660         segmentmins[1] = min(start[1], end[1]) - 1;
661         segmentmins[2] = min(start[2], end[2]) - 1;
662         segmentmaxs[0] = max(start[0], end[0]) + 1;
663         segmentmaxs[1] = max(start[1], end[1]) + 1;
664         segmentmaxs[2] = max(start[2], end[2]) + 1;
665         model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
666         for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
667                 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);
668 }
669
670 static int maxvertices = 0;
671 static float *vertex3f = NULL;
672
673 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)
674 {
675         int i;
676         vec3_t shiftstart, shiftend;
677         float segmentmins[3], segmentmaxs[3];
678         msurface_t *surface;
679         colboxbrushf_t thisbrush_start, thisbrush_end;
680         vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
681
682         if (VectorCompare(boxmins, boxmaxs))
683         {
684                 VectorAdd(start, boxmins, shiftstart);
685                 VectorAdd(end, boxmins, shiftend);
686                 Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask);
687                 VectorSubtract(trace->endpos, boxmins, trace->endpos);
688                 return;
689         }
690
691         // box trace, performed as brush trace
692         memset(trace, 0, sizeof(*trace));
693         trace->fraction = 1;
694         trace->realfraction = 1;
695         trace->hitsupercontentsmask = hitsupercontentsmask;
696         if (maxvertices < model->surfmesh.num_vertices)
697         {
698                 if (vertex3f)
699                         Z_Free(vertex3f);
700                 maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
701                 vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3]));
702         }
703         segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
704         segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
705         segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
706         segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
707         segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
708         segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
709         VectorAdd(start, boxmins, boxstartmins);
710         VectorAdd(start, boxmaxs, boxstartmaxs);
711         VectorAdd(end, boxmins, boxendmins);
712         VectorAdd(end, boxmaxs, boxendmaxs);
713         Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL);
714         Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL);
715         if (maxvertices < model->surfmesh.num_vertices)
716         {
717                 if (vertex3f)
718                         Z_Free(vertex3f);
719                 maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
720                 vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3]));
721         }
722         model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
723         for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
724                 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);
725 }
726
727 static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
728 {
729         int i, j;
730         for (i = 0;i < inverts;i++)
731         {
732                 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
733                         continue;
734                 j = vertremap[i]; // not onseam
735                 if (j >= 0)
736                         out[j] = v[i];
737                 j = vertremap[i+inverts]; // onseam
738                 if (j >= 0)
739                         out[j] = v[i];
740         }
741 }
742
743 static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
744 {
745         int i, f, pose, groupframes;
746         float interval;
747         daliasframetype_t *pframetype;
748         daliasframe_t *pinframe;
749         daliasgroup_t *group;
750         daliasinterval_t *intervals;
751         animscene_t *scene;
752         pose = 0;
753         scene = loadmodel->animscenes;
754         for (f = 0;f < loadmodel->numframes;f++)
755         {
756                 pframetype = (daliasframetype_t *)datapointer;
757                 datapointer += sizeof(daliasframetype_t);
758                 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
759                 {
760                         // a single frame is still treated as a group
761                         interval = 0.1f;
762                         groupframes = 1;
763                 }
764                 else
765                 {
766                         // read group header
767                         group = (daliasgroup_t *)datapointer;
768                         datapointer += sizeof(daliasgroup_t);
769                         groupframes = LittleLong (group->numframes);
770
771                         // intervals (time per frame)
772                         intervals = (daliasinterval_t *)datapointer;
773                         datapointer += sizeof(daliasinterval_t) * groupframes;
774
775                         interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
776                         if (interval < 0.01f)
777                         {
778                                 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
779                                 interval = 0.1f;
780                         }
781                 }
782
783                 // get scene name from first frame
784                 pinframe = (daliasframe_t *)datapointer;
785
786                 strlcpy(scene->name, pinframe->name, sizeof(scene->name));
787                 scene->firstframe = pose;
788                 scene->framecount = groupframes;
789                 scene->framerate = 1.0f / interval;
790                 scene->loop = true;
791                 scene++;
792
793                 // read frames
794                 for (i = 0;i < groupframes;i++)
795                 {
796                         pinframe = (daliasframe_t *)datapointer;
797                         datapointer += sizeof(daliasframe_t);
798                         Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
799                         datapointer += sizeof(trivertx_t) * inverts;
800                         pose++;
801                 }
802         }
803 }
804
805 static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *skinframe)
806 {
807         if (cls.state == ca_dedicated)
808                 return;
809         // hack
810         if (!skinframe)
811                 skinframe = R_SkinFrame_LoadMissing();
812         memset(texture, 0, sizeof(*texture));
813         texture->currentframe = texture;
814         //texture->animated = false;
815         texture->numskinframes = 1;
816         texture->skinframerate = 1;
817         texture->skinframes[0] = skinframe;
818         texture->currentskinframe = skinframe;
819         //texture->backgroundnumskinframes = 0;
820         //texture->customblendfunc[0] = 0;
821         //texture->customblendfunc[1] = 0;
822         //texture->surfaceflags = 0;
823         //texture->supercontents = 0;
824         //texture->surfaceparms = 0;
825         //texture->textureflags = 0;
826
827         texture->basematerialflags = MATERIALFLAG_WALL;
828         if (texture->currentskinframe->hasalpha)
829                 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
830         texture->currentmaterialflags = texture->basematerialflags;
831         texture->offsetmapping = OFFSETMAPPING_DEFAULT;
832         texture->offsetscale = 1;
833         texture->offsetbias = 0;
834         texture->specularscalemod = 1;
835         texture->specularpowermod = 1;
836         texture->surfaceflags = 0;
837         texture->supercontents = SUPERCONTENTS_SOLID;
838         if (!(texture->basematerialflags & MATERIALFLAG_BLENDED))
839                 texture->supercontents |= SUPERCONTENTS_OPAQUE;
840 }
841
842 void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
843 {
844         int i;
845         static char stripbuf[MAX_QPATH];
846         skinfileitem_t *skinfileitem;
847         if(developer_extra.integer)
848                 Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername);
849         if (skinfile)
850         {
851                 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
852                 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
853                 {
854                         memset(skin, 0, sizeof(*skin));
855                         // see if a mesh
856                         for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
857                         {
858                                 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
859                                 if (!strcmp(skinfileitem->name, meshname))
860                                 {
861                                         Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
862                                         if(developer_extra.integer)
863                                                 Con_DPrintf("--> got %s from skin file\n", stripbuf);
864                                         Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
865                                         break;
866                                 }
867                         }
868                         if (!skinfileitem)
869                         {
870                                 // don't render unmentioned meshes
871                                 Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
872                                 if(developer_extra.integer)
873                                         Con_DPrintf("--> skipping\n");
874                                 skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
875                         }
876                 }
877         }
878         else
879         {
880                 if(developer_extra.integer)
881                         Con_DPrintf("--> using default\n");
882                 Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
883                 Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
884         }
885 }
886
887 #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);
888 #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);
889 void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
890 {
891         int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
892         float scales, scalet, interval;
893         msurface_t *surface;
894         unsigned char *data;
895         mdl_t *pinmodel;
896         stvert_t *pinstverts;
897         dtriangle_t *pintriangles;
898         daliasskintype_t *pinskintype;
899         daliasskingroup_t *pinskingroup;
900         daliasskininterval_t *pinskinintervals;
901         daliasframetype_t *pinframetype;
902         daliasgroup_t *pinframegroup;
903         unsigned char *datapointer, *startframes, *startskins;
904         char name[MAX_QPATH];
905         skinframe_t *tempskinframe;
906         animscene_t *tempskinscenes;
907         texture_t *tempaliasskins;
908         float *vertst;
909         int *vertonseam, *vertremap;
910         skinfile_t *skinfiles;
911
912         datapointer = (unsigned char *)buffer;
913         pinmodel = (mdl_t *)datapointer;
914         datapointer += sizeof(mdl_t);
915
916         version = LittleLong (pinmodel->version);
917         if (version != ALIAS_VERSION)
918                 Host_Error ("%s has wrong version number (%i should be %i)",
919                                  loadmodel->name, version, ALIAS_VERSION);
920
921         loadmodel->modeldatatypestring = "MDL";
922
923         loadmodel->type = mod_alias;
924         loadmodel->DrawSky = NULL;
925         loadmodel->DrawAddWaterPlanes = NULL;
926         loadmodel->Draw = R_Q1BSP_Draw;
927         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
928         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
929         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
930         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
931         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
932         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
933         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
934         loadmodel->DrawLight = R_Q1BSP_DrawLight;
935         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
936         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
937         // FIXME add TraceBrush!
938         loadmodel->PointSuperContents = NULL;
939
940         loadmodel->num_surfaces = 1;
941         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
942         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
943         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
944         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
945         loadmodel->sortedmodelsurfaces[0] = 0;
946
947         loadmodel->numskins = LittleLong(pinmodel->numskins);
948         BOUNDI(loadmodel->numskins,0,65536);
949         skinwidth = LittleLong (pinmodel->skinwidth);
950         BOUNDI(skinwidth,0,65536);
951         skinheight = LittleLong (pinmodel->skinheight);
952         BOUNDI(skinheight,0,65536);
953         numverts = LittleLong(pinmodel->numverts);
954         BOUNDI(numverts,0,65536);
955         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
956         BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
957         loadmodel->numframes = LittleLong(pinmodel->numframes);
958         BOUNDI(loadmodel->numframes,0,65536);
959         loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
960         BOUNDI((int)loadmodel->synctype,0,2);
961         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
962         i = LittleLong (pinmodel->flags);
963         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
964
965         for (i = 0;i < 3;i++)
966         {
967                 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
968                 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
969         }
970
971         startskins = datapointer;
972         totalskins = 0;
973         for (i = 0;i < loadmodel->numskins;i++)
974         {
975                 pinskintype = (daliasskintype_t *)datapointer;
976                 datapointer += sizeof(daliasskintype_t);
977                 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
978                         groupskins = 1;
979                 else
980                 {
981                         pinskingroup = (daliasskingroup_t *)datapointer;
982                         datapointer += sizeof(daliasskingroup_t);
983                         groupskins = LittleLong(pinskingroup->numskins);
984                         datapointer += sizeof(daliasskininterval_t) * groupskins;
985                 }
986
987                 for (j = 0;j < groupskins;j++)
988                 {
989                         datapointer += skinwidth * skinheight;
990                         totalskins++;
991                 }
992         }
993
994         pinstverts = (stvert_t *)datapointer;
995         datapointer += sizeof(stvert_t) * numverts;
996
997         pintriangles = (dtriangle_t *)datapointer;
998         datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
999
1000         startframes = datapointer;
1001         loadmodel->surfmesh.num_morphframes = 0;
1002         for (i = 0;i < loadmodel->numframes;i++)
1003         {
1004                 pinframetype = (daliasframetype_t *)datapointer;
1005                 datapointer += sizeof(daliasframetype_t);
1006                 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1007                         groupframes = 1;
1008                 else
1009                 {
1010                         pinframegroup = (daliasgroup_t *)datapointer;
1011                         datapointer += sizeof(daliasgroup_t);
1012                         groupframes = LittleLong(pinframegroup->numframes);
1013                         datapointer += sizeof(daliasinterval_t) * groupframes;
1014                 }
1015
1016                 for (j = 0;j < groupframes;j++)
1017                 {
1018                         datapointer += sizeof(daliasframe_t);
1019                         datapointer += sizeof(trivertx_t) * numverts;
1020                         loadmodel->surfmesh.num_morphframes++;
1021                 }
1022         }
1023         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1024
1025         // store texture coordinates into temporary array, they will be stored
1026         // after usage is determined (triangle data)
1027         vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1028         vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1029         vertonseam = vertremap + numverts * 2;
1030
1031         scales = 1.0 / skinwidth;
1032         scalet = 1.0 / skinheight;
1033         for (i = 0;i < numverts;i++)
1034         {
1035                 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1036                 vertst[i*2+0] = (LittleLong(pinstverts[i].s) + 0.5) * scales;
1037                 vertst[i*2+1] = (LittleLong(pinstverts[i].t) + 0.5) * scalet;
1038                 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1039                 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1040         }
1041
1042 // load triangle data
1043         loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1044
1045         // read the triangle elements
1046         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1047                 for (j = 0;j < 3;j++)
1048                         loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1049         // validate (note numverts is used because this is the original data)
1050         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1051         // now butcher the elements according to vertonseam and tri->facesfront
1052         // and then compact the vertex set to remove duplicates
1053         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1054                 if (!LittleLong(pintriangles[i].facesfront)) // backface
1055                         for (j = 0;j < 3;j++)
1056                                 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1057                                         loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1058         // count the usage
1059         // (this uses vertremap to count usage to save some memory)
1060         for (i = 0;i < numverts*2;i++)
1061                 vertremap[i] = 0;
1062         for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1063                 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1064         // build remapping table and compact array
1065         loadmodel->surfmesh.num_vertices = 0;
1066         for (i = 0;i < numverts*2;i++)
1067         {
1068                 if (vertremap[i])
1069                 {
1070                         vertremap[i] = loadmodel->surfmesh.num_vertices;
1071                         vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1072                         vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1073                         loadmodel->surfmesh.num_vertices++;
1074                 }
1075                 else
1076                         vertremap[i] = -1; // not used at all
1077         }
1078         // remap the elements to the new vertex set
1079         for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1080                 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1081         // store the texture coordinates
1082         loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1083         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1084         {
1085                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1086                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1087         }
1088
1089         // generate ushort elements array if possible
1090         if (loadmodel->surfmesh.num_vertices <= 65536)
1091                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1092         if (loadmodel->surfmesh.data_element3s)
1093                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1094                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1095
1096 // load the frames
1097         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1098         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1099         if (r_enableshadowvolumes.integer)
1100         {
1101                 loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1102         }
1103         Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1104         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices; // needed during loading, may be cleared by code later in this function
1105         if (loadmodel->surfmesh.data_neighbor3i)
1106                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1107         Mod_Alias_CalculateBoundingBox();
1108         Mod_Alias_MorphMesh_CompileFrames();
1109         loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MDL_AnimateVertices : NULL;
1110
1111         Mem_Free(vertst);
1112         Mem_Free(vertremap);
1113
1114         // load the skins
1115         skinfiles = Mod_LoadSkinFiles();
1116         if (skinfiles)
1117         {
1118                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1119                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1120                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1121                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1122                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1123                 Mod_FreeSkinFiles(skinfiles);
1124                 for (i = 0;i < loadmodel->numskins;i++)
1125                 {
1126                         loadmodel->skinscenes[i].firstframe = i;
1127                         loadmodel->skinscenes[i].framecount = 1;
1128                         loadmodel->skinscenes[i].loop = true;
1129                         loadmodel->skinscenes[i].framerate = 10;
1130                 }
1131         }
1132         else
1133         {
1134                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1135                 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1136                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1137                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1138                 totalskins = 0;
1139                 datapointer = startskins;
1140                 for (i = 0;i < loadmodel->numskins;i++)
1141                 {
1142                         pinskintype = (daliasskintype_t *)datapointer;
1143                         datapointer += sizeof(daliasskintype_t);
1144
1145                         if (pinskintype->type == ALIAS_SKIN_SINGLE)
1146                         {
1147                                 groupskins = 1;
1148                                 interval = 0.1f;
1149                         }
1150                         else
1151                         {
1152                                 pinskingroup = (daliasskingroup_t *)datapointer;
1153                                 datapointer += sizeof(daliasskingroup_t);
1154
1155                                 groupskins = LittleLong (pinskingroup->numskins);
1156
1157                                 pinskinintervals = (daliasskininterval_t *)datapointer;
1158                                 datapointer += sizeof(daliasskininterval_t) * groupskins;
1159
1160                                 interval = LittleFloat(pinskinintervals[0].interval);
1161                                 if (interval < 0.01f)
1162                                 {
1163                                         Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1164                                         interval = 0.1f;
1165                                 }
1166                         }
1167
1168                         dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1169                         loadmodel->skinscenes[i].firstframe = totalskins;
1170                         loadmodel->skinscenes[i].framecount = groupskins;
1171                         loadmodel->skinscenes[i].framerate = 1.0f / interval;
1172                         loadmodel->skinscenes[i].loop = true;
1173
1174                         for (j = 0;j < groupskins;j++)
1175                         {
1176                                 if (groupskins > 1)
1177                                         dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1178                                 else
1179                                         dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1180                                 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))
1181                                         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));
1182                                 datapointer += skinwidth * skinheight;
1183                                 totalskins++;
1184                         }
1185                 }
1186                 // check for skins that don't exist in the model, but do exist as external images
1187                 // (this was added because yummyluv kept pestering me about support for it)
1188                 // TODO: support shaders here?
1189                 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)))
1190                 {
1191                         // expand the arrays to make room
1192                         tempskinscenes = loadmodel->skinscenes;
1193                         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1194                         memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1195                         Mem_Free(tempskinscenes);
1196
1197                         tempaliasskins = loadmodel->data_textures;
1198                         loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1199                         memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1200                         Mem_Free(tempaliasskins);
1201
1202                         // store the info about the new skin
1203                         Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
1204                         strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1205                         loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1206                         loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1207                         loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1208                         loadmodel->skinscenes[loadmodel->numskins].loop = true;
1209
1210                         //increase skin counts
1211                         loadmodel->numskins++;
1212                         totalskins++;
1213
1214                         // fix up the pointers since they are pointing at the old textures array
1215                         // FIXME: this is a hack!
1216                         for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1217                                 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1218                 }
1219         }
1220
1221         surface = loadmodel->data_surfaces;
1222         surface->texture = loadmodel->data_textures;
1223         surface->num_firsttriangle = 0;
1224         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1225         surface->num_firstvertex = 0;
1226         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1227
1228         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
1229         loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MDL_AnimateVertices : NULL;
1230
1231         if (!loadmodel->surfmesh.isanimated)
1232         {
1233                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1234                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1235                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1236                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1237                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1238                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1239         }
1240
1241         // because shaders can do somewhat unexpected things, check for unusual features now
1242         for (i = 0;i < loadmodel->num_textures;i++)
1243         {
1244                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1245                         mod->DrawSky = R_Q1BSP_DrawSky;
1246                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1247                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1248         }
1249 }
1250
1251 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1252 {
1253         int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1254         float iskinwidth, iskinheight;
1255         unsigned char *data;
1256         msurface_t *surface;
1257         md2_t *pinmodel;
1258         unsigned char *base, *datapointer;
1259         md2frame_t *pinframe;
1260         char *inskin;
1261         md2triangle_t *intri;
1262         unsigned short *inst;
1263         struct md2verthash_s
1264         {
1265                 struct md2verthash_s *next;
1266                 unsigned short xyz;
1267                 unsigned short st;
1268         }
1269         *hash, **md2verthash, *md2verthashdata;
1270         skinfile_t *skinfiles;
1271
1272         pinmodel = (md2_t *)buffer;
1273         base = (unsigned char *)buffer;
1274
1275         version = LittleLong (pinmodel->version);
1276         if (version != MD2ALIAS_VERSION)
1277                 Host_Error ("%s has wrong version number (%i should be %i)",
1278                         loadmodel->name, version, MD2ALIAS_VERSION);
1279
1280         loadmodel->modeldatatypestring = "MD2";
1281
1282         loadmodel->type = mod_alias;
1283         loadmodel->DrawSky = NULL;
1284         loadmodel->DrawAddWaterPlanes = NULL;
1285         loadmodel->Draw = R_Q1BSP_Draw;
1286         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1287         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1288         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1289         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1290         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1291         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1292         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1293         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1294         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1295         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1296         loadmodel->PointSuperContents = NULL;
1297
1298         if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1299                 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1300         if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1301                 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1302         if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1303                 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1304         if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1305                 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1306
1307         end = LittleLong(pinmodel->ofs_end);
1308         if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1309                 Host_Error ("%s is not a valid model", loadmodel->name);
1310         if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1311                 Host_Error ("%s is not a valid model", loadmodel->name);
1312         if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1313                 Host_Error ("%s is not a valid model", loadmodel->name);
1314         if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1315                 Host_Error ("%s is not a valid model", loadmodel->name);
1316         if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1317                 Host_Error ("%s is not a valid model", loadmodel->name);
1318
1319         loadmodel->numskins = LittleLong(pinmodel->num_skins);
1320         numxyz = LittleLong(pinmodel->num_xyz);
1321         numst = LittleLong(pinmodel->num_st);
1322         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1323         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1324         loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1325         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1326         skinwidth = LittleLong(pinmodel->skinwidth);
1327         skinheight = LittleLong(pinmodel->skinheight);
1328         iskinwidth = 1.0f / skinwidth;
1329         iskinheight = 1.0f / skinheight;
1330
1331         loadmodel->num_surfaces = 1;
1332         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1333         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));
1334         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1335         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1336         loadmodel->sortedmodelsurfaces[0] = 0;
1337         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1338         loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1339         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1340         if (r_enableshadowvolumes.integer)
1341         {
1342                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1343         }
1344
1345         loadmodel->synctype = ST_RAND;
1346
1347         // load the skins
1348         inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1349         skinfiles = Mod_LoadSkinFiles();
1350         if (skinfiles)
1351         {
1352                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1353                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1354                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1355                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1356                 Mod_FreeSkinFiles(skinfiles);
1357         }
1358         else if (loadmodel->numskins)
1359         {
1360                 // skins found (most likely not a player model)
1361                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1362                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1363                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1364                 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1365                         Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
1366         }
1367         else
1368         {
1369                 // no skins (most likely a player model)
1370                 loadmodel->numskins = 1;
1371                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1372                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1373                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1374                 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL);
1375         }
1376
1377         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1378         for (i = 0;i < loadmodel->numskins;i++)
1379         {
1380                 loadmodel->skinscenes[i].firstframe = i;
1381                 loadmodel->skinscenes[i].framecount = 1;
1382                 loadmodel->skinscenes[i].loop = true;
1383                 loadmodel->skinscenes[i].framerate = 10;
1384         }
1385
1386         // load the triangles and stvert data
1387         inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1388         intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1389         md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1390         md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1391         // swap the triangle list
1392         loadmodel->surfmesh.num_vertices = 0;
1393         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1394         {
1395                 for (j = 0;j < 3;j++)
1396                 {
1397                         xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1398                         st = (unsigned short) LittleShort (intri[i].index_st[j]);
1399                         if (xyz >= numxyz)
1400                         {
1401                                 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1402                                 xyz = 0;
1403                         }
1404                         if (st >= numst)
1405                         {
1406                                 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1407                                 st = 0;
1408                         }
1409                         hashindex = (xyz * 256 + st) & 65535;
1410                         for (hash = md2verthash[hashindex];hash;hash = hash->next)
1411                                 if (hash->xyz == xyz && hash->st == st)
1412                                         break;
1413                         if (hash == NULL)
1414                         {
1415                                 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1416                                 hash->xyz = xyz;
1417                                 hash->st = st;
1418                                 hash->next = md2verthash[hashindex];
1419                                 md2verthash[hashindex] = hash;
1420                         }
1421                         loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1422                 }
1423         }
1424
1425         vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1426         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));
1427         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1428         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1429         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1430         {
1431                 int sts, stt;
1432                 hash = md2verthashdata + i;
1433                 vertremap[i] = hash->xyz;
1434                 sts = LittleShort(inst[hash->st*2+0]);
1435                 stt = LittleShort(inst[hash->st*2+1]);
1436                 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1437                 {
1438                         Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1439                         sts = 0;
1440                         stt = 0;
1441                 }
1442                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1443                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1444         }
1445
1446         Mem_Free(md2verthash);
1447         Mem_Free(md2verthashdata);
1448
1449         // generate ushort elements array if possible
1450         if (loadmodel->surfmesh.num_vertices <= 65536)
1451                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1452         if (loadmodel->surfmesh.data_element3s)
1453                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1454                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1455
1456         // load the frames
1457         datapointer = (base + LittleLong(pinmodel->ofs_frames));
1458         for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1459         {
1460                 int k;
1461                 trivertx_t *v;
1462                 trivertx_t *out;
1463                 pinframe = (md2frame_t *)datapointer;
1464                 datapointer += sizeof(md2frame_t);
1465                 // store the frame scale/translate into the appropriate array
1466                 for (j = 0;j < 3;j++)
1467                 {
1468                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1469                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1470                 }
1471                 // convert the vertices
1472                 v = (trivertx_t *)datapointer;
1473                 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1474                 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1475                         out[k] = v[vertremap[k]];
1476                 datapointer += numxyz * sizeof(trivertx_t);
1477
1478                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1479                 loadmodel->animscenes[i].firstframe = i;
1480                 loadmodel->animscenes[i].framecount = 1;
1481                 loadmodel->animscenes[i].framerate = 10;
1482                 loadmodel->animscenes[i].loop = true;
1483         }
1484
1485         Mem_Free(vertremap);
1486
1487         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
1488         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices; // needed during loading, may be cleared by code later in this function
1489         if (loadmodel->surfmesh.data_neighbor3i)
1490                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1491         Mod_Alias_CalculateBoundingBox();
1492         Mod_Alias_MorphMesh_CompileFrames();
1493         loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MDL_AnimateVertices : NULL;
1494
1495         surface = loadmodel->data_surfaces;
1496         surface->texture = loadmodel->data_textures;
1497         surface->num_firsttriangle = 0;
1498         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1499         surface->num_firstvertex = 0;
1500         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1501
1502         if (!loadmodel->surfmesh.isanimated)
1503         {
1504                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1505                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1506                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1507                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1508                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1509                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1510         }
1511
1512         // because shaders can do somewhat unexpected things, check for unusual features now
1513         for (i = 0;i < loadmodel->num_textures;i++)
1514         {
1515                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1516                         mod->DrawSky = R_Q1BSP_DrawSky;
1517                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1518                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1519         }
1520 }
1521
1522 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1523 {
1524         int i, j, k, version, meshvertices, meshtriangles;
1525         unsigned char *data;
1526         msurface_t *surface;
1527         md3modelheader_t *pinmodel;
1528         md3frameinfo_t *pinframe;
1529         md3mesh_t *pinmesh;
1530         md3tag_t *pintag;
1531         skinfile_t *skinfiles;
1532
1533         pinmodel = (md3modelheader_t *)buffer;
1534
1535         if (memcmp(pinmodel->identifier, "IDP3", 4))
1536                 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1537         version = LittleLong (pinmodel->version);
1538         if (version != MD3VERSION)
1539                 Host_Error ("%s has wrong version number (%i should be %i)",
1540                         loadmodel->name, version, MD3VERSION);
1541
1542         skinfiles = Mod_LoadSkinFiles();
1543         if (loadmodel->numskins < 1)
1544                 loadmodel->numskins = 1;
1545
1546         loadmodel->modeldatatypestring = "MD3";
1547
1548         loadmodel->type = mod_alias;
1549         loadmodel->DrawSky = NULL;
1550         loadmodel->DrawAddWaterPlanes = NULL;
1551         loadmodel->Draw = R_Q1BSP_Draw;
1552         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1553         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1554         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1555         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1556         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1557         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1558         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1559         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1560         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1561         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1562         loadmodel->PointSuperContents = NULL;
1563         loadmodel->synctype = ST_RAND;
1564         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1565         i = LittleLong (pinmodel->flags);
1566         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1567
1568         // set up some global info about the model
1569         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1570         loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1571
1572         // make skinscenes for the skins (no groups)
1573         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1574         for (i = 0;i < loadmodel->numskins;i++)
1575         {
1576                 loadmodel->skinscenes[i].firstframe = i;
1577                 loadmodel->skinscenes[i].framecount = 1;
1578                 loadmodel->skinscenes[i].loop = true;
1579                 loadmodel->skinscenes[i].framerate = 10;
1580         }
1581
1582         // load frameinfo
1583         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1584         for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1585         {
1586                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1587                 loadmodel->animscenes[i].firstframe = i;
1588                 loadmodel->animscenes[i].framecount = 1;
1589                 loadmodel->animscenes[i].framerate = 10;
1590                 loadmodel->animscenes[i].loop = true;
1591         }
1592
1593         // load tags
1594         loadmodel->num_tagframes = loadmodel->numframes;
1595         loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1596         loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1597         for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1598         {
1599                 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1600                 for (j = 0;j < 9;j++)
1601                         loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1602                 for (j = 0;j < 3;j++)
1603                         loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1604                 //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);
1605         }
1606
1607         // load meshes
1608         meshvertices = 0;
1609         meshtriangles = 0;
1610         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)))
1611         {
1612                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1613                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1614                 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1615                         Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1616                 meshvertices += LittleLong(pinmesh->num_vertices);
1617                 meshtriangles += LittleLong(pinmesh->num_triangles);
1618         }
1619
1620         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1621         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1622         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1623         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));
1624         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1625         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1626         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1627         loadmodel->surfmesh.num_vertices = meshvertices;
1628         loadmodel->surfmesh.num_triangles = meshtriangles;
1629         loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1630         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1631         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1632         if (r_enableshadowvolumes.integer)
1633         {
1634                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1635         }
1636         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1637         loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1638         if (meshvertices <= 65536)
1639         {
1640                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1641         }
1642
1643         meshvertices = 0;
1644         meshtriangles = 0;
1645         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)))
1646         {
1647                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1648                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1649                 loadmodel->sortedmodelsurfaces[i] = i;
1650                 surface = loadmodel->data_surfaces + i;
1651                 surface->texture = loadmodel->data_textures + i;
1652                 surface->num_firsttriangle = meshtriangles;
1653                 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1654                 surface->num_firstvertex = meshvertices;
1655                 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1656                 meshvertices += surface->num_vertices;
1657                 meshtriangles += surface->num_triangles;
1658
1659                 for (j = 0;j < surface->num_triangles * 3;j++)
1660                         loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1661                 for (j = 0;j < surface->num_vertices;j++)
1662                 {
1663                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1664                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1665                 }
1666                 for (j = 0;j < loadmodel->numframes;j++)
1667                 {
1668                         const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1669                         md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1670                         for (k = 0;k < surface->num_vertices;k++, in++, out++)
1671                         {
1672                                 out->origin[0] = LittleShort(in->origin[0]);
1673                                 out->origin[1] = LittleShort(in->origin[1]);
1674                                 out->origin[2] = LittleShort(in->origin[2]);
1675                                 out->pitch = in->pitch;
1676                                 out->yaw = in->yaw;
1677                         }
1678                 }
1679
1680                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1681
1682                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1683         }
1684         if (loadmodel->surfmesh.data_element3s)
1685                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1686                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1687         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
1688         loadmodel->AnimateVertices = Mod_MD3_AnimateVertices; // needed during loading, may be cleared by code later in this function
1689         if (loadmodel->surfmesh.data_neighbor3i)
1690                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1691         Mod_Alias_MorphMesh_CompileFrames();
1692         Mod_Alias_CalculateBoundingBox();
1693         Mod_FreeSkinFiles(skinfiles);
1694         Mod_MakeSortedSurfaces(loadmodel);
1695         loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MD3_AnimateVertices : NULL;
1696
1697         if (!loadmodel->surfmesh.isanimated)
1698         {
1699                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1700                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1701                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1702                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1703                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1704                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1705         }
1706
1707         // because shaders can do somewhat unexpected things, check for unusual features now
1708         for (i = 0;i < loadmodel->num_textures;i++)
1709         {
1710                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1711                         mod->DrawSky = R_Q1BSP_DrawSky;
1712                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1713                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1714         }
1715 }
1716
1717 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1718 {
1719         zymtype1header_t *pinmodel, *pheader;
1720         unsigned char *pbase;
1721         int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1722         float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1723         zymvertex_t *verts, *vertdata;
1724         zymscene_t *scene;
1725         zymbone_t *bone;
1726         char *shadername;
1727         skinfile_t *skinfiles;
1728         unsigned char *data;
1729         msurface_t *surface;
1730
1731         pinmodel = (zymtype1header_t *)buffer;
1732         pbase = (unsigned char *)buffer;
1733         if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1734                 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1735         if (BigLong(pinmodel->type) != 1)
1736                 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1737
1738         loadmodel->modeldatatypestring = "ZYM";
1739
1740         loadmodel->type = mod_alias;
1741         loadmodel->synctype = ST_RAND;
1742
1743         // byteswap header
1744         pheader = pinmodel;
1745         pheader->type = BigLong(pinmodel->type);
1746         pheader->filesize = BigLong(pinmodel->filesize);
1747         pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1748         pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1749         pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1750         pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1751         pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1752         pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1753         pheader->radius = BigFloat(pinmodel->radius);
1754         pheader->numverts = BigLong(pinmodel->numverts);
1755         pheader->numtris = BigLong(pinmodel->numtris);
1756         pheader->numshaders = BigLong(pinmodel->numshaders);
1757         pheader->numbones = BigLong(pinmodel->numbones);
1758         pheader->numscenes = BigLong(pinmodel->numscenes);
1759         pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1760         pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1761         pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1762         pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1763         pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1764         pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1765         pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1766         pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1767         pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1768         pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1769         pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1770         pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1771         pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1772         pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1773         pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1774         pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1775         pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1776         pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1777
1778         if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1779         {
1780                 Con_Printf("%s has no geometry\n", loadmodel->name);
1781                 return;
1782         }
1783         if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1784         {
1785                 Con_Printf("%s has no animations\n", loadmodel->name);
1786                 return;
1787         }
1788
1789         loadmodel->DrawSky = NULL;
1790         loadmodel->DrawAddWaterPlanes = NULL;
1791         loadmodel->Draw = R_Q1BSP_Draw;
1792         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1793         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1794         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1795         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1796         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1797         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1798         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1799         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1800         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1801         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1802         loadmodel->PointSuperContents = NULL;
1803
1804         loadmodel->numframes = pheader->numscenes;
1805         loadmodel->num_surfaces = pheader->numshaders;
1806
1807         skinfiles = Mod_LoadSkinFiles();
1808         if (loadmodel->numskins < 1)
1809                 loadmodel->numskins = 1;
1810
1811         // make skinscenes for the skins (no groups)
1812         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1813         for (i = 0;i < loadmodel->numskins;i++)
1814         {
1815                 loadmodel->skinscenes[i].firstframe = i;
1816                 loadmodel->skinscenes[i].framecount = 1;
1817                 loadmodel->skinscenes[i].loop = true;
1818                 loadmodel->skinscenes[i].framerate = 10;
1819         }
1820
1821         // model bbox
1822         modelradius = pheader->radius;
1823         for (i = 0;i < 3;i++)
1824         {
1825                 loadmodel->normalmins[i] = pheader->mins[i];
1826                 loadmodel->normalmaxs[i] = pheader->maxs[i];
1827                 loadmodel->rotatedmins[i] = -modelradius;
1828                 loadmodel->rotatedmaxs[i] = modelradius;
1829         }
1830         corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1831         corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1832         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1833         if (loadmodel->yawmaxs[0] > modelradius)
1834                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1835         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1836         loadmodel->yawmins[2] = loadmodel->normalmins[2];
1837         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1838         loadmodel->radius = modelradius;
1839         loadmodel->radius2 = modelradius * modelradius;
1840
1841         // go through the lumps, swapping things
1842
1843         //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1844         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1845         scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1846         numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1847         for (i = 0;i < pheader->numscenes;i++)
1848         {
1849                 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1850                 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1851                 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1852                 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1853                 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1854                 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1855                         Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1856                 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1857                         Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1858                 if (loadmodel->animscenes[i].framerate < 0)
1859                         Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1860                 scene++;
1861         }
1862
1863         //zymlump_t lump_bones; // zymbone_t bone[numbones];
1864         loadmodel->num_bones = pheader->numbones;
1865         loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1866         bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1867         for (i = 0;i < pheader->numbones;i++)
1868         {
1869                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1870                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1871                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1872                 if (loadmodel->data_bones[i].parent >= i)
1873                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1874         }
1875
1876         //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1877         vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1878         bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1879         for (i = 0;i < pheader->numverts;i++)
1880         {
1881                 vertbonecounts[i] = BigLong(bonecount[i]);
1882                 if (vertbonecounts[i] != 1)
1883                         Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1884         }
1885
1886         loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1887
1888         meshvertices = pheader->numverts;
1889         meshtriangles = pheader->numtris;
1890
1891         loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
1892         loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
1893         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1894         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1895         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1896         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]));
1897         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1898         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1899         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1900         loadmodel->surfmesh.num_vertices = meshvertices;
1901         loadmodel->surfmesh.num_triangles = meshtriangles;
1902         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1903         if (r_enableshadowvolumes.integer)
1904         {
1905                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1906         }
1907         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1908         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1909         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1910         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1911         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1912         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1913         loadmodel->surfmesh.num_blends = 0;
1914         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
1915         if (loadmodel->surfmesh.num_vertices <= 65536)
1916         {
1917                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1918         }
1919         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
1920         loadmodel->surfmesh.data_blendweights = NULL;
1921
1922         //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1923         poses = (float *) (pheader->lump_poses.start + pbase);
1924         // figure out scale of model from root bone, for compatibility with old zmodel versions
1925         tempvec[0] = BigFloat(poses[0]);
1926         tempvec[1] = BigFloat(poses[1]);
1927         tempvec[2] = BigFloat(poses[2]);
1928         modelscale = VectorLength(tempvec);
1929         biggestorigin = 0;
1930         for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
1931         {
1932                 f = fabs(BigFloat(poses[i]));
1933                 biggestorigin = max(biggestorigin, f);
1934         }
1935         loadmodel->num_posescale = biggestorigin / 32767.0f;
1936         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
1937         for (i = 0;i < numposes;i++)
1938         {
1939                 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
1940                 for (j = 0;j < loadmodel->num_bones;j++)
1941                 {
1942                         float pose[12];
1943                         matrix4x4_t posematrix;
1944                         for (k = 0;k < 12;k++)
1945                                 pose[k] = BigFloat(frameposes[j*12+k]);
1946                         //if (j < loadmodel->num_bones)
1947                         //      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));
1948                         // scale child bones to match the root scale
1949                         if (loadmodel->data_bones[j].parent >= 0)
1950                         {
1951                                 pose[3] *= modelscale;
1952                                 pose[7] *= modelscale;
1953                                 pose[11] *= modelscale;
1954                         }
1955                         // normalize rotation matrix
1956                         VectorNormalize(pose + 0);
1957                         VectorNormalize(pose + 4);
1958                         VectorNormalize(pose + 8);
1959                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
1960                         Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*(i*loadmodel->num_bones+j));
1961                 }
1962         }
1963
1964         //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
1965         verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
1966         vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
1967         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
1968         // (converting from weight-blending skeletal animation to
1969         //  deformation-based skeletal animation)
1970         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
1971         for (i = 0;i < loadmodel->num_bones;i++)
1972         {
1973                 float m[12];
1974                 for (k = 0;k < 12;k++)
1975                         m[k] = BigFloat(poses[i*12+k]);
1976                 if (loadmodel->data_bones[i].parent >= 0)
1977                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
1978                 else
1979                         for (k = 0;k < 12;k++)
1980                                 bonepose[12*i+k] = m[k];
1981         }
1982         for (j = 0;j < pheader->numverts;j++)
1983         {
1984                 // this format really should have had a per vertexweight weight value...
1985                 // but since it does not, the weighting is completely ignored and
1986                 // only one weight is allowed per vertex
1987                 int boneindex = BigLong(vertdata[j].bonenum);
1988                 const float *m = bonepose + 12 * boneindex;
1989                 float relativeorigin[3];
1990                 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
1991                 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
1992                 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
1993                 // transform the vertex bone weight into the base mesh
1994                 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
1995                 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
1996                 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
1997                 // store the weight as the primary weight on this vertex
1998                 loadmodel->surfmesh.blends[j] = boneindex;
1999         }
2000         Z_Free(bonepose);
2001         // normals and tangents are calculated after elements are loaded
2002
2003         //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2004         outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2005         intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2006         for (i = 0;i < pheader->numverts;i++)
2007         {
2008                 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2009                 // flip T coordinate for OpenGL
2010                 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2011         }
2012
2013         //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2014         //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2015         //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2016
2017         //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2018         //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)
2019         // byteswap, validate, and swap winding order of tris
2020         count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2021         if (pheader->lump_render.length != count)
2022                 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2023         renderlist = (int *) (pheader->lump_render.start + pbase);
2024         renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2025         meshtriangles = 0;
2026         for (i = 0;i < loadmodel->num_surfaces;i++)
2027         {
2028                 int firstvertex, lastvertex;
2029                 if (renderlist >= renderlistend)
2030                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2031                 count = BigLong(*renderlist);renderlist++;
2032                 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2033                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2034
2035                 loadmodel->sortedmodelsurfaces[i] = i;
2036                 surface = loadmodel->data_surfaces + i;
2037                 surface->texture = loadmodel->data_textures + i;
2038                 surface->num_firsttriangle = meshtriangles;
2039                 surface->num_triangles = count;
2040                 meshtriangles += surface->num_triangles;
2041
2042                 // load the elements
2043                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2044                 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2045                 {
2046                         outelements[j*3+2] = BigLong(renderlist[0]);
2047                         outelements[j*3+1] = BigLong(renderlist[1]);
2048                         outelements[j*3+0] = BigLong(renderlist[2]);
2049                 }
2050                 // validate the elements and find the used vertex range
2051                 firstvertex = meshvertices;
2052                 lastvertex = 0;
2053                 for (j = 0;j < surface->num_triangles * 3;j++)
2054                 {
2055                         if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2056                                 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2057                         firstvertex = min(firstvertex, outelements[j]);
2058                         lastvertex = max(lastvertex, outelements[j]);
2059                 }
2060                 surface->num_firstvertex = firstvertex;
2061                 surface->num_vertices = lastvertex + 1 - firstvertex;
2062
2063                 // since zym models do not have named sections, reuse their shader
2064                 // name as the section name
2065                 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2066                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2067         }
2068         Mod_FreeSkinFiles(skinfiles);
2069         Mem_Free(vertbonecounts);
2070         Mem_Free(verts);
2071         Mod_MakeSortedSurfaces(loadmodel);
2072
2073         // compute all the mesh information that was not loaded from the file
2074         if (loadmodel->surfmesh.data_element3s)
2075                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2076                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2077         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2078         Mod_BuildBaseBonePoses();
2079         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);
2080         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);
2081         if (loadmodel->surfmesh.data_neighbor3i)
2082                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2083
2084         if (!loadmodel->surfmesh.isanimated)
2085         {
2086                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2087                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2088                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2089                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2090                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2091                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2092         }
2093
2094         // because shaders can do somewhat unexpected things, check for unusual features now
2095         for (i = 0;i < loadmodel->num_textures;i++)
2096         {
2097                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2098                         mod->DrawSky = R_Q1BSP_DrawSky;
2099                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2100                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2101         }
2102 }
2103
2104 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2105 {
2106         dpmheader_t *pheader;
2107         dpmframe_t *frames;
2108         dpmbone_t *bone;
2109         dpmmesh_t *dpmmesh;
2110         unsigned char *pbase;
2111         int i, j, k, meshvertices, meshtriangles;
2112         skinfile_t *skinfiles;
2113         unsigned char *data;
2114         float *bonepose;
2115         float biggestorigin, tempvec[3], modelscale;
2116         float f;
2117         float *poses;
2118
2119         pheader = (dpmheader_t *)buffer;
2120         pbase = (unsigned char *)buffer;
2121         if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2122                 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2123         if (BigLong(pheader->type) != 2)
2124                 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2125
2126         loadmodel->modeldatatypestring = "DPM";
2127
2128         loadmodel->type = mod_alias;
2129         loadmodel->synctype = ST_RAND;
2130
2131         // byteswap header
2132         pheader->type = BigLong(pheader->type);
2133         pheader->filesize = BigLong(pheader->filesize);
2134         pheader->mins[0] = BigFloat(pheader->mins[0]);
2135         pheader->mins[1] = BigFloat(pheader->mins[1]);
2136         pheader->mins[2] = BigFloat(pheader->mins[2]);
2137         pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2138         pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2139         pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2140         pheader->yawradius = BigFloat(pheader->yawradius);
2141         pheader->allradius = BigFloat(pheader->allradius);
2142         pheader->num_bones = BigLong(pheader->num_bones);
2143         pheader->num_meshs = BigLong(pheader->num_meshs);
2144         pheader->num_frames = BigLong(pheader->num_frames);
2145         pheader->ofs_bones = BigLong(pheader->ofs_bones);
2146         pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2147         pheader->ofs_frames = BigLong(pheader->ofs_frames);
2148
2149         if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2150         {
2151                 Con_Printf("%s has no geometry\n", loadmodel->name);
2152                 return;
2153         }
2154         if (pheader->num_frames < 1)
2155         {
2156                 Con_Printf("%s has no frames\n", loadmodel->name);
2157                 return;
2158         }
2159
2160         loadmodel->DrawSky = NULL;
2161         loadmodel->DrawAddWaterPlanes = NULL;
2162         loadmodel->Draw = R_Q1BSP_Draw;
2163         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2164         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2165         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2166         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2167         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2168         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2169         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2170         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2171         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2172         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2173         loadmodel->PointSuperContents = NULL;
2174
2175         // model bbox
2176         for (i = 0;i < 3;i++)
2177         {
2178                 loadmodel->normalmins[i] = pheader->mins[i];
2179                 loadmodel->normalmaxs[i] = pheader->maxs[i];
2180                 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2181                 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2182                 loadmodel->rotatedmins[i] = -pheader->allradius;
2183                 loadmodel->rotatedmaxs[i] = pheader->allradius;
2184         }
2185         loadmodel->radius = pheader->allradius;
2186         loadmodel->radius2 = pheader->allradius * pheader->allradius;
2187
2188         // load external .skin files if present
2189         skinfiles = Mod_LoadSkinFiles();
2190         if (loadmodel->numskins < 1)
2191                 loadmodel->numskins = 1;
2192
2193         meshvertices = 0;
2194         meshtriangles = 0;
2195
2196         // gather combined statistics from the meshes
2197         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2198         for (i = 0;i < (int)pheader->num_meshs;i++)
2199         {
2200                 int numverts = BigLong(dpmmesh->num_verts);
2201                 meshvertices += numverts;
2202                 meshtriangles += BigLong(dpmmesh->num_tris);
2203                 dpmmesh++;
2204         }
2205
2206         loadmodel->numframes = pheader->num_frames;
2207         loadmodel->num_bones = pheader->num_bones;
2208         loadmodel->num_poses = loadmodel->numframes;
2209         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2210         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2211         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2212         loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
2213         loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
2214         // do most allocations as one merged chunk
2215         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));
2216         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2217         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2218         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2219         loadmodel->surfmesh.num_vertices = meshvertices;
2220         loadmodel->surfmesh.num_triangles = meshtriangles;
2221         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2222         if (r_enableshadowvolumes.integer)
2223         {
2224                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2225         }
2226         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2227         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2228         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2229         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2230         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2231         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2232         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2233         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2234         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2235         loadmodel->surfmesh.num_blends = 0;
2236         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2237         if (meshvertices <= 65536)
2238         {
2239                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2240         }
2241         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
2242         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2243
2244         for (i = 0;i < loadmodel->numskins;i++)
2245         {
2246                 loadmodel->skinscenes[i].firstframe = i;
2247                 loadmodel->skinscenes[i].framecount = 1;
2248                 loadmodel->skinscenes[i].loop = true;
2249                 loadmodel->skinscenes[i].framerate = 10;
2250         }
2251
2252         // load the bone info
2253         bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2254         for (i = 0;i < loadmodel->num_bones;i++)
2255         {
2256                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2257                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2258                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2259                 if (loadmodel->data_bones[i].parent >= i)
2260                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2261         }
2262
2263         // load the frames
2264         frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2265         // figure out scale of model from root bone, for compatibility with old dpmodel versions
2266         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2267         tempvec[0] = BigFloat(poses[0]);
2268         tempvec[1] = BigFloat(poses[1]);
2269         tempvec[2] = BigFloat(poses[2]);
2270         modelscale = VectorLength(tempvec);
2271         biggestorigin = 0;
2272         for (i = 0;i < loadmodel->numframes;i++)
2273         {
2274                 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2275                 loadmodel->animscenes[i].firstframe = i;
2276                 loadmodel->animscenes[i].framecount = 1;
2277                 loadmodel->animscenes[i].loop = true;
2278                 loadmodel->animscenes[i].framerate = 10;
2279                 // load the bone poses for this frame
2280                 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2281                 for (j = 0;j < loadmodel->num_bones*12;j++)
2282                 {
2283                         f = fabs(BigFloat(poses[j]));
2284                         biggestorigin = max(biggestorigin, f);
2285                 }
2286                 // stuff not processed here: mins, maxs, yawradius, allradius
2287         }
2288         loadmodel->num_posescale = biggestorigin / 32767.0f;
2289         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2290         for (i = 0;i < loadmodel->numframes;i++)
2291         {
2292                 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2293                 for (j = 0;j < loadmodel->num_bones;j++)
2294                 {
2295                         float pose[12];
2296                         matrix4x4_t posematrix;
2297                         for (k = 0;k < 12;k++)
2298                                 pose[k] = BigFloat(frameposes[j*12+k]);
2299                         // scale child bones to match the root scale
2300                         if (loadmodel->data_bones[j].parent >= 0)
2301                         {
2302                                 pose[3] *= modelscale;
2303                                 pose[7] *= modelscale;
2304                                 pose[11] *= modelscale;
2305                         }
2306                         // normalize rotation matrix
2307                         VectorNormalize(pose + 0);
2308                         VectorNormalize(pose + 4);
2309                         VectorNormalize(pose + 8);
2310                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2311                         Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*(i*loadmodel->num_bones+j));
2312                 }
2313         }
2314
2315         // load the meshes now
2316         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2317         meshvertices = 0;
2318         meshtriangles = 0;
2319         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2320         // (converting from weight-blending skeletal animation to
2321         //  deformation-based skeletal animation)
2322         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2323         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2324         for (i = 0;i < loadmodel->num_bones;i++)
2325         {
2326                 float m[12];
2327                 for (k = 0;k < 12;k++)
2328                         m[k] = BigFloat(poses[i*12+k]);
2329                 if (loadmodel->data_bones[i].parent >= 0)
2330                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2331                 else
2332                         for (k = 0;k < 12;k++)
2333                                 bonepose[12*i+k] = m[k];
2334         }
2335         for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2336         {
2337                 const int *inelements;
2338                 int *outelements;
2339                 const float *intexcoord;
2340                 msurface_t *surface;
2341
2342                 loadmodel->sortedmodelsurfaces[i] = i;
2343                 surface = loadmodel->data_surfaces + i;
2344                 surface->texture = loadmodel->data_textures + i;
2345                 surface->num_firsttriangle = meshtriangles;
2346                 surface->num_triangles = BigLong(dpmmesh->num_tris);
2347                 surface->num_firstvertex = meshvertices;
2348                 surface->num_vertices = BigLong(dpmmesh->num_verts);
2349                 meshvertices += surface->num_vertices;
2350                 meshtriangles += surface->num_triangles;
2351
2352                 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2353                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2354                 for (j = 0;j < surface->num_triangles;j++)
2355                 {
2356                         // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2357                         outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2358                         outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2359                         outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2360                         inelements += 3;
2361                         outelements += 3;
2362                 }
2363
2364                 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2365                 for (j = 0;j < surface->num_vertices*2;j++)
2366                         loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2367
2368                 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2369                 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2370                 {
2371                         int weightindex[4] = { 0, 0, 0, 0 };
2372                         float weightinfluence[4] = { 0, 0, 0, 0 };
2373                         int l;
2374                         int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2375                         data += sizeof(dpmvertex_t);
2376                         for (k = 0;k < numweights;k++)
2377                         {
2378                                 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2379                                 int boneindex = BigLong(vert->bonenum);
2380                                 const float *m = bonepose + 12 * boneindex;
2381                                 float influence = BigFloat(vert->influence);
2382                                 float relativeorigin[3], relativenormal[3];
2383                                 relativeorigin[0] = BigFloat(vert->origin[0]);
2384                                 relativeorigin[1] = BigFloat(vert->origin[1]);
2385                                 relativeorigin[2] = BigFloat(vert->origin[2]);
2386                                 relativenormal[0] = BigFloat(vert->normal[0]);
2387                                 relativenormal[1] = BigFloat(vert->normal[1]);
2388                                 relativenormal[2] = BigFloat(vert->normal[2]);
2389                                 // blend the vertex bone weights into the base mesh
2390                                 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2391                                 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2392                                 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2393                                 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2394                                 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2395                                 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2396                                 if (!k)
2397                                 {
2398                                         // store the first (and often only) weight
2399                                         weightinfluence[0] = influence;
2400                                         weightindex[0] = boneindex;
2401                                 }
2402                                 else
2403                                 {
2404                                         // sort the new weight into this vertex's weight table
2405                                         // (which only accepts up to 4 bones per vertex)
2406                                         for (l = 0;l < 4;l++)
2407                                         {
2408                                                 if (weightinfluence[l] < influence)
2409                                                 {
2410                                                         // move weaker influence weights out of the way first
2411                                                         int l2;
2412                                                         for (l2 = 3;l2 > l;l2--)
2413                                                         {
2414                                                                 weightinfluence[l2] = weightinfluence[l2-1];
2415                                                                 weightindex[l2] = weightindex[l2-1];
2416                                                         }
2417                                                         // store the new weight
2418                                                         weightinfluence[l] = influence;
2419                                                         weightindex[l] = boneindex;
2420                                                         break;
2421                                                 }
2422                                         }
2423                                 }
2424                                 data += sizeof(dpmbonevert_t);
2425                         }
2426                         loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2427                 }
2428
2429                 // since dpm models do not have named sections, reuse their shader name as the section name
2430                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2431
2432                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2433         }
2434         if (loadmodel->surfmesh.num_blends < meshvertices)
2435                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2436         Z_Free(bonepose);
2437         Mod_FreeSkinFiles(skinfiles);
2438         Mod_MakeSortedSurfaces(loadmodel);
2439
2440         // compute all the mesh information that was not loaded from the file
2441         if (loadmodel->surfmesh.data_element3s)
2442                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2443                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2444         Mod_BuildBaseBonePoses();
2445         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);
2446         if (loadmodel->surfmesh.data_neighbor3i)
2447                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2448
2449         if (!loadmodel->surfmesh.isanimated)
2450         {
2451                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2452                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2453                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2454                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2455                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2456                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2457         }
2458
2459         // because shaders can do somewhat unexpected things, check for unusual features now
2460         for (i = 0;i < loadmodel->num_textures;i++)
2461         {
2462                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2463                         mod->DrawSky = R_Q1BSP_DrawSky;
2464                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2465                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2466         }
2467 }
2468
2469 // no idea why PSK/PSA files contain weird quaternions but they do...
2470 #define PSKQUATNEGATIONS
2471 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2472 {
2473         int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2474         int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2475         fs_offset_t filesize;
2476         pskpnts_t *pnts;
2477         pskvtxw_t *vtxw;
2478         pskface_t *faces;
2479         pskmatt_t *matts;
2480         pskboneinfo_t *bones;
2481         pskrawweights_t *rawweights;
2482         //pskboneinfo_t *animbones;
2483         pskaniminfo_t *anims;
2484         pskanimkeys_t *animkeys;
2485         void *animfilebuffer, *animbuffer, *animbufferend;
2486         unsigned char *data;
2487         pskchunk_t *pchunk;
2488         skinfile_t *skinfiles;
2489         char animname[MAX_QPATH];
2490         size_t size;
2491         float biggestorigin;
2492
2493         pchunk = (pskchunk_t *)buffer;
2494         if (strcmp(pchunk->id, "ACTRHEAD"))
2495                 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2496
2497         loadmodel->modeldatatypestring = "PSK";
2498
2499         loadmodel->type = mod_alias;
2500         loadmodel->DrawSky = NULL;
2501         loadmodel->DrawAddWaterPlanes = NULL;
2502         loadmodel->Draw = R_Q1BSP_Draw;
2503         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2504         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2505         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2506         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2507         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2508         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2509         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2510         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2511         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2512         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2513         loadmodel->PointSuperContents = NULL;
2514         loadmodel->synctype = ST_RAND;
2515
2516         FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2517         strlcat(animname, ".psa", sizeof(animname));
2518         animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2519         animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2520         if (!animbuffer)
2521                 animbufferend = animbuffer;
2522
2523         numpnts = 0;
2524         pnts = NULL;
2525         numvtxw = 0;
2526         vtxw = NULL;
2527         numfaces = 0;
2528         faces = NULL;
2529         nummatts = 0;
2530         matts = NULL;
2531         numbones = 0;
2532         bones = NULL;
2533         numrawweights = 0;
2534         rawweights = NULL;
2535         numanims = 0;
2536         anims = NULL;
2537         numanimkeys = 0;
2538         animkeys = NULL;
2539
2540         while (buffer < bufferend)
2541         {
2542                 pchunk = (pskchunk_t *)buffer;
2543                 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2544                 version = LittleLong(pchunk->version);
2545                 recordsize = LittleLong(pchunk->recordsize);
2546                 numrecords = LittleLong(pchunk->numrecords);
2547                 if (developer_extra.integer)
2548                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2549                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2550                         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);
2551                 if (!strcmp(pchunk->id, "ACTRHEAD"))
2552                 {
2553                         // nothing to do
2554                 }
2555                 else if (!strcmp(pchunk->id, "PNTS0000"))
2556                 {
2557                         pskpnts_t *p;
2558                         if (recordsize != sizeof(*p))
2559                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2560                         // byteswap in place and keep the pointer
2561                         numpnts = numrecords;
2562                         pnts = (pskpnts_t *)buffer;
2563                         for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2564                         {
2565                                 p->origin[0] = LittleFloat(p->origin[0]);
2566                                 p->origin[1] = LittleFloat(p->origin[1]);
2567                                 p->origin[2] = LittleFloat(p->origin[2]);
2568                         }
2569                         buffer = p;
2570                 }
2571                 else if (!strcmp(pchunk->id, "VTXW0000"))
2572                 {
2573                         pskvtxw_t *p;
2574                         if (recordsize != sizeof(*p))
2575                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2576                         // byteswap in place and keep the pointer
2577                         numvtxw = numrecords;
2578                         vtxw = (pskvtxw_t *)buffer;
2579                         for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2580                         {
2581                                 p->pntsindex = LittleShort(p->pntsindex);
2582                                 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2583                                 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2584                                 if (p->pntsindex >= numpnts)
2585                                 {
2586                                         Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2587                                         p->pntsindex = 0;
2588                                 }
2589                         }
2590                         buffer = p;
2591                 }
2592                 else if (!strcmp(pchunk->id, "FACE0000"))
2593                 {
2594                         pskface_t *p;
2595                         if (recordsize != sizeof(*p))
2596                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2597                         // byteswap in place and keep the pointer
2598                         numfaces = numrecords;
2599                         faces = (pskface_t *)buffer;
2600                         for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2601                         {
2602                                 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2603                                 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2604                                 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2605                                 p->group = LittleLong(p->group);
2606                                 if (p->vtxwindex[0] >= numvtxw)
2607                                 {
2608                                         Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2609                                         p->vtxwindex[0] = 0;
2610                                 }
2611                                 if (p->vtxwindex[1] >= numvtxw)
2612                                 {
2613                                         Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2614                                         p->vtxwindex[1] = 0;
2615                                 }
2616                                 if (p->vtxwindex[2] >= numvtxw)
2617                                 {
2618                                         Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2619                                         p->vtxwindex[2] = 0;
2620                                 }
2621                         }
2622                         buffer = p;
2623                 }
2624                 else if (!strcmp(pchunk->id, "MATT0000"))
2625                 {
2626                         pskmatt_t *p;
2627                         if (recordsize != sizeof(*p))
2628                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2629                         // byteswap in place and keep the pointer
2630                         nummatts = numrecords;
2631                         matts = (pskmatt_t *)buffer;
2632                         for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2633                         {
2634                                 // nothing to do
2635                         }
2636                         buffer = p;
2637                 }
2638                 else if (!strcmp(pchunk->id, "REFSKELT"))
2639                 {
2640                         pskboneinfo_t *p;
2641                         if (recordsize != sizeof(*p))
2642                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2643                         // byteswap in place and keep the pointer
2644                         numbones = numrecords;
2645                         bones = (pskboneinfo_t *)buffer;
2646                         for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2647                         {
2648                                 p->numchildren = LittleLong(p->numchildren);
2649                                 p->parent = LittleLong(p->parent);
2650                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2651                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2652                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2653                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2654                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2655                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2656                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2657                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2658                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2659                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2660                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2661 #ifdef PSKQUATNEGATIONS
2662                                 if (index)
2663                                 {
2664                                         p->basepose.quat[0] *= -1;
2665                                         p->basepose.quat[1] *= -1;
2666                                         p->basepose.quat[2] *= -1;
2667                                 }
2668                                 else
2669                                 {
2670                                         p->basepose.quat[0] *=  1;
2671                                         p->basepose.quat[1] *= -1;
2672                                         p->basepose.quat[2] *=  1;
2673                                 }
2674 #endif
2675                                 if (p->parent < 0 || p->parent >= numbones)
2676                                 {
2677                                         Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2678                                         p->parent = 0;
2679                                 }
2680                         }
2681                         buffer = p;
2682                 }
2683                 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2684                 {
2685                         pskrawweights_t *p;
2686                         if (recordsize != sizeof(*p))
2687                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2688                         // byteswap in place and keep the pointer
2689                         numrawweights = numrecords;
2690                         rawweights = (pskrawweights_t *)buffer;
2691                         for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2692                         {
2693                                 p->weight = LittleFloat(p->weight);
2694                                 p->pntsindex = LittleLong(p->pntsindex);
2695                                 p->boneindex = LittleLong(p->boneindex);
2696                                 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2697                                 {
2698                                         Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2699                                         p->pntsindex = 0;
2700                                 }
2701                                 if (p->boneindex < 0 || p->boneindex >= numbones)
2702                                 {
2703                                         Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2704                                         p->boneindex = 0;
2705                                 }
2706                         }
2707                         buffer = p;
2708                 }
2709         }
2710
2711         while (animbuffer < animbufferend)
2712         {
2713                 pchunk = (pskchunk_t *)animbuffer;
2714                 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2715                 version = LittleLong(pchunk->version);
2716                 recordsize = LittleLong(pchunk->recordsize);
2717                 numrecords = LittleLong(pchunk->numrecords);
2718                 if (developer_extra.integer)
2719                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2720                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2721                         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);
2722                 if (!strcmp(pchunk->id, "ANIMHEAD"))
2723                 {
2724                         // nothing to do
2725                 }
2726                 else if (!strcmp(pchunk->id, "BONENAMES"))
2727                 {
2728                         pskboneinfo_t *p;
2729                         if (recordsize != sizeof(*p))
2730                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2731                         // byteswap in place and keep the pointer
2732                         numanimbones = numrecords;
2733                         //animbones = (pskboneinfo_t *)animbuffer;
2734                         // NOTE: supposedly psa does not need to match the psk model, the
2735                         // bones missing from the psa would simply use their base
2736                         // positions from the psk, but this is hard for me to implement
2737                         // and people can easily make animations that match.
2738                         if (numanimbones != numbones)
2739                                 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2740                         for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2741                         {
2742                                 p->numchildren = LittleLong(p->numchildren);
2743                                 p->parent = LittleLong(p->parent);
2744                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2745                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2746                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2747                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2748                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2749                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2750                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2751                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2752                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2753                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2754                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2755 #ifdef PSKQUATNEGATIONS
2756                                 if (index)
2757                                 {
2758                                         p->basepose.quat[0] *= -1;
2759                                         p->basepose.quat[1] *= -1;
2760                                         p->basepose.quat[2] *= -1;
2761                                 }
2762                                 else
2763                                 {
2764                                         p->basepose.quat[0] *=  1;
2765                                         p->basepose.quat[1] *= -1;
2766                                         p->basepose.quat[2] *=  1;
2767                                 }
2768 #endif
2769                                 if (p->parent < 0 || p->parent >= numanimbones)
2770                                 {
2771                                         Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2772                                         p->parent = 0;
2773                                 }
2774                                 // check that bones are the same as in the base
2775                                 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2776                                         Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2777                         }
2778                         animbuffer = p;
2779                 }
2780                 else if (!strcmp(pchunk->id, "ANIMINFO"))
2781                 {
2782                         pskaniminfo_t *p;
2783                         if (recordsize != sizeof(*p))
2784                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2785                         // byteswap in place and keep the pointer
2786                         numanims = numrecords;
2787                         anims = (pskaniminfo_t *)animbuffer;
2788                         for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2789                         {
2790                                 p->numbones = LittleLong(p->numbones);
2791                                 p->playtime = LittleFloat(p->playtime);
2792                                 p->fps = LittleFloat(p->fps);
2793                                 p->firstframe = LittleLong(p->firstframe);
2794                                 p->numframes = LittleLong(p->numframes);
2795                                 if (p->numbones != numbones)
2796                                         Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2797                         }
2798                         animbuffer = p;
2799                 }
2800                 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2801                 {
2802                         pskanimkeys_t *p;
2803                         if (recordsize != sizeof(*p))
2804                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2805                         numanimkeys = numrecords;
2806                         animkeys = (pskanimkeys_t *)animbuffer;
2807                         for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2808                         {
2809                                 p->origin[0] = LittleFloat(p->origin[0]);
2810                                 p->origin[1] = LittleFloat(p->origin[1]);
2811                                 p->origin[2] = LittleFloat(p->origin[2]);
2812                                 p->quat[0] = LittleFloat(p->quat[0]);
2813                                 p->quat[1] = LittleFloat(p->quat[1]);
2814                                 p->quat[2] = LittleFloat(p->quat[2]);
2815                                 p->quat[3] = LittleFloat(p->quat[3]);
2816                                 p->frametime = LittleFloat(p->frametime);
2817 #ifdef PSKQUATNEGATIONS
2818                                 if (index % numbones)
2819                                 {
2820                                         p->quat[0] *= -1;
2821                                         p->quat[1] *= -1;
2822                                         p->quat[2] *= -1;
2823                                 }
2824                                 else
2825                                 {
2826                                         p->quat[0] *=  1;
2827                                         p->quat[1] *= -1;
2828                                         p->quat[2] *=  1;
2829                                 }
2830 #endif
2831                         }
2832                         animbuffer = p;
2833                         // TODO: allocate bonepose stuff
2834                 }
2835                 else
2836                         Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2837         }
2838
2839         if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2840                 Host_Error("%s: missing required chunks", loadmodel->name);
2841
2842         if (numanims)
2843         {
2844                 loadmodel->numframes = 0;
2845                 for (index = 0;index < numanims;index++)
2846                         loadmodel->numframes += anims[index].numframes;
2847                 if (numanimkeys != numbones * loadmodel->numframes)
2848                         Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2849         }
2850         else
2851                 loadmodel->numframes = loadmodel->num_poses = 1;
2852
2853         meshvertices = numvtxw;
2854         meshtriangles = numfaces;
2855
2856         // load external .skin files if present
2857         skinfiles = Mod_LoadSkinFiles();
2858         if (loadmodel->numskins < 1)
2859                 loadmodel->numskins = 1;
2860         loadmodel->num_bones = numbones;
2861         loadmodel->num_poses = loadmodel->numframes;
2862         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2863         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2864         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2865         loadmodel->surfmesh.num_vertices = meshvertices;
2866         loadmodel->surfmesh.num_triangles = meshtriangles;
2867         loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
2868         loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
2869         // do most allocations as one merged chunk
2870         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);
2871         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2872         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2873         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2874         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2875         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2876         if (r_enableshadowvolumes.integer)
2877         {
2878                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2879         }
2880         loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2881         loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2882         loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2883         loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2884         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2885         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2886         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2887         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2888         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2889         loadmodel->surfmesh.num_blends = 0;
2890         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2891         if (loadmodel->surfmesh.num_vertices <= 65536)
2892         {
2893                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2894         }
2895         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
2896         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2897
2898         for (i = 0;i < loadmodel->numskins;i++)
2899         {
2900                 loadmodel->skinscenes[i].firstframe = i;
2901                 loadmodel->skinscenes[i].framecount = 1;
2902                 loadmodel->skinscenes[i].loop = true;
2903                 loadmodel->skinscenes[i].framerate = 10;
2904         }
2905
2906         // create surfaces
2907         for (index = 0, i = 0;index < nummatts;index++)
2908         {
2909                 // since psk models do not have named sections, reuse their shader name as the section name
2910                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2911                 loadmodel->sortedmodelsurfaces[index] = index;
2912                 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2913                 loadmodel->data_surfaces[index].num_firstvertex = 0;
2914                 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2915         }
2916
2917         // copy over the vertex locations and texcoords
2918         for (index = 0;index < numvtxw;index++)
2919         {
2920                 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2921                 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2922                 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2923                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2924                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
2925         }
2926
2927         // loading the faces is complicated because we need to sort them into surfaces by mattindex
2928         for (index = 0;index < numfaces;index++)
2929                 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
2930         for (index = 0, i = 0;index < nummatts;index++)
2931         {
2932                 loadmodel->data_surfaces[index].num_firsttriangle = i;
2933                 i += loadmodel->data_surfaces[index].num_triangles;
2934                 loadmodel->data_surfaces[index].num_triangles = 0;
2935         }
2936         for (index = 0;index < numfaces;index++)
2937         {
2938                 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
2939                 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
2940                 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
2941                 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
2942         }
2943
2944         // copy over the bones
2945         for (index = 0;index < numbones;index++)
2946         {
2947                 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
2948                 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
2949                 if (loadmodel->data_bones[index].parent >= index)
2950                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
2951         }
2952
2953         // convert the basepose data
2954         if (loadmodel->num_bones)
2955         {
2956                 int boneindex;
2957                 matrix4x4_t *basebonepose;
2958                 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
2959                 matrix4x4_t bonematrix;
2960                 matrix4x4_t tempbonematrix;
2961                 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
2962                 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
2963                 {
2964                         Matrix4x4_FromOriginQuat(&bonematrix, bones[boneindex].basepose.origin[0], bones[boneindex].basepose.origin[1], bones[boneindex].basepose.origin[2], bones[boneindex].basepose.quat[0], bones[boneindex].basepose.quat[1], bones[boneindex].basepose.quat[2], bones[boneindex].basepose.quat[3]);
2965                         if (loadmodel->data_bones[boneindex].parent >= 0)
2966                         {
2967                                 tempbonematrix = bonematrix;
2968                                 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
2969                         }
2970                         basebonepose[boneindex] = bonematrix;
2971                         Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
2972                         Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
2973                 }
2974                 Mem_Free(basebonepose);
2975         }
2976
2977         // sort the psk point weights into the vertex weight tables
2978         // (which only accept up to 4 bones per vertex)
2979         for (index = 0;index < numvtxw;index++)
2980         {
2981                 int weightindex[4] = { 0, 0, 0, 0 };
2982                 float weightinfluence[4] = { 0, 0, 0, 0 };
2983                 int l;
2984                 for (j = 0;j < numrawweights;j++)
2985                 {
2986                         if (rawweights[j].pntsindex == vtxw[index].pntsindex)
2987                         {
2988                                 int boneindex = rawweights[j].boneindex;
2989                                 float influence = rawweights[j].weight;
2990                                 for (l = 0;l < 4;l++)
2991                                 {
2992                                         if (weightinfluence[l] < influence)
2993                                         {
2994                                                 // move lower influence weights out of the way first
2995                                                 int l2;
2996                                                 for (l2 = 3;l2 > l;l2--)
2997                                                 {
2998                                                         weightinfluence[l2] = weightinfluence[l2-1];
2999                                                         weightindex[l2] = weightindex[l2-1];
3000                                                 }
3001                                                 // store the new weight
3002                                                 weightinfluence[l] = influence;
3003                                                 weightindex[l] = boneindex;
3004                                                 break;
3005                                         }
3006                                 }
3007                         }
3008                 }
3009                 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3010         }
3011         if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3012                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3013
3014         // set up the animscenes based on the anims
3015         if (numanims)
3016         {
3017                 for (index = 0, i = 0;index < numanims;index++)
3018                 {
3019                         for (j = 0;j < anims[index].numframes;j++, i++)
3020                         {
3021                                 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3022                                 loadmodel->animscenes[i].firstframe = i;
3023                                 loadmodel->animscenes[i].framecount = 1;
3024                                 loadmodel->animscenes[i].loop = true;
3025                                 loadmodel->animscenes[i].framerate = anims[index].fps;
3026                         }
3027                 }
3028                 // calculate the scaling value for bone origins so they can be compressed to short
3029                 biggestorigin = 0;
3030                 for (index = 0;index < numanimkeys;index++)
3031                 {
3032                         pskanimkeys_t *k = animkeys + index;
3033                         biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3034                         biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3035                         biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3036                 }
3037                 loadmodel->num_posescale = biggestorigin / 32767.0f;
3038                 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3039         
3040                 // load the poses from the animkeys
3041                 for (index = 0;index < numanimkeys;index++)
3042                 {
3043                         pskanimkeys_t *k = animkeys + index;
3044                         float quat[4];
3045                         Vector4Copy(k->quat, quat);
3046                         if (quat[3] > 0)
3047                                 Vector4Negate(quat, quat);
3048                         Vector4Normalize2(quat, quat);
3049                         // compress poses to the short[6] format for longterm storage
3050                         loadmodel->data_poses6s[index*6+0] = k->origin[0] * loadmodel->num_poseinvscale;
3051                         loadmodel->data_poses6s[index*6+1] = k->origin[1] * loadmodel->num_poseinvscale;
3052                         loadmodel->data_poses6s[index*6+2] = k->origin[2] * loadmodel->num_poseinvscale;
3053                         loadmodel->data_poses6s[index*6+3] = quat[0] * 32767.0f;
3054                         loadmodel->data_poses6s[index*6+4] = quat[1] * 32767.0f;
3055                         loadmodel->data_poses6s[index*6+5] = quat[2] * 32767.0f;
3056                 }
3057         }
3058         else
3059         {
3060                 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3061                 loadmodel->animscenes[0].firstframe = 0;
3062                 loadmodel->animscenes[0].framecount = 1;
3063                 loadmodel->animscenes[0].loop = true;
3064                 loadmodel->animscenes[0].framerate = 10;
3065
3066                 // calculate the scaling value for bone origins so they can be compressed to short
3067                 biggestorigin = 0;
3068                 for (index = 0;index < numbones;index++)
3069                 {
3070                         pskboneinfo_t *p = bones + index;
3071                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3072                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3073                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3074                 }
3075                 loadmodel->num_posescale = biggestorigin / 32767.0f;
3076                 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3077         
3078                 // load the basepose as a frame
3079                 for (index = 0;index < numbones;index++)
3080                 {
3081                         pskboneinfo_t *p = bones + index;
3082                         float quat[4];
3083                         Vector4Copy(p->basepose.quat, quat);
3084                         if (quat[3] > 0)
3085                                 Vector4Negate(quat, quat);
3086                         Vector4Normalize2(quat, quat);
3087                         // compress poses to the short[6] format for longterm storage
3088                         loadmodel->data_poses6s[index*6+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3089                         loadmodel->data_poses6s[index*6+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3090                         loadmodel->data_poses6s[index*6+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3091                         loadmodel->data_poses6s[index*6+3] = quat[0] * 32767.0f;
3092                         loadmodel->data_poses6s[index*6+4] = quat[1] * 32767.0f;
3093                         loadmodel->data_poses6s[index*6+5] = quat[2] * 32767.0f;
3094                 }
3095         }
3096
3097         Mod_FreeSkinFiles(skinfiles);
3098         if (animfilebuffer)
3099                 Mem_Free(animfilebuffer);
3100         Mod_MakeSortedSurfaces(loadmodel);
3101
3102         // compute all the mesh information that was not loaded from the file
3103         // TODO: honor smoothing groups somehow?
3104         if (loadmodel->surfmesh.data_element3s)
3105                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3106                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3107         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3108         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);
3109         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);
3110         if (loadmodel->surfmesh.data_neighbor3i)
3111                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
3112         Mod_Alias_CalculateBoundingBox();
3113
3114         if (!loadmodel->surfmesh.isanimated)
3115         {
3116                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3117                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3118                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3119                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3120                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3121                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3122         }
3123
3124         // because shaders can do somewhat unexpected things, check for unusual features now
3125         for (i = 0;i < loadmodel->num_textures;i++)
3126         {
3127                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3128                         mod->DrawSky = R_Q1BSP_DrawSky;
3129                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3130                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3131         }
3132 }
3133
3134 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
3135 {
3136         unsigned char *data;
3137         const char *text;
3138         const unsigned char *pbase, *pend;
3139         iqmheader_t header;
3140         skinfile_t *skinfiles;
3141         int i, j, k, meshvertices, meshtriangles;
3142         float biggestorigin;
3143         const unsigned int *inelements;
3144         int *outelements;
3145         const int *inneighbors;
3146         int *outneighbors;
3147         float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3148         // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3149         const float *vnormal = NULL;
3150         const float *vposition = NULL;
3151         const float *vtangent = NULL;
3152         const float *vtexcoord = NULL;
3153         const float *vcolor4f = NULL;
3154         const unsigned char *vblendindexes = NULL;
3155         const unsigned char *vblendweights = NULL;
3156         const unsigned char *vcolor4ub = NULL;
3157         const unsigned short *framedata = NULL;
3158         // temporary memory allocations (because the data in the file may be misaligned)
3159         iqmanim_t *anims = NULL;
3160         iqmbounds_t *bounds = NULL;
3161         iqmjoint1_t *joint1 = NULL;
3162         iqmjoint_t *joint = NULL;
3163         iqmmesh_t *meshes = NULL;
3164         iqmpose1_t *pose1 = NULL;
3165         iqmpose_t *pose = NULL;
3166         iqmvertexarray_t *vas = NULL;
3167
3168         pbase = (unsigned char *)buffer;
3169         pend = (unsigned char *)bufferend;
3170
3171         if (pbase + sizeof(iqmheader_t) > pend)
3172                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3173
3174         // copy struct (otherwise it may be misaligned)
3175         // LordHavoc: okay it's definitely not misaligned here, but for consistency...
3176         memcpy(&header, pbase, sizeof(iqmheader_t));
3177
3178         if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3179                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3180         if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3181                 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3182
3183         loadmodel->modeldatatypestring = "IQM";
3184
3185         loadmodel->type = mod_alias;
3186         loadmodel->synctype = ST_RAND;
3187
3188         // byteswap header
3189         header.version = LittleLong(header.version);
3190         header.filesize = LittleLong(header.filesize);
3191         header.flags = LittleLong(header.flags);
3192         header.num_text = LittleLong(header.num_text);
3193         header.ofs_text = LittleLong(header.ofs_text);
3194         header.num_meshes = LittleLong(header.num_meshes);
3195         header.ofs_meshes = LittleLong(header.ofs_meshes);
3196         header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3197         header.num_vertexes = LittleLong(header.num_vertexes);
3198         header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3199         header.num_triangles = LittleLong(header.num_triangles);
3200         header.ofs_triangles = LittleLong(header.ofs_triangles);
3201         header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3202         header.num_joints = LittleLong(header.num_joints);
3203         header.ofs_joints = LittleLong(header.ofs_joints);
3204         header.num_poses = LittleLong(header.num_poses);
3205         header.ofs_poses = LittleLong(header.ofs_poses);
3206         header.num_anims = LittleLong(header.num_anims);
3207         header.ofs_anims = LittleLong(header.ofs_anims);
3208         header.num_frames = LittleLong(header.num_frames);
3209         header.num_framechannels = LittleLong(header.num_framechannels);
3210         header.ofs_frames = LittleLong(header.ofs_frames);
3211         header.ofs_bounds = LittleLong(header.ofs_bounds);
3212         header.num_comment = LittleLong(header.num_comment);
3213         header.ofs_comment = LittleLong(header.ofs_comment);
3214         header.num_extensions = LittleLong(header.num_extensions);
3215         header.ofs_extensions = LittleLong(header.ofs_extensions);
3216
3217         if (header.version == 1)
3218         {
3219                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3220                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3221                 {
3222                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3223                         return;
3224                 }
3225         }
3226         else
3227         {
3228                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3229                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3230                 {
3231                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3232                         return;
3233                 }
3234         }
3235         if (pbase + header.ofs_text + header.num_text > pend ||
3236                 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3237                 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3238                 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3239                 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3240                 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3241                 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3242                 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3243                 pbase + header.ofs_comment + header.num_comment > pend)
3244         {
3245                 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3246                 return;
3247         }
3248
3249         // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3250         if (header.num_vertexarrays)
3251                 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3252         if (header.num_anims)
3253                 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3254         if (header.ofs_bounds)
3255                 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3256         if (header.num_meshes)
3257                 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3258
3259         for (i = 0;i < (int)header.num_vertexarrays;i++)
3260         {
3261                 iqmvertexarray_t va;
3262                 size_t vsize;
3263                 va.type = LittleLong(vas[i].type);
3264                 va.flags = LittleLong(vas[i].flags);
3265                 va.format = LittleLong(vas[i].format);
3266                 va.size = LittleLong(vas[i].size);
3267                 va.offset = LittleLong(vas[i].offset);
3268                 vsize = header.num_vertexes*va.size;
3269                 switch (va.format)
3270                 { 
3271                 case IQM_FLOAT: vsize *= sizeof(float); break;
3272                 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3273                 default: continue;
3274                 }
3275                 if (pbase + va.offset + vsize > pend)
3276                         continue;
3277                 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3278                 switch (va.type)
3279                 {
3280                 case IQM_POSITION:
3281                         if (va.format == IQM_FLOAT && va.size == 3)
3282                                 vposition = (const float *)(pbase + va.offset);
3283                         break;
3284                 case IQM_TEXCOORD:
3285                         if (va.format == IQM_FLOAT && va.size == 2)
3286                                 vtexcoord = (const float *)(pbase + va.offset);
3287                         break;
3288                 case IQM_NORMAL:
3289                         if (va.format == IQM_FLOAT && va.size == 3)
3290                                 vnormal = (const float *)(pbase + va.offset);
3291                         break;
3292                 case IQM_TANGENT:
3293                         if (va.format == IQM_FLOAT && va.size == 4)
3294                                 vtangent = (const float *)(pbase + va.offset);
3295                         break;
3296                 case IQM_BLENDINDEXES:
3297                         if (va.format == IQM_UBYTE && va.size == 4)
3298                                 vblendindexes = (const unsigned char *)(pbase + va.offset);
3299                         break;
3300                 case IQM_BLENDWEIGHTS:
3301                         if (va.format == IQM_UBYTE && va.size == 4)
3302                                 vblendweights = (const unsigned char *)(pbase + va.offset);
3303                         break;
3304                 case IQM_COLOR:
3305                         if (va.format == IQM_FLOAT && va.size == 4)
3306                                 vcolor4f = (const float *)(pbase + va.offset);
3307                         if (va.format == IQM_UBYTE && va.size == 4)
3308                                 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3309                         break;
3310                 }
3311         }
3312         if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3313         {
3314                 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3315                 return;
3316         }
3317
3318         text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3319
3320         loadmodel->DrawSky = NULL;
3321         loadmodel->DrawAddWaterPlanes = NULL;
3322         loadmodel->Draw = R_Q1BSP_Draw;
3323         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
3324         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
3325         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
3326         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
3327         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
3328         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
3329         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
3330         loadmodel->DrawLight = R_Q1BSP_DrawLight;
3331         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3332         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3333         loadmodel->PointSuperContents = NULL;
3334
3335         // load external .skin files if present
3336         skinfiles = Mod_LoadSkinFiles();
3337         if (loadmodel->numskins < 1)
3338                 loadmodel->numskins = 1;
3339
3340         loadmodel->numframes = max(header.num_anims, 1);
3341         loadmodel->num_bones = header.num_joints;
3342         loadmodel->num_poses = max(header.num_frames, 1);
3343         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
3344         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3345         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3346         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices; // updated later
3347
3348         meshvertices = header.num_vertexes;
3349         meshtriangles = header.num_triangles;
3350
3351         // do most allocations as one merged chunk
3352         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]) + (vcolor4f || vcolor4ub ? sizeof(float[4]) : 0)) + (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));
3353         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3354         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3355         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3356         loadmodel->surfmesh.num_vertices = meshvertices;
3357         loadmodel->surfmesh.num_triangles = meshtriangles;
3358         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3359         if (r_enableshadowvolumes.integer)
3360         {
3361                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3362         }
3363         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3364         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3365         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3366         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3367         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3368         if (vcolor4f || vcolor4ub)
3369         {
3370                 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3371         }
3372         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3373         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3374         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3375         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3376         if (vblendindexes && vblendweights)
3377         {
3378                 loadmodel->surfmesh.num_blends = 0;
3379                 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3380         }
3381         if (meshvertices <= 65536)
3382         {
3383                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3384         }
3385         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
3386         if (vblendindexes && vblendweights)
3387                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3388
3389         for (i = 0;i < loadmodel->numskins;i++)
3390         {
3391                 loadmodel->skinscenes[i].firstframe = i;
3392                 loadmodel->skinscenes[i].framecount = 1;
3393                 loadmodel->skinscenes[i].loop = true;
3394                 loadmodel->skinscenes[i].framerate = 10;
3395         }
3396
3397         // load the bone info
3398         if (header.version == 1)
3399         {
3400                 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3401                 if (loadmodel->num_bones)
3402                         joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3403                 for (i = 0;i < loadmodel->num_bones;i++)
3404                 {
3405                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3406                         joint1[i].name = LittleLong(injoint1[i].name);
3407                         joint1[i].parent = LittleLong(injoint1[i].parent);
3408                         for (j = 0;j < 3;j++)
3409                         {
3410                                 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3411                                 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3412                                 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3413                         }
3414                         strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3415                         loadmodel->data_bones[i].parent = joint1[i].parent;
3416                         if (loadmodel->data_bones[i].parent >= i)
3417                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3418                         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]);
3419                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3420                         if (loadmodel->data_bones[i].parent >= 0)
3421                         {
3422                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3423                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3424                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3425                         }
3426                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3427                 }
3428         }
3429         else
3430         {
3431                 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3432                 if (header.num_joints)
3433                         joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3434                 for (i = 0;i < loadmodel->num_bones;i++)
3435                 {
3436                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3437                         joint[i].name = LittleLong(injoint[i].name);
3438                         joint[i].parent = LittleLong(injoint[i].parent);
3439                         for (j = 0;j < 3;j++)
3440                         {
3441                                 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3442                                 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3443                                 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3444                         }
3445                         joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3446                         strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3447                         loadmodel->data_bones[i].parent = joint[i].parent;
3448                         if (loadmodel->data_bones[i].parent >= i)
3449                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3450                         if (joint[i].rotation[3] > 0)
3451                                 Vector4Negate(joint[i].rotation, joint[i].rotation);
3452                         Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3453                         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]);
3454                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3455                         if (loadmodel->data_bones[i].parent >= 0)
3456                         {
3457                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3458                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3459                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3460                         }       
3461                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3462                 }
3463         }
3464
3465         // set up the animscenes based on the anims
3466         for (i = 0;i < (int)header.num_anims;i++)
3467         {
3468                 iqmanim_t anim;
3469                 anim.name = LittleLong(anims[i].name);
3470                 anim.first_frame = LittleLong(anims[i].first_frame);
3471                 anim.num_frames = LittleLong(anims[i].num_frames);
3472                 anim.framerate = LittleFloat(anims[i].framerate);
3473                 anim.flags = LittleLong(anims[i].flags);
3474                 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3475                 loadmodel->animscenes[i].firstframe = anim.first_frame;
3476                 loadmodel->animscenes[i].framecount = anim.num_frames;
3477                 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3478                 loadmodel->animscenes[i].framerate = anim.framerate;
3479         }
3480         if (header.num_anims <= 0)
3481         {
3482                 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3483                 loadmodel->animscenes[0].firstframe = 0;
3484                 loadmodel->animscenes[0].framecount = 1;
3485                 loadmodel->animscenes[0].loop = true;
3486                 loadmodel->animscenes[0].framerate = 10;
3487         }
3488
3489         loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3490         loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
3491
3492         biggestorigin = 0;
3493         if (header.version == 1)
3494         {
3495                 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3496                 if (header.num_poses)
3497                         pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3498                 for (i = 0;i < (int)header.num_poses;i++)
3499                 {
3500                         float f;
3501                         pose1[i].parent = LittleLong(inpose1[i].parent);
3502                         pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3503                         for (j = 0;j < 9;j++)
3504                         {
3505                                 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3506                                 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3507                         }
3508                         f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3509                         f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3510                         f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3511                         f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3512                         f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3513                         f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3514                 }
3515                 if (header.num_frames <= 0)
3516                 {
3517                         for (i = 0;i < loadmodel->num_bones;i++)
3518                         {
3519                                 float f;
3520                                 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3521                                 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3522                                 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3523                         }
3524                 }
3525         }
3526         else
3527         {
3528                 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3529                 if (header.num_poses)
3530                         pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3531                 for (i = 0;i < (int)header.num_poses;i++)
3532                 {
3533                         float f;
3534                         pose[i].parent = LittleLong(inpose[i].parent);
3535                         pose[i].channelmask = LittleLong(inpose[i].channelmask);
3536                         for (j = 0;j < 10;j++)
3537                         {
3538                                 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3539                                 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3540                         }
3541                         f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3542                         f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3543                         f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3544                         f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3545                         f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3546                         f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3547                 }
3548                 if (header.num_frames <= 0)
3549                 {
3550                         for (i = 0;i < loadmodel->num_bones;i++)
3551                         {
3552                                 float f;
3553                                 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3554                                 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3555                                 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3556                         }
3557                 }
3558         }
3559         loadmodel->num_posescale = biggestorigin / 32767.0f;
3560         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3561
3562         // load the pose data
3563         // this unaligned memory access is safe (LittleShort reads as bytes)
3564         framedata = (const unsigned short *)(pbase + header.ofs_frames);
3565         if (header.version == 1)
3566         {
3567                 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3568                 {
3569                         for (j = 0;j < (int)header.num_poses;j++, k++)
3570                         {
3571                                 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));
3572                                 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));
3573                                 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));
3574                                 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));
3575                                 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));
3576                                 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));
3577                                 // skip scale data for now
3578                                 if(pose1[j].channelmask&64) framedata++;
3579                                 if(pose1[j].channelmask&128) framedata++;
3580                                 if(pose1[j].channelmask&256) framedata++;
3581                         }
3582                 }
3583                 if (header.num_frames <= 0)
3584                 {
3585                         for (i = 0;i < loadmodel->num_bones;i++)
3586                         {
3587                                 loadmodel->data_poses6s[i*6 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3588                                 loadmodel->data_poses6s[i*6 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3589                                 loadmodel->data_poses6s[i*6 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3590                                 loadmodel->data_poses6s[i*6 + 3] = 32767.0f * joint1[i].rotation[0];
3591                                 loadmodel->data_poses6s[i*6 + 4] = 32767.0f * joint1[i].rotation[1];
3592                                 loadmodel->data_poses6s[i*6 + 5] = 32767.0f * joint1[i].rotation[2];
3593                         }
3594                 }
3595         }
3596         else
3597         {
3598                 for (i = 0, k = 0;i < (int)header.num_frames;i++)       
3599                 {
3600                         for (j = 0;j < (int)header.num_poses;j++, k++)
3601                         {
3602                                 float rot[4];
3603                                 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));
3604                                 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));
3605                                 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));
3606                                 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3607                                 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3608                                 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3609                                 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3610                                 if (rot[3] > 0)
3611                                         Vector4Negate(rot, rot);
3612                                 Vector4Normalize2(rot, rot);
3613                                 loadmodel->data_poses6s[k*6 + 3] = 32767.0f * rot[0];
3614                                 loadmodel->data_poses6s[k*6 + 4] = 32767.0f * rot[1];
3615                                 loadmodel->data_poses6s[k*6 + 5] = 32767.0f * rot[2];
3616                                 // skip scale data for now
3617                                 if(pose[j].channelmask&128) framedata++;
3618                                 if(pose[j].channelmask&256) framedata++;
3619                                 if(pose[j].channelmask&512) framedata++;
3620                         }
3621                 }
3622                 if (header.num_frames <= 0)
3623                 {
3624                         for (i = 0;i < loadmodel->num_bones;i++)
3625                         {
3626                                 loadmodel->data_poses6s[i*6 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3627                                 loadmodel->data_poses6s[i*6 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3628                                 loadmodel->data_poses6s[i*6 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3629                                 loadmodel->data_poses6s[i*6 + 3] = 32767.0f * joint[i].rotation[0];
3630                                 loadmodel->data_poses6s[i*6 + 4] = 32767.0f * joint[i].rotation[1];
3631                                 loadmodel->data_poses6s[i*6 + 5] = 32767.0f * joint[i].rotation[2];
3632                         }
3633                 }
3634         }
3635
3636         // load bounding box data
3637         if (header.ofs_bounds)
3638         {
3639                 float xyradius = 0, radius = 0;
3640                 VectorClear(loadmodel->normalmins);
3641                 VectorClear(loadmodel->normalmaxs);
3642                 for (i = 0; i < (int)header.num_frames;i++)
3643                 {
3644                         iqmbounds_t bound;
3645                         bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3646                         bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3647                         bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3648                         bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);                 
3649                         bound.maxs[1] = LittleFloat(bounds[i].maxs[1]); 
3650                         bound.maxs[2] = LittleFloat(bounds[i].maxs[2]); 
3651                         bound.xyradius = LittleFloat(bounds[i].xyradius);
3652                         bound.radius = LittleFloat(bounds[i].radius);
3653                         if (!i)
3654                         {
3655                                 VectorCopy(bound.mins, loadmodel->normalmins);
3656                                 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3657                         }
3658                         else
3659                         {
3660                                 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3661                                 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3662                                 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3663                                 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3664                                 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3665                                 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3666                         }
3667                         if (bound.xyradius > xyradius)
3668                                 xyradius = bound.xyradius;
3669                         if (bound.radius > radius)
3670                                 radius = bound.radius;
3671                 }
3672                 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3673                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3674                 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3675                 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3676                 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3677                 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3678                 loadmodel->radius = radius;
3679                 loadmodel->radius2 = radius * radius;
3680         }
3681
3682         // load triangle data
3683         // this unaligned memory access is safe (LittleLong reads as bytes)
3684         inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3685         outelements = loadmodel->surfmesh.data_element3i;
3686         for (i = 0;i < (int)header.num_triangles;i++)
3687         {
3688                 outelements[0] = LittleLong(inelements[0]);
3689                 outelements[1] = LittleLong(inelements[1]);
3690                 outelements[2] = LittleLong(inelements[2]);
3691                 outelements += 3;
3692                 inelements += 3;
3693         }
3694         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3695
3696         if (header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
3697         {
3698                 // this unaligned memory access is safe (LittleLong reads as bytes)
3699                 inneighbors = (const int *)(pbase + header.ofs_neighbors);
3700                 outneighbors = loadmodel->surfmesh.data_neighbor3i;
3701                 for (i = 0;i < (int)header.num_triangles;i++)
3702                 {
3703                         outneighbors[0] = LittleLong(inneighbors[0]);
3704                         outneighbors[1] = LittleLong(inneighbors[1]);
3705                         outneighbors[2] = LittleLong(inneighbors[2]);
3706                         outneighbors += 3;
3707                         inneighbors += 3;
3708                 }
3709         }
3710
3711         // load vertex data
3712         // this unaligned memory access is safe (LittleFloat reads as bytes)
3713         outvertex = loadmodel->surfmesh.data_vertex3f;
3714         for (i = 0;i < (int)header.num_vertexes;i++)
3715         {
3716                 outvertex[0] = LittleFloat(vposition[0]);
3717                 outvertex[1] = LittleFloat(vposition[1]);
3718                 outvertex[2] = LittleFloat(vposition[2]);
3719                 vposition += 3;
3720                 outvertex += 3;
3721         }
3722
3723         outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3724         // this unaligned memory access is safe (LittleFloat reads as bytes)
3725         for (i = 0;i < (int)header.num_vertexes;i++)
3726         {
3727                 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3728                 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3729                 vtexcoord += 2;
3730                 outtexcoord += 2;
3731         }
3732
3733         // this unaligned memory access is safe (LittleFloat reads as bytes)
3734         if(vnormal)
3735         {
3736                 outnormal = loadmodel->surfmesh.data_normal3f;
3737                 for (i = 0;i < (int)header.num_vertexes;i++)
3738                 {
3739                         outnormal[0] = LittleFloat(vnormal[0]);
3740                         outnormal[1] = LittleFloat(vnormal[1]);
3741                         outnormal[2] = LittleFloat(vnormal[2]);
3742                         vnormal += 3;
3743                         outnormal += 3;
3744                 }
3745         }
3746
3747         // this unaligned memory access is safe (LittleFloat reads as bytes)
3748         if(vnormal && vtangent)
3749         {
3750                 outnormal = loadmodel->surfmesh.data_normal3f;
3751                 outsvector = loadmodel->surfmesh.data_svector3f;
3752                 outtvector = loadmodel->surfmesh.data_tvector3f;
3753                 for (i = 0;i < (int)header.num_vertexes;i++)
3754                 {
3755                         outsvector[0] = LittleFloat(vtangent[0]);
3756                         outsvector[1] = LittleFloat(vtangent[1]);
3757                         outsvector[2] = LittleFloat(vtangent[2]);
3758                         if(LittleFloat(vtangent[3]) < 0)
3759                                 CrossProduct(outsvector, outnormal, outtvector);
3760                         else
3761                                 CrossProduct(outnormal, outsvector, outtvector);
3762                         vtangent += 4;
3763                         outnormal += 3;
3764                         outsvector += 3;
3765                         outtvector += 3;
3766                 }
3767         }
3768
3769         // this unaligned memory access is safe (all bytes)
3770         if (vblendindexes && vblendweights)
3771         {
3772                 for (i = 0; i < (int)header.num_vertexes;i++)
3773                 {
3774                         blendweights_t weights;
3775                         memcpy(weights.index, vblendindexes + i*4, 4);
3776                         memcpy(weights.influence, vblendweights + i*4, 4);
3777                         loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3778                 }
3779         }
3780
3781         if (vcolor4f)
3782         {
3783                 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3784                 // this unaligned memory access is safe (LittleFloat reads as bytes)
3785                 for (i = 0;i < (int)header.num_vertexes;i++)
3786                 {
3787                         outcolor[0] = LittleFloat(vcolor4f[0]);
3788                         outcolor[1] = LittleFloat(vcolor4f[1]);
3789                         outcolor[2] = LittleFloat(vcolor4f[2]);
3790                         outcolor[3] = LittleFloat(vcolor4f[3]);
3791                         vcolor4f += 4;
3792                         outcolor += 4;
3793                 }
3794         }
3795         else if (vcolor4ub)
3796         {
3797                 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3798                 // this unaligned memory access is safe (all bytes)
3799                 for (i = 0;i < (int)header.num_vertexes;i++)
3800                 {
3801                         outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3802                         outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3803                         outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3804                         outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3805                         vcolor4ub += 4;
3806                         outcolor += 4;
3807                 }
3808         }
3809
3810         // load meshes
3811         for (i = 0;i < (int)header.num_meshes;i++)
3812         {
3813                 iqmmesh_t mesh;
3814                 msurface_t *surface;
3815
3816                 mesh.name = LittleLong(meshes[i].name);
3817                 mesh.material = LittleLong(meshes[i].material);
3818                 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3819                 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3820                 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3821                 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3822
3823                 loadmodel->sortedmodelsurfaces[i] = i;
3824                 surface = loadmodel->data_surfaces + i;
3825                 surface->texture = loadmodel->data_textures + i;
3826                 surface->num_firsttriangle = mesh.first_triangle;
3827                 surface->num_triangles = mesh.num_triangles;
3828                 surface->num_firstvertex = mesh.first_vertex;
3829                 surface->num_vertices = mesh.num_vertexes;
3830
3831                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3832         }
3833
3834         Mod_FreeSkinFiles(skinfiles);
3835         Mod_MakeSortedSurfaces(loadmodel);
3836
3837         // compute all the mesh information that was not loaded from the file
3838         if (loadmodel->surfmesh.data_element3s)
3839                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3840                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3841         if (!vnormal)
3842                 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);
3843         if (!vnormal || !vtangent)
3844                 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);
3845         if (!header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
3846                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
3847         if (!header.ofs_bounds)
3848                 Mod_Alias_CalculateBoundingBox();
3849
3850         if (!loadmodel->surfmesh.isanimated && loadmodel->surfmesh.num_triangles >= 1)
3851         {
3852                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3853                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3854                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3855                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3856                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3857                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3858         }
3859
3860         if (joint        ) Mem_Free(joint        );joint         = NULL;
3861         if (joint1       ) Mem_Free(joint1       );joint1        = NULL;
3862         if (pose         ) Mem_Free(pose         );pose          = NULL;
3863         if (pose1        ) Mem_Free(pose1        );pose1         = NULL;
3864
3865         // because shaders can do somewhat unexpected things, check for unusual features now
3866         for (i = 0;i < loadmodel->num_textures;i++)
3867         {
3868                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3869                         mod->DrawSky = R_Q1BSP_DrawSky;
3870                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3871                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3872         }
3873 }