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