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