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