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