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