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