]> git.xonotic.org Git - xonotic/darkplaces.git/blob - model_alias.c
fix more crashes to do with animscenes being NULL on some models,
[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 == NULL)
2521                 Host_Error("%s: can't find .psa file (%s)", loadmodel->name, animname);
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 || !numanims || !anims || !numanimkeys || !animkeys)
2840                 Host_Error("%s: missing required chunks", loadmodel->name);
2841
2842         loadmodel->numframes = 0;
2843         for (index = 0;index < numanims;index++)
2844                 loadmodel->numframes += anims[index].numframes;
2845
2846         if (numanimkeys != numbones * loadmodel->numframes)
2847                 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2848
2849         meshvertices = numvtxw;
2850         meshtriangles = numfaces;
2851
2852         // load external .skin files if present
2853         skinfiles = Mod_LoadSkinFiles();
2854         if (loadmodel->numskins < 1)
2855                 loadmodel->numskins = 1;
2856         loadmodel->num_bones = numbones;
2857         loadmodel->num_poses = loadmodel->numframes;
2858         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2859         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2860         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2861         loadmodel->surfmesh.num_vertices = meshvertices;
2862         loadmodel->surfmesh.num_triangles = meshtriangles;
2863         loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
2864         loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
2865         // do most allocations as one merged chunk
2866         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);
2867         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2868         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2869         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2870         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2871         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2872         if (r_enableshadowvolumes.integer)
2873         {
2874                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2875         }
2876         loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2877         loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2878         loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2879         loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2880         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2881         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2882         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2883         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2884         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2885         loadmodel->surfmesh.num_blends = 0;
2886         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2887         if (loadmodel->surfmesh.num_vertices <= 65536)
2888         {
2889                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2890         }
2891         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
2892         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2893
2894         for (i = 0;i < loadmodel->numskins;i++)
2895         {
2896                 loadmodel->skinscenes[i].firstframe = i;
2897                 loadmodel->skinscenes[i].framecount = 1;
2898                 loadmodel->skinscenes[i].loop = true;
2899                 loadmodel->skinscenes[i].framerate = 10;
2900         }
2901
2902         // create surfaces
2903         for (index = 0, i = 0;index < nummatts;index++)
2904         {
2905                 // since psk models do not have named sections, reuse their shader name as the section name
2906                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2907                 loadmodel->sortedmodelsurfaces[index] = index;
2908                 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2909                 loadmodel->data_surfaces[index].num_firstvertex = 0;
2910                 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2911         }
2912
2913         // copy over the vertex locations and texcoords
2914         for (index = 0;index < numvtxw;index++)
2915         {
2916                 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2917                 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2918                 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2919                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2920                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
2921         }
2922
2923         // loading the faces is complicated because we need to sort them into surfaces by mattindex
2924         for (index = 0;index < numfaces;index++)
2925                 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
2926         for (index = 0, i = 0;index < nummatts;index++)
2927         {
2928                 loadmodel->data_surfaces[index].num_firsttriangle = i;
2929                 i += loadmodel->data_surfaces[index].num_triangles;
2930                 loadmodel->data_surfaces[index].num_triangles = 0;
2931         }
2932         for (index = 0;index < numfaces;index++)
2933         {
2934                 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
2935                 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
2936                 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
2937                 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
2938         }
2939
2940         // copy over the bones
2941         for (index = 0;index < numbones;index++)
2942         {
2943                 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
2944                 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
2945                 if (loadmodel->data_bones[index].parent >= index)
2946                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
2947         }
2948
2949         // sort the psk point weights into the vertex weight tables
2950         // (which only accept up to 4 bones per vertex)
2951         for (index = 0;index < numvtxw;index++)
2952         {
2953                 int weightindex[4] = { 0, 0, 0, 0 };
2954                 float weightinfluence[4] = { 0, 0, 0, 0 };
2955                 int l;
2956                 for (j = 0;j < numrawweights;j++)
2957                 {
2958                         if (rawweights[j].pntsindex == vtxw[index].pntsindex)
2959                         {
2960                                 int boneindex = rawweights[j].boneindex;
2961                                 float influence = rawweights[j].weight;
2962                                 for (l = 0;l < 4;l++)
2963                                 {
2964                                         if (weightinfluence[l] < influence)
2965                                         {
2966                                                 // move lower influence weights out of the way first
2967                                                 int l2;
2968                                                 for (l2 = 3;l2 > l;l2--)
2969                                                 {
2970                                                         weightinfluence[l2] = weightinfluence[l2-1];
2971                                                         weightindex[l2] = weightindex[l2-1];
2972                                                 }
2973                                                 // store the new weight
2974                                                 weightinfluence[l] = influence;
2975                                                 weightindex[l] = boneindex;
2976                                                 break;
2977                                         }
2978                                 }
2979                         }
2980                 }
2981                 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2982         }
2983         if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
2984                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2985
2986         // set up the animscenes based on the anims
2987         for (index = 0, i = 0;index < numanims;index++)
2988         {
2989                 for (j = 0;j < anims[index].numframes;j++, i++)
2990                 {
2991                         dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
2992                         loadmodel->animscenes[i].firstframe = i;
2993                         loadmodel->animscenes[i].framecount = 1;
2994                         loadmodel->animscenes[i].loop = true;
2995                         loadmodel->animscenes[i].framerate = anims[index].fps;
2996                 }
2997         }
2998
2999         // calculate the scaling value for bone origins so they can be compressed to short
3000         biggestorigin = 0;
3001         for (index = 0;index < numanimkeys;index++)
3002         {
3003                 pskanimkeys_t *k = animkeys + index;
3004                 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3005                 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3006                 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3007         }
3008         loadmodel->num_posescale = biggestorigin / 32767.0f;
3009         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3010
3011         // load the poses from the animkeys
3012         for (index = 0;index < numanimkeys;index++)
3013         {
3014                 pskanimkeys_t *k = animkeys + index;
3015                 float quat[4];
3016                 Vector4Copy(k->quat, quat);
3017                 if (quat[3] > 0)
3018                         Vector4Negate(quat, quat);
3019                 Vector4Normalize2(quat, quat);
3020                 // compress poses to the short[6] format for longterm storage
3021                 loadmodel->data_poses6s[index*6+0] = k->origin[0] * loadmodel->num_poseinvscale;
3022                 loadmodel->data_poses6s[index*6+1] = k->origin[1] * loadmodel->num_poseinvscale;
3023                 loadmodel->data_poses6s[index*6+2] = k->origin[2] * loadmodel->num_poseinvscale;
3024                 loadmodel->data_poses6s[index*6+3] = quat[0] * 32767.0f;
3025                 loadmodel->data_poses6s[index*6+4] = quat[1] * 32767.0f;
3026                 loadmodel->data_poses6s[index*6+5] = quat[2] * 32767.0f;
3027         }
3028         Mod_FreeSkinFiles(skinfiles);
3029         Mem_Free(animfilebuffer);
3030         Mod_MakeSortedSurfaces(loadmodel);
3031
3032         // compute all the mesh information that was not loaded from the file
3033         // TODO: honor smoothing groups somehow?
3034         if (loadmodel->surfmesh.data_element3s)
3035                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3036                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3037         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3038         Mod_BuildBaseBonePoses();
3039         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);
3040         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);
3041         if (loadmodel->surfmesh.data_neighbor3i)
3042                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
3043         Mod_Alias_CalculateBoundingBox();
3044
3045         if (!loadmodel->surfmesh.isanimated)
3046         {
3047                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3048                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3049                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3050                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3051                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3052                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3053         }
3054
3055         // because shaders can do somewhat unexpected things, check for unusual features now
3056         for (i = 0;i < loadmodel->num_textures;i++)
3057         {
3058                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3059                         mod->DrawSky = R_Q1BSP_DrawSky;
3060                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3061                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3062         }
3063 }
3064
3065 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
3066 {
3067         unsigned char *data;
3068         const char *text;
3069         const unsigned char *pbase, *pend;
3070         iqmheader_t header;
3071         skinfile_t *skinfiles;
3072         int i, j, k, meshvertices, meshtriangles;
3073         float biggestorigin;
3074         const unsigned int *inelements;
3075         int *outelements;
3076         const int *inneighbors;
3077         int *outneighbors;
3078         float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3079         // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3080         const float *vnormal = NULL;
3081         const float *vposition = NULL;
3082         const float *vtangent = NULL;
3083         const float *vtexcoord = NULL;
3084         const float *vcolor4f = NULL;
3085         const unsigned char *vblendindexes = NULL;
3086         const unsigned char *vblendweights = NULL;
3087         const unsigned char *vcolor4ub = NULL;
3088         const unsigned short *framedata = NULL;
3089         // temporary memory allocations (because the data in the file may be misaligned)
3090         iqmanim_t *anims = NULL;
3091         iqmbounds_t *bounds = NULL;
3092         iqmjoint1_t *joint1 = NULL;
3093         iqmjoint_t *joint = NULL;
3094         iqmmesh_t *meshes = NULL;
3095         iqmpose1_t *pose1 = NULL;
3096         iqmpose_t *pose = NULL;
3097         iqmvertexarray_t *vas = NULL;
3098
3099         pbase = (unsigned char *)buffer;
3100         pend = (unsigned char *)bufferend;
3101
3102         if (pbase + sizeof(iqmheader_t) > pend)
3103                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3104
3105         // copy struct (otherwise it may be misaligned)
3106         // LordHavoc: okay it's definitely not misaligned here, but for consistency...
3107         memcpy(&header, pbase, sizeof(iqmheader_t));
3108
3109         if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3110                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3111         if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3112                 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3113
3114         loadmodel->modeldatatypestring = "IQM";
3115
3116         loadmodel->type = mod_alias;
3117         loadmodel->synctype = ST_RAND;
3118
3119         // byteswap header
3120         header.version = LittleLong(header.version);
3121         header.filesize = LittleLong(header.filesize);
3122         header.flags = LittleLong(header.flags);
3123         header.num_text = LittleLong(header.num_text);
3124         header.ofs_text = LittleLong(header.ofs_text);
3125         header.num_meshes = LittleLong(header.num_meshes);
3126         header.ofs_meshes = LittleLong(header.ofs_meshes);
3127         header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3128         header.num_vertexes = LittleLong(header.num_vertexes);
3129         header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3130         header.num_triangles = LittleLong(header.num_triangles);
3131         header.ofs_triangles = LittleLong(header.ofs_triangles);
3132         header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3133         header.num_joints = LittleLong(header.num_joints);
3134         header.ofs_joints = LittleLong(header.ofs_joints);
3135         header.num_poses = LittleLong(header.num_poses);
3136         header.ofs_poses = LittleLong(header.ofs_poses);
3137         header.num_anims = LittleLong(header.num_anims);
3138         header.ofs_anims = LittleLong(header.ofs_anims);
3139         header.num_frames = LittleLong(header.num_frames);
3140         header.num_framechannels = LittleLong(header.num_framechannels);
3141         header.ofs_frames = LittleLong(header.ofs_frames);
3142         header.ofs_bounds = LittleLong(header.ofs_bounds);
3143         header.num_comment = LittleLong(header.num_comment);
3144         header.ofs_comment = LittleLong(header.ofs_comment);
3145         header.num_extensions = LittleLong(header.num_extensions);
3146         header.ofs_extensions = LittleLong(header.ofs_extensions);
3147
3148         if (header.version == 1)
3149         {
3150                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3151                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3152                 {
3153                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3154                         return;
3155                 }
3156         }
3157         else
3158         {
3159                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3160                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3161                 {
3162                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3163                         return;
3164                 }
3165         }
3166         if (pbase + header.ofs_text + header.num_text > pend ||
3167                 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3168                 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3169                 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3170                 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3171                 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3172                 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3173                 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3174                 pbase + header.ofs_comment + header.num_comment > pend)
3175         {
3176                 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3177                 return;
3178         }
3179
3180         // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3181         if (header.num_vertexarrays)
3182                 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3183         if (header.num_anims)
3184                 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3185         if (header.ofs_bounds)
3186                 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3187         if (header.num_meshes)
3188                 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3189
3190         for (i = 0;i < (int)header.num_vertexarrays;i++)
3191         {
3192                 iqmvertexarray_t va;
3193                 size_t vsize;
3194                 va.type = LittleLong(vas[i].type);
3195                 va.flags = LittleLong(vas[i].flags);
3196                 va.format = LittleLong(vas[i].format);
3197                 va.size = LittleLong(vas[i].size);
3198                 va.offset = LittleLong(vas[i].offset);
3199                 vsize = header.num_vertexes*va.size;
3200                 switch (va.format)
3201                 { 
3202                 case IQM_FLOAT: vsize *= sizeof(float); break;
3203                 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3204                 default: continue;
3205                 }
3206                 if (pbase + va.offset + vsize > pend)
3207                         continue;
3208                 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3209                 switch (va.type)
3210                 {
3211                 case IQM_POSITION:
3212                         if (va.format == IQM_FLOAT && va.size == 3)
3213                                 vposition = (const float *)(pbase + va.offset);
3214                         break;
3215                 case IQM_TEXCOORD:
3216                         if (va.format == IQM_FLOAT && va.size == 2)
3217                                 vtexcoord = (const float *)(pbase + va.offset);
3218                         break;
3219                 case IQM_NORMAL:
3220                         if (va.format == IQM_FLOAT && va.size == 3)
3221                                 vnormal = (const float *)(pbase + va.offset);
3222                         break;
3223                 case IQM_TANGENT:
3224                         if (va.format == IQM_FLOAT && va.size == 4)
3225                                 vtangent = (const float *)(pbase + va.offset);
3226                         break;
3227                 case IQM_BLENDINDEXES:
3228                         if (va.format == IQM_UBYTE && va.size == 4)
3229                                 vblendindexes = (const unsigned char *)(pbase + va.offset);
3230                         break;
3231                 case IQM_BLENDWEIGHTS:
3232                         if (va.format == IQM_UBYTE && va.size == 4)
3233                                 vblendweights = (const unsigned char *)(pbase + va.offset);
3234                         break;
3235                 case IQM_COLOR:
3236                         if (va.format == IQM_FLOAT && va.size == 4)
3237                                 vcolor4f = (const float *)(pbase + va.offset);
3238                         if (va.format == IQM_UBYTE && va.size == 4)
3239                                 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3240                         break;
3241                 }
3242         }
3243         if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3244         {
3245                 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3246                 return;
3247         }
3248
3249         text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3250
3251         loadmodel->DrawSky = NULL;
3252         loadmodel->DrawAddWaterPlanes = NULL;
3253         loadmodel->Draw = R_Q1BSP_Draw;
3254         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
3255         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
3256         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
3257         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
3258         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
3259         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
3260         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
3261         loadmodel->DrawLight = R_Q1BSP_DrawLight;
3262         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3263         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3264         loadmodel->PointSuperContents = NULL;
3265
3266         // load external .skin files if present
3267         skinfiles = Mod_LoadSkinFiles();
3268         if (loadmodel->numskins < 1)
3269                 loadmodel->numskins = 1;
3270
3271         loadmodel->numframes = max(header.num_anims, 1);
3272         loadmodel->num_bones = header.num_joints;
3273         loadmodel->num_poses = max(header.num_frames, 1);
3274         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
3275         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3276         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3277         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices; // updated later
3278
3279         meshvertices = header.num_vertexes;
3280         meshtriangles = header.num_triangles;
3281
3282         // do most allocations as one merged chunk
3283         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));
3284         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3285         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3286         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3287         loadmodel->surfmesh.num_vertices = meshvertices;
3288         loadmodel->surfmesh.num_triangles = meshtriangles;
3289         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3290         if (r_enableshadowvolumes.integer)
3291         {
3292                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3293         }
3294         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3295         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3296         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3297         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3298         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3299         if (vcolor4f || vcolor4ub)
3300         {
3301                 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3302         }
3303         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3304         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3305         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3306         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3307         if (vblendindexes && vblendweights)
3308         {
3309                 loadmodel->surfmesh.num_blends = 0;
3310                 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3311         }
3312         if (meshvertices <= 65536)
3313         {
3314                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3315         }
3316         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
3317         if (vblendindexes && vblendweights)
3318                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3319
3320         for (i = 0;i < loadmodel->numskins;i++)
3321         {
3322                 loadmodel->skinscenes[i].firstframe = i;
3323                 loadmodel->skinscenes[i].framecount = 1;
3324                 loadmodel->skinscenes[i].loop = true;
3325                 loadmodel->skinscenes[i].framerate = 10;
3326         }
3327
3328         // load the bone info
3329         if (header.version == 1)
3330         {
3331                 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3332                 if (loadmodel->num_bones)
3333                         joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3334                 for (i = 0;i < loadmodel->num_bones;i++)
3335                 {
3336                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3337                         joint1[i].name = LittleLong(injoint1[i].name);
3338                         joint1[i].parent = LittleLong(injoint1[i].parent);
3339                         for (j = 0;j < 3;j++)
3340                         {
3341                                 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3342                                 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3343                                 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3344                         }
3345                         strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3346                         loadmodel->data_bones[i].parent = joint1[i].parent;
3347                         if (loadmodel->data_bones[i].parent >= i)
3348                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3349                         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]);
3350                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3351                         if (loadmodel->data_bones[i].parent >= 0)
3352                         {
3353                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3354                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3355                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3356                         }
3357                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3358                 }
3359         }
3360         else
3361         {
3362                 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3363                 if (header.num_joints)
3364                         joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3365                 for (i = 0;i < loadmodel->num_bones;i++)
3366                 {
3367                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3368                         joint[i].name = LittleLong(injoint[i].name);
3369                         joint[i].parent = LittleLong(injoint[i].parent);
3370                         for (j = 0;j < 3;j++)
3371                         {
3372                                 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3373                                 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3374                                 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3375                         }
3376                         joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3377                         strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3378                         loadmodel->data_bones[i].parent = joint[i].parent;
3379                         if (loadmodel->data_bones[i].parent >= i)
3380                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3381                         if (joint[i].rotation[3] > 0)
3382                                 Vector4Negate(joint[i].rotation, joint[i].rotation);
3383                         Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3384                         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]);
3385                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3386                         if (loadmodel->data_bones[i].parent >= 0)
3387                         {
3388                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3389                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3390                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3391                         }       
3392                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3393                 }
3394         }
3395
3396         // set up the animscenes based on the anims
3397         for (i = 0;i < (int)header.num_anims;i++)
3398         {
3399                 iqmanim_t anim;
3400                 anim.name = LittleLong(anims[i].name);
3401                 anim.first_frame = LittleLong(anims[i].first_frame);
3402                 anim.num_frames = LittleLong(anims[i].num_frames);
3403                 anim.framerate = LittleFloat(anims[i].framerate);
3404                 anim.flags = LittleLong(anims[i].flags);
3405                 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3406                 loadmodel->animscenes[i].firstframe = anim.first_frame;
3407                 loadmodel->animscenes[i].framecount = anim.num_frames;
3408                 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3409                 loadmodel->animscenes[i].framerate = anim.framerate;
3410         }
3411         if (header.num_anims <= 0)
3412         {
3413                 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3414                 loadmodel->animscenes[0].firstframe = 0;
3415                 loadmodel->animscenes[0].framecount = 1;
3416                 loadmodel->animscenes[0].loop = true;
3417                 loadmodel->animscenes[0].framerate = 10;
3418         }
3419
3420         loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3421         loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
3422
3423         biggestorigin = 0;
3424         if (header.version == 1)
3425         {
3426                 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3427                 if (header.num_poses)
3428                         pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3429                 for (i = 0;i < (int)header.num_poses;i++)
3430                 {
3431                         float f;
3432                         pose1[i].parent = LittleLong(inpose1[i].parent);
3433                         pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3434                         for (j = 0;j < 9;j++)
3435                         {
3436                                 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3437                                 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3438                         }
3439                         f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3440                         f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3441                         f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3442                         f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3443                         f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3444                         f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3445                 }
3446                 if (header.num_frames <= 0)
3447                 {
3448                         for (i = 0;i < loadmodel->num_bones;i++)
3449                         {
3450                                 float f;
3451                                 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3452                                 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3453                                 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3454                         }
3455                 }
3456         }
3457         else
3458         {
3459                 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3460                 if (header.num_poses)
3461                         pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3462                 for (i = 0;i < (int)header.num_poses;i++)
3463                 {
3464                         float f;
3465                         pose[i].parent = LittleLong(inpose[i].parent);
3466                         pose[i].channelmask = LittleLong(inpose[i].channelmask);
3467                         for (j = 0;j < 10;j++)
3468                         {
3469                                 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3470                                 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3471                         }
3472                         f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3473                         f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3474                         f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3475                         f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3476                         f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3477                         f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3478                 }
3479                 if (header.num_frames <= 0)
3480                 {
3481                         for (i = 0;i < loadmodel->num_bones;i++)
3482                         {
3483                                 float f;
3484                                 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3485                                 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3486                                 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3487                         }
3488                 }
3489         }
3490         loadmodel->num_posescale = biggestorigin / 32767.0f;
3491         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3492
3493         // load the pose data
3494         // this unaligned memory access is safe (LittleShort reads as bytes)
3495         framedata = (const unsigned short *)(pbase + header.ofs_frames);
3496         if (header.version == 1)
3497         {
3498                 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3499                 {
3500                         for (j = 0;j < (int)header.num_poses;j++, k++)
3501                         {
3502                                 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));
3503                                 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));
3504                                 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));
3505                                 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));
3506                                 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));
3507                                 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));
3508                                 // skip scale data for now
3509                                 if(pose1[j].channelmask&64) framedata++;
3510                                 if(pose1[j].channelmask&128) framedata++;
3511                                 if(pose1[j].channelmask&256) framedata++;
3512                         }
3513                 }
3514                 if (header.num_frames <= 0)
3515                 {
3516                         for (i = 0;i < loadmodel->num_bones;i++)
3517                         {
3518                                 loadmodel->data_poses6s[i*6 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3519                                 loadmodel->data_poses6s[i*6 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3520                                 loadmodel->data_poses6s[i*6 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3521                                 loadmodel->data_poses6s[i*6 + 3] = 32767.0f * joint1[i].rotation[0];
3522                                 loadmodel->data_poses6s[i*6 + 4] = 32767.0f * joint1[i].rotation[1];
3523                                 loadmodel->data_poses6s[i*6 + 5] = 32767.0f * joint1[i].rotation[2];
3524                         }
3525                 }
3526         }
3527         else
3528         {
3529                 for (i = 0, k = 0;i < (int)header.num_frames;i++)       
3530                 {
3531                         for (j = 0;j < (int)header.num_poses;j++, k++)
3532                         {
3533                                 float rot[4];
3534                                 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));
3535                                 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));
3536                                 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));
3537                                 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3538                                 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3539                                 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3540                                 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3541                                 if (rot[3] > 0)
3542                                         Vector4Negate(rot, rot);
3543                                 Vector4Normalize2(rot, rot);
3544                                 loadmodel->data_poses6s[k*6 + 3] = 32767.0f * rot[0];
3545                                 loadmodel->data_poses6s[k*6 + 4] = 32767.0f * rot[1];
3546                                 loadmodel->data_poses6s[k*6 + 5] = 32767.0f * rot[2];
3547                                 // skip scale data for now
3548                                 if(pose[j].channelmask&128) framedata++;
3549                                 if(pose[j].channelmask&256) framedata++;
3550                                 if(pose[j].channelmask&512) framedata++;
3551                         }
3552                 }
3553                 if (header.num_frames <= 0)
3554                 {
3555                         for (i = 0;i < loadmodel->num_bones;i++)
3556                         {
3557                                 loadmodel->data_poses6s[i*6 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3558                                 loadmodel->data_poses6s[i*6 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3559                                 loadmodel->data_poses6s[i*6 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3560                                 loadmodel->data_poses6s[i*6 + 3] = 32767.0f * joint[i].rotation[0];
3561                                 loadmodel->data_poses6s[i*6 + 4] = 32767.0f * joint[i].rotation[1];
3562                                 loadmodel->data_poses6s[i*6 + 5] = 32767.0f * joint[i].rotation[2];
3563                         }
3564                 }
3565         }
3566
3567         // load bounding box data
3568         if (header.ofs_bounds)
3569         {
3570                 float xyradius = 0, radius = 0;
3571                 VectorClear(loadmodel->normalmins);
3572                 VectorClear(loadmodel->normalmaxs);
3573                 for (i = 0; i < (int)header.num_frames;i++)
3574                 {
3575                         iqmbounds_t bound;
3576                         bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3577                         bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3578                         bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3579                         bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);                 
3580                         bound.maxs[1] = LittleFloat(bounds[i].maxs[1]); 
3581                         bound.maxs[2] = LittleFloat(bounds[i].maxs[2]); 
3582                         bound.xyradius = LittleFloat(bounds[i].xyradius);
3583                         bound.radius = LittleFloat(bounds[i].radius);
3584                         if (!i)
3585                         {
3586                                 VectorCopy(bound.mins, loadmodel->normalmins);
3587                                 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3588                         }
3589                         else
3590                         {
3591                                 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3592                                 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3593                                 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3594                                 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3595                                 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3596                                 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3597                         }
3598                         if (bound.xyradius > xyradius)
3599                                 xyradius = bound.xyradius;
3600                         if (bound.radius > radius)
3601                                 radius = bound.radius;
3602                 }
3603                 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3604                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3605                 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3606                 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3607                 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3608                 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3609                 loadmodel->radius = radius;
3610                 loadmodel->radius2 = radius * radius;
3611         }
3612
3613         // load triangle data
3614         // this unaligned memory access is safe (LittleLong reads as bytes)
3615         inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3616         outelements = loadmodel->surfmesh.data_element3i;
3617         for (i = 0;i < (int)header.num_triangles;i++)
3618         {
3619                 outelements[0] = LittleLong(inelements[0]);
3620                 outelements[1] = LittleLong(inelements[1]);
3621                 outelements[2] = LittleLong(inelements[2]);
3622                 outelements += 3;
3623                 inelements += 3;
3624         }
3625         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3626
3627         if (header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
3628         {
3629                 // this unaligned memory access is safe (LittleLong reads as bytes)
3630                 inneighbors = (const int *)(pbase + header.ofs_neighbors);
3631                 outneighbors = loadmodel->surfmesh.data_neighbor3i;
3632                 for (i = 0;i < (int)header.num_triangles;i++)
3633                 {
3634                         outneighbors[0] = LittleLong(inneighbors[0]);
3635                         outneighbors[1] = LittleLong(inneighbors[1]);
3636                         outneighbors[2] = LittleLong(inneighbors[2]);
3637                         outneighbors += 3;
3638                         inneighbors += 3;
3639                 }
3640         }
3641
3642         // load vertex data
3643         // this unaligned memory access is safe (LittleFloat reads as bytes)
3644         outvertex = loadmodel->surfmesh.data_vertex3f;
3645         for (i = 0;i < (int)header.num_vertexes;i++)
3646         {
3647                 outvertex[0] = LittleFloat(vposition[0]);
3648                 outvertex[1] = LittleFloat(vposition[1]);
3649                 outvertex[2] = LittleFloat(vposition[2]);
3650                 vposition += 3;
3651                 outvertex += 3;
3652         }
3653
3654         outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3655         // this unaligned memory access is safe (LittleFloat reads as bytes)
3656         for (i = 0;i < (int)header.num_vertexes;i++)
3657         {
3658                 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3659                 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3660                 vtexcoord += 2;
3661                 outtexcoord += 2;
3662         }
3663
3664         // this unaligned memory access is safe (LittleFloat reads as bytes)
3665         if(vnormal)
3666         {
3667                 outnormal = loadmodel->surfmesh.data_normal3f;
3668                 for (i = 0;i < (int)header.num_vertexes;i++)
3669                 {
3670                         outnormal[0] = LittleFloat(vnormal[0]);
3671                         outnormal[1] = LittleFloat(vnormal[1]);
3672                         outnormal[2] = LittleFloat(vnormal[2]);
3673                         vnormal += 3;
3674                         outnormal += 3;
3675                 }
3676         }
3677
3678         // this unaligned memory access is safe (LittleFloat reads as bytes)
3679         if(vnormal && vtangent)
3680         {
3681                 outnormal = loadmodel->surfmesh.data_normal3f;
3682                 outsvector = loadmodel->surfmesh.data_svector3f;
3683                 outtvector = loadmodel->surfmesh.data_tvector3f;
3684                 for (i = 0;i < (int)header.num_vertexes;i++)
3685                 {
3686                         outsvector[0] = LittleFloat(vtangent[0]);
3687                         outsvector[1] = LittleFloat(vtangent[1]);
3688                         outsvector[2] = LittleFloat(vtangent[2]);
3689                         if(LittleFloat(vtangent[3]) < 0)
3690                                 CrossProduct(outsvector, outnormal, outtvector);
3691                         else
3692                                 CrossProduct(outnormal, outsvector, outtvector);
3693                         vtangent += 4;
3694                         outnormal += 3;
3695                         outsvector += 3;
3696                         outtvector += 3;
3697                 }
3698         }
3699
3700         // this unaligned memory access is safe (all bytes)
3701         if (vblendindexes && vblendweights)
3702         {
3703                 for (i = 0; i < (int)header.num_vertexes;i++)
3704                 {
3705                         blendweights_t weights;
3706                         memcpy(weights.index, vblendindexes + i*4, 4);
3707                         memcpy(weights.influence, vblendweights + i*4, 4);
3708                         loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3709                 }
3710         }
3711
3712         if (vcolor4f)
3713         {
3714                 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3715                 // this unaligned memory access is safe (LittleFloat reads as bytes)
3716                 for (i = 0;i < (int)header.num_vertexes;i++)
3717                 {
3718                         outcolor[0] = LittleFloat(vcolor4f[0]);
3719                         outcolor[1] = LittleFloat(vcolor4f[1]);
3720                         outcolor[2] = LittleFloat(vcolor4f[2]);
3721                         outcolor[3] = LittleFloat(vcolor4f[3]);
3722                         vcolor4f += 4;
3723                         outcolor += 4;
3724                 }
3725         }
3726         else if (vcolor4ub)
3727         {
3728                 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3729                 // this unaligned memory access is safe (all bytes)
3730                 for (i = 0;i < (int)header.num_vertexes;i++)
3731                 {
3732                         outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3733                         outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3734                         outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3735                         outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3736                         vcolor4ub += 4;
3737                         outcolor += 4;
3738                 }
3739         }
3740
3741         // load meshes
3742         for (i = 0;i < (int)header.num_meshes;i++)
3743         {
3744                 iqmmesh_t mesh;
3745                 msurface_t *surface;
3746
3747                 mesh.name = LittleLong(meshes[i].name);
3748                 mesh.material = LittleLong(meshes[i].material);
3749                 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3750                 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3751                 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3752                 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3753
3754                 loadmodel->sortedmodelsurfaces[i] = i;
3755                 surface = loadmodel->data_surfaces + i;
3756                 surface->texture = loadmodel->data_textures + i;
3757                 surface->num_firsttriangle = mesh.first_triangle;
3758                 surface->num_triangles = mesh.num_triangles;
3759                 surface->num_firstvertex = mesh.first_vertex;
3760                 surface->num_vertices = mesh.num_vertexes;
3761
3762                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3763         }
3764
3765         Mod_FreeSkinFiles(skinfiles);
3766         Mod_MakeSortedSurfaces(loadmodel);
3767
3768         // compute all the mesh information that was not loaded from the file
3769         if (loadmodel->surfmesh.data_element3s)
3770                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3771                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3772         if (!vnormal)
3773                 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);
3774         if (!vnormal || !vtangent)
3775                 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);
3776         if (!header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
3777                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
3778         if (!header.ofs_bounds)
3779                 Mod_Alias_CalculateBoundingBox();
3780
3781         if (!loadmodel->surfmesh.isanimated && loadmodel->surfmesh.num_triangles >= 1)
3782         {
3783                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3784                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3785                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3786                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3787                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3788                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3789         }
3790
3791         if (joint        ) Mem_Free(joint        );joint         = NULL;
3792         if (joint1       ) Mem_Free(joint1       );joint1        = NULL;
3793         if (pose         ) Mem_Free(pose         );pose          = NULL;
3794         if (pose1        ) Mem_Free(pose1        );pose1         = NULL;
3795
3796         // because shaders can do somewhat unexpected things, check for unusual features now
3797         for (i = 0;i < loadmodel->num_textures;i++)
3798         {
3799                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3800                         mod->DrawSky = R_Q1BSP_DrawSky;
3801                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3802                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3803         }
3804 }