]> icculus.org git repositories - divverent/darkplaces.git/blob - model_alias.c
reworked mdl .skin file loading a bit to fix problems with not loading
[divverent/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
25 cvar_t r_skeletal_debugbone = {0, "r_skeletal_debugbone", "-1", "development cvar for testing skeletal model code"};
26 cvar_t r_skeletal_debugbonecomponent = {0, "r_skeletal_debugbonecomponent", "3", "development cvar for testing skeletal model code"};
27 cvar_t r_skeletal_debugbonevalue = {0, "r_skeletal_debugbonevalue", "100", "development cvar for testing skeletal model code"};
28 cvar_t r_skeletal_debugtranslatex = {0, "r_skeletal_debugtranslatex", "1", "development cvar for testing skeletal model code"};
29 cvar_t r_skeletal_debugtranslatey = {0, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"};
30 cvar_t r_skeletal_debugtranslatez = {0, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"};
31
32 float mod_md3_sin[320];
33
34 void Mod_AliasInit (void)
35 {
36         int i;
37         Cvar_RegisterVariable(&r_skeletal_debugbone);
38         Cvar_RegisterVariable(&r_skeletal_debugbonecomponent);
39         Cvar_RegisterVariable(&r_skeletal_debugbonevalue);
40         Cvar_RegisterVariable(&r_skeletal_debugtranslatex);
41         Cvar_RegisterVariable(&r_skeletal_debugtranslatey);
42         Cvar_RegisterVariable(&r_skeletal_debugtranslatez);
43         for (i = 0;i < 320;i++)
44                 mod_md3_sin[i] = sin(i * M_PI * 2.0f / 256.0);
45 }
46
47 void Mod_Skeletal_AnimateVertices(const dp_model_t *model, const frameblend_t *frameblend, float *vertex3f, float *normal3f, float *svector3f, float *tvector3f)
48 {
49 #define MAX_BONES 256
50         // vertex weighted skeletal
51         int i, k;
52         int blends;
53         float boneposerelative[MAX_BONES][12];
54         float *matrix, m[12], bonepose[MAX_BONES][12];
55
56         // interpolate matrices and concatenate them to their parents
57         for (i = 0;i < model->num_bones;i++)
58         {
59                 for (k = 0;k < 12;k++)
60                         m[k] = 0;
61                 for (blends = 0;blends < 4 && frameblend[blends].lerp > 0;blends++)
62                 {
63                         matrix = model->data_poses + (frameblend[blends].frame * model->num_bones + i) * 12;
64                         for (k = 0;k < 12;k++)
65                                 m[k] += matrix[k] * frameblend[blends].lerp;
66                 }
67                 if (i == r_skeletal_debugbone.integer)
68                         m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value;
69                 m[3] *= r_skeletal_debugtranslatex.value;
70                 m[7] *= r_skeletal_debugtranslatey.value;
71                 m[11] *= r_skeletal_debugtranslatez.value;
72                 if (model->data_bones[i].parent >= 0)
73                         R_ConcatTransforms(bonepose[model->data_bones[i].parent], m, bonepose[i]);
74                 else
75                         for (k = 0;k < 12;k++)
76                                 bonepose[i][k] = m[k];
77                 // create a relative deformation matrix to describe displacement
78                 // from the base mesh, which is used by the actual weighting
79                 R_ConcatTransforms(bonepose[i], model->data_baseboneposeinverse + i * 12, boneposerelative[i]);
80         }
81         // blend the vertex bone weights
82         // special case for the extremely common wf[0] == 1 because it saves 3 multiplies per array when compared to the other case (w[0] is always 1 if only one bone controls this vertex, artists only use multiple bones for certain special cases)
83         // special case for the first bone because it avoids the need to memset the arrays before filling
84         {
85                 const float *v = model->surfmesh.data_vertex3f;
86                 const int *wi = model->surfmesh.data_vertexweightindex4i;
87                 const float *wf = model->surfmesh.data_vertexweightinfluence4f;
88                 memset(vertex3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices);
89                 for (i = 0;i < model->surfmesh.num_vertices;i++, v += 3, wi += 4, wf += 4, vertex3f += 3)
90                 {
91                         if (wf[0] == 1)
92                         {
93                                 const float *m = boneposerelative[wi[0]];
94                                 vertex3f[0] = (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
95                                 vertex3f[1] = (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
96                                 vertex3f[2] = (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
97                         }
98                         else
99                         {
100                                 const float *m = boneposerelative[wi[0]];
101                                 float f = wf[0];
102                                 vertex3f[0] = f * (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
103                                 vertex3f[1] = f * (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
104                                 vertex3f[2] = f * (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
105                                 for (k = 1;k < 4 && wf[k];k++)
106                                 {
107                                         const float *m = boneposerelative[wi[k]];
108                                         float f = wf[k];
109                                         vertex3f[0] += f * (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
110                                         vertex3f[1] += f * (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
111                                         vertex3f[2] += f * (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
112                                 }
113                         }
114                 }
115         }
116         if (normal3f)
117         {
118                 const float *n = model->surfmesh.data_normal3f;
119                 const int *wi = model->surfmesh.data_vertexweightindex4i;
120                 const float *wf = model->surfmesh.data_vertexweightinfluence4f;
121                 memset(normal3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices);
122                 for (i = 0;i < model->surfmesh.num_vertices;i++, n += 3, wi += 4, wf += 4, normal3f += 3)
123                 {
124                         if (wf[0] == 1)
125                         {
126                                 const float *m = boneposerelative[wi[0]];
127                                 normal3f[0] = (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
128                                 normal3f[1] = (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]);
129                                 normal3f[2] = (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]);
130                         }
131                         else
132                         {
133                                 const float *m = boneposerelative[wi[0]];
134                                 float f = wf[0];
135                                 normal3f[0] = f * (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
136                                 normal3f[1] = f * (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]);
137                                 normal3f[2] = f * (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]);
138                                 for (k = 1;k < 4 && wf[k];k++)
139                                 {
140                                         const float *m = boneposerelative[wi[k]];
141                                         float f = wf[k];
142                                         normal3f[0] += f * (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
143                                         normal3f[1] += f * (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]);
144                                         normal3f[2] += f * (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]);
145                                 }
146                         }
147                 }
148         }
149         if (svector3f)
150         {
151                 const float *sv = model->surfmesh.data_svector3f;
152                 const int *wi = model->surfmesh.data_vertexweightindex4i;
153                 const float *wf = model->surfmesh.data_vertexweightinfluence4f;
154                 memset(svector3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices);
155                 for (i = 0;i < model->surfmesh.num_vertices;i++, sv += 3, wi += 4, wf += 4, svector3f += 3)
156                 {
157                         if (wf[0] == 1)
158                         {
159                                 const float *m = boneposerelative[wi[0]];
160                                 svector3f[0] = (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]);
161                                 svector3f[1] = (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]);
162                                 svector3f[2] = (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]);
163                         }
164                         else
165                         {
166                                 const float *m = boneposerelative[wi[0]];
167                                 float f = wf[0];
168                                 svector3f[0] = f * (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]);
169                                 svector3f[1] = f * (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]);
170                                 svector3f[2] = f * (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]);
171                                 for (k = 1;k < 4 && wf[k];k++)
172                                 {
173                                         const float *m = boneposerelative[wi[k]];
174                                         float f = wf[k];
175                                         svector3f[0] += f * (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]);
176                                         svector3f[1] += f * (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]);
177                                         svector3f[2] += f * (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]);
178                                 }
179                         }
180                 }
181         }
182         if (tvector3f)
183         {
184                 const float *tv = model->surfmesh.data_tvector3f;
185                 const int *wi = model->surfmesh.data_vertexweightindex4i;
186                 const float *wf = model->surfmesh.data_vertexweightinfluence4f;
187                 memset(tvector3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices);
188                 for (i = 0;i < model->surfmesh.num_vertices;i++, tv += 3, wi += 4, wf += 4, tvector3f += 3)
189                 {
190                         if (wf[0] == 1)
191                         {
192                                 const float *m = boneposerelative[wi[0]];
193                                 tvector3f[0] = (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]);
194                                 tvector3f[1] = (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]);
195                                 tvector3f[2] = (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]);
196                         }
197                         else
198                         {
199                                 const float *m = boneposerelative[wi[0]];
200                                 float f = wf[0];
201                                 tvector3f[0] = f * (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]);
202                                 tvector3f[1] = f * (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]);
203                                 tvector3f[2] = f * (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]);
204                                 for (k = 1;k < 4 && wf[k];k++)
205                                 {
206                                         const float *m = boneposerelative[wi[k]];
207                                         float f = wf[k];
208                                         tvector3f[0] += f * (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]);
209                                         tvector3f[1] += f * (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]);
210                                         tvector3f[2] += f * (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]);
211                                 }
212                         }
213                 }
214         }
215 }
216
217 void Mod_MD3_AnimateVertices(const dp_model_t *model, const frameblend_t *frameblend, float *vertex3f, float *normal3f, float *svector3f, float *tvector3f)
218 {
219         // vertex morph
220         int i, numblends, blendnum;
221         int numverts = model->surfmesh.num_vertices;
222         numblends = 0;
223         for (blendnum = 0;blendnum < 4;blendnum++)
224         {
225                 //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate);
226                 if (frameblend[blendnum].lerp > 0)
227                         numblends = blendnum + 1;
228         }
229         // special case for the first blend because it avoids some adds and the need to memset the arrays first
230         for (blendnum = 0;blendnum < numblends;blendnum++)
231         {
232                 const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].frame;
233                 float scale = frameblend[blendnum].lerp * (1.0f / 64.0f);
234                 if (blendnum == 0)
235                 {
236                         for (i = 0;i < numverts;i++)
237                         {
238                                 vertex3f[i * 3 + 0] = verts[i].origin[0] * scale;
239                                 vertex3f[i * 3 + 1] = verts[i].origin[1] * scale;
240                                 vertex3f[i * 3 + 2] = verts[i].origin[2] * scale;
241                         }
242                 }
243                 else
244                 {
245                         for (i = 0;i < numverts;i++)
246                         {
247                                 vertex3f[i * 3 + 0] += verts[i].origin[0] * scale;
248                                 vertex3f[i * 3 + 1] += verts[i].origin[1] * scale;
249                                 vertex3f[i * 3 + 2] += verts[i].origin[2] * scale;
250                         }
251                 }
252                 // the yaw and pitch stored in md3 models are 8bit quantized angles
253                 // (0-255), and as such a lookup table is very well suited to
254                 // decoding them, and since cosine is equivilant to sine with an
255                 // extra 45 degree rotation, this uses one lookup table for both
256                 // sine and cosine with a +64 bias to get cosine.
257                 if (normal3f)
258                 {
259                         float lerp = frameblend[blendnum].lerp;
260                         if (blendnum == 0)
261                         {
262                                 for (i = 0;i < numverts;i++)
263                                 {
264                                         normal3f[i * 3 + 0] = mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch     ] * lerp;
265                                         normal3f[i * 3 + 1] = mod_md3_sin[verts[i].yaw     ] * mod_md3_sin[verts[i].pitch     ] * lerp;
266                                         normal3f[i * 3 + 2] =                                  mod_md3_sin[verts[i].pitch + 64] * lerp;
267                                 }
268                         }
269                         else
270                         {
271                                 for (i = 0;i < numverts;i++)
272                                 {
273                                         normal3f[i * 3 + 0] += mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch     ] * lerp;
274                                         normal3f[i * 3 + 1] += mod_md3_sin[verts[i].yaw     ] * mod_md3_sin[verts[i].pitch     ] * lerp;
275                                         normal3f[i * 3 + 2] +=                                  mod_md3_sin[verts[i].pitch + 64] * lerp;
276                                 }
277                         }
278                 }
279                 if (svector3f)
280                 {
281                         const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].frame;
282                         float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
283                         if (blendnum == 0)
284                         {
285                                 for (i = 0;i < numverts;i++, texvecvert++)
286                                 {
287                                         VectorScale(texvecvert->svec, f, svector3f + i*3);
288                                         VectorScale(texvecvert->tvec, f, tvector3f + i*3);
289                                 }
290                         }
291                         else
292                         {
293                                 for (i = 0;i < numverts;i++, texvecvert++)
294                                 {
295                                         VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
296                                         VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
297                                 }
298                         }
299                 }
300         }
301 }
302
303 void Mod_MDL_AnimateVertices(const dp_model_t *model, const frameblend_t *frameblend, float *vertex3f, float *normal3f, float *svector3f, float *tvector3f)
304 {
305         // vertex morph
306         int i, numblends, blendnum;
307         int numverts = model->surfmesh.num_vertices;
308         float translate[3];
309         VectorClear(translate);
310         numblends = 0;
311         // blend the frame translates to avoid redundantly doing so on each vertex
312         // (a bit of a brain twister but it works)
313         for (blendnum = 0;blendnum < 4;blendnum++)
314         {
315                 if (model->surfmesh.data_morphmd2framesize6f)
316                         VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].frame * 6 + 3, translate);
317                 else
318                         VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate);
319                 if (frameblend[blendnum].lerp > 0)
320                         numblends = blendnum + 1;
321         }
322         // special case for the first blend because it avoids some adds and the need to memset the arrays first
323         for (blendnum = 0;blendnum < numblends;blendnum++)
324         {
325                 const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].frame;
326                 float scale[3];
327                 if (model->surfmesh.data_morphmd2framesize6f)
328                         VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].frame * 6, frameblend[blendnum].lerp, scale);
329                 else
330                         VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale);
331                 if (blendnum == 0)
332                 {
333                         for (i = 0;i < numverts;i++)
334                         {
335                                 vertex3f[i * 3 + 0] = translate[0] + verts[i].v[0] * scale[0];
336                                 vertex3f[i * 3 + 1] = translate[1] + verts[i].v[1] * scale[1];
337                                 vertex3f[i * 3 + 2] = translate[2] + verts[i].v[2] * scale[2];
338                         }
339                 }
340                 else
341                 {
342                         for (i = 0;i < numverts;i++)
343                         {
344                                 vertex3f[i * 3 + 0] += verts[i].v[0] * scale[0];
345                                 vertex3f[i * 3 + 1] += verts[i].v[1] * scale[1];
346                                 vertex3f[i * 3 + 2] += verts[i].v[2] * scale[2];
347                         }
348                 }
349                 // the vertex normals in mdl models are an index into a table of
350                 // 162 unique values, this very crude quantization reduces the
351                 // vertex normal to only one byte, which saves a lot of space but
352                 // also makes lighting pretty coarse
353                 if (normal3f)
354                 {
355                         float lerp = frameblend[blendnum].lerp;
356                         if (blendnum == 0)
357                         {
358                                 for (i = 0;i < numverts;i++)
359                                 {
360                                         const float *vn = m_bytenormals[verts[i].lightnormalindex];
361                                         VectorScale(vn, lerp, normal3f + i*3);
362                                 }
363                         }
364                         else
365                         {
366                                 for (i = 0;i < numverts;i++)
367                                 {
368                                         const float *vn = m_bytenormals[verts[i].lightnormalindex];
369                                         VectorMA(normal3f + i*3, lerp, vn, normal3f + i*3);
370                                 }
371                         }
372                 }
373                 if (svector3f)
374                 {
375                         const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].frame;
376                         float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
377                         if (blendnum == 0)
378                         {
379                                 for (i = 0;i < numverts;i++, texvecvert++)
380                                 {
381                                         VectorScale(texvecvert->svec, f, svector3f + i*3);
382                                         VectorScale(texvecvert->tvec, f, tvector3f + i*3);
383                                 }
384                         }
385                         else
386                         {
387                                 for (i = 0;i < numverts;i++, texvecvert++)
388                                 {
389                                         VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
390                                         VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
391                                 }
392                         }
393                 }
394         }
395 }
396
397 int Mod_Alias_GetTagMatrix(const dp_model_t *model, int poseframe, int tagindex, matrix4x4_t *outmatrix)
398 {
399         const float *boneframe;
400         float tempbonematrix[12], bonematrix[12];
401         *outmatrix = identitymatrix;
402         if (model->num_bones)
403         {
404                 if (tagindex < 0 || tagindex >= model->num_bones)
405                         return 4;
406                 if (poseframe >= model->num_poses)
407                         return 6;
408                 boneframe = model->data_poses + poseframe * model->num_bones * 12;
409                 memcpy(bonematrix, boneframe + tagindex * 12, sizeof(float[12]));
410                 while (model->data_bones[tagindex].parent >= 0)
411                 {
412                         memcpy(tempbonematrix, bonematrix, sizeof(float[12]));
413                         R_ConcatTransforms(boneframe + model->data_bones[tagindex].parent * 12, tempbonematrix, bonematrix);
414                         tagindex = model->data_bones[tagindex].parent;
415                 }
416                 Matrix4x4_FromArray12FloatD3D(outmatrix, bonematrix);
417         }
418         else if (model->num_tags)
419         {
420                 if (tagindex < 0 || tagindex >= model->num_tags)
421                         return 4;
422                 if (poseframe >= model->num_tagframes)
423                         return 6;
424                 Matrix4x4_FromArray12FloatGL(outmatrix, model->data_tags[poseframe * model->num_tags + tagindex].matrixgl);
425         }
426         return 0;
427 }
428
429 int Mod_Alias_GetTagIndexForName(const dp_model_t *model, unsigned int skin, const char *tagname)
430 {
431         int i;
432         if(skin >= (unsigned int)model->numskins)
433                 skin = 0;
434         if (model->num_bones)
435                 for (i = 0;i < model->num_bones;i++)
436                         if (!strcasecmp(tagname, model->data_bones[i].name))
437                                 return i + 1;
438         if (model->num_tags)
439                 for (i = 0;i < model->num_tags;i++)
440                         if (!strcasecmp(tagname, model->data_tags[i].name))
441                                 return i + 1;
442         return 0;
443 }
444
445 static void Mod_BuildBaseBonePoses(void)
446 {
447         int i, k;
448         double scale;
449         float *basebonepose = Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(float[12]));
450         float *in12f = loadmodel->data_poses;
451         float *out12f = basebonepose;
452         float *outinv12f = loadmodel->data_baseboneposeinverse;
453         for (i = 0;i < loadmodel->num_bones;i++, in12f += 12, out12f += 12, outinv12f += 12)
454         {
455                 if (loadmodel->data_bones[i].parent >= 0)
456                         R_ConcatTransforms(basebonepose + 12 * loadmodel->data_bones[i].parent, in12f, out12f);
457                 else
458                         for (k = 0;k < 12;k++)
459                                 out12f[k] = in12f[k];
460
461                 // invert The Matrix
462
463                 // we only support uniform scaling, so assume the first row is enough
464                 // (note the lack of sqrt here, because we're trying to undo the scaling,
465                 // this means multiplying by the inverse scale twice - squaring it, which
466                 // makes the sqrt a waste of time)
467                 scale = 1.0 / (out12f[ 0] * out12f[ 0] + out12f[ 1] * out12f[ 1] + out12f[ 2] * out12f[ 2]);
468
469                 // invert the rotation by transposing and multiplying by the squared
470                 // recipricol of the input matrix scale as described above
471                 outinv12f[ 0] = (float)(out12f[ 0] * scale);
472                 outinv12f[ 1] = (float)(out12f[ 4] * scale);
473                 outinv12f[ 2] = (float)(out12f[ 8] * scale);
474                 outinv12f[ 4] = (float)(out12f[ 1] * scale);
475                 outinv12f[ 5] = (float)(out12f[ 5] * scale);
476                 outinv12f[ 6] = (float)(out12f[ 9] * scale);
477                 outinv12f[ 8] = (float)(out12f[ 2] * scale);
478                 outinv12f[ 9] = (float)(out12f[ 6] * scale);
479                 outinv12f[10] = (float)(out12f[10] * scale);
480
481                 // invert the translate
482                 outinv12f[ 3] = -(out12f[ 3] * outinv12f[ 0] + out12f[ 7] * outinv12f[ 1] + out12f[11] * outinv12f[ 2]);
483                 outinv12f[ 7] = -(out12f[ 3] * outinv12f[ 4] + out12f[ 7] * outinv12f[ 5] + out12f[11] * outinv12f[ 6]);
484                 outinv12f[11] = -(out12f[ 3] * outinv12f[ 8] + out12f[ 7] * outinv12f[ 9] + out12f[11] * outinv12f[10]);
485         }
486         Mem_Free(basebonepose);
487 }
488
489 static void Mod_Alias_CalculateBoundingBox(void)
490 {
491         int vnum;
492         qboolean firstvertex = true;
493         float dist, yawradius, radius;
494         float *v;
495         float *vertex3f;
496         frameblend_t frameblend[4];
497         memset(frameblend, 0, sizeof(frameblend));
498         frameblend[0].lerp = 1;
499         vertex3f = Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
500         VectorClear(loadmodel->normalmins);
501         VectorClear(loadmodel->normalmaxs);
502         yawradius = 0;
503         radius = 0;
504         for (frameblend[0].frame = 0;frameblend[0].frame < loadmodel->num_poses;frameblend[0].frame++)
505         {
506                 loadmodel->AnimateVertices(loadmodel, frameblend, vertex3f, NULL, NULL, NULL);
507                 for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
508                 {
509                         if (firstvertex)
510                         {
511                                 firstvertex = false;
512                                 VectorCopy(v, loadmodel->normalmins);
513                                 VectorCopy(v, loadmodel->normalmaxs);
514                         }
515                         else
516                         {
517                                 if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
518                                 if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
519                                 if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
520                                 if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
521                                 if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
522                                 if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
523                         }
524                         dist = v[0] * v[0] + v[1] * v[1];
525                         if (yawradius < dist)
526                                 yawradius = dist;
527                         dist += v[2] * v[2];
528                         if (radius < dist)
529                                 radius = dist;
530                 }
531         }
532         Mem_Free(vertex3f);
533         radius = sqrt(radius);
534         yawradius = sqrt(yawradius);
535         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
536         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius;
537         loadmodel->yawmins[2] = loadmodel->normalmins[2];
538         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
539         loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
540         loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
541         loadmodel->radius = radius;
542         loadmodel->radius2 = radius * radius;
543 }
544
545 static void Mod_Alias_MorphMesh_CompileFrames(void)
546 {
547         int i, j;
548         frameblend_t frameblend[4] = {{0, 1}, {0, 0}, {0, 0}, {0, 0}};
549         unsigned char *datapointer;
550         datapointer = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * (sizeof(float[3]) * 4 + loadmodel->surfmesh.num_morphframes * sizeof(texvecvertex_t)));
551         loadmodel->surfmesh.data_vertex3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
552         loadmodel->surfmesh.data_svector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
553         loadmodel->surfmesh.data_tvector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
554         loadmodel->surfmesh.data_normal3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
555         loadmodel->surfmesh.data_morphtexvecvertex = (texvecvertex_t *)datapointer;datapointer += loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices * sizeof(texvecvertex_t);
556         // 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)
557         for (i = loadmodel->surfmesh.num_morphframes-1;i >= 0;i--)
558         {
559                 frameblend[0].frame = i;
560                 loadmodel->AnimateVertices(loadmodel, frameblend, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL);
561                 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);
562                 // encode the svector and tvector in 3 byte format for permanent storage
563                 for (j = 0;j < loadmodel->surfmesh.num_vertices;j++)
564                 {
565                         VectorScale(loadmodel->surfmesh.data_svector3f + j * 3, 127.0f, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].svec);
566                         VectorScale(loadmodel->surfmesh.data_tvector3f + j * 3, 127.0f, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].tvec);
567                 }
568         }
569 }
570
571 static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, int frame, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask)
572 {
573         int i;
574         float segmentmins[3], segmentmaxs[3];
575         frameblend_t frameblend[4];
576         msurface_t *surface;
577         static int maxvertices = 0;
578         static float *vertex3f = NULL;
579         memset(trace, 0, sizeof(*trace));
580         trace->fraction = 1;
581         trace->realfraction = 1;
582         trace->hitsupercontentsmask = hitsupercontentsmask;
583         memset(frameblend, 0, sizeof(frameblend));
584         frameblend[0].frame = frame;
585         frameblend[0].lerp = 1;
586         if (maxvertices < model->surfmesh.num_vertices)
587         {
588                 if (vertex3f)
589                         Z_Free(vertex3f);
590                 maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
591                 vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3]));
592         }
593         if (VectorLength2(boxmins) + VectorLength2(boxmaxs) == 0)
594         {
595                 // line trace
596                 segmentmins[0] = min(start[0], end[0]) - 1;
597                 segmentmins[1] = min(start[1], end[1]) - 1;
598                 segmentmins[2] = min(start[2], end[2]) - 1;
599                 segmentmaxs[0] = max(start[0], end[0]) + 1;
600                 segmentmaxs[1] = max(start[1], end[1]) + 1;
601                 segmentmaxs[2] = max(start[2], end[2]) + 1;
602                 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
603                 {
604                         model->AnimateVertices(model, frameblend, vertex3f, NULL, NULL, NULL);
605                         Collision_TraceLineTriangleMeshFloat(trace, start, end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, SUPERCONTENTS_SOLID, 0, surface->texture, segmentmins, segmentmaxs);
606                 }
607         }
608         else
609         {
610                 // box trace, performed as brush trace
611                 colbrushf_t *thisbrush_start, *thisbrush_end;
612                 vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
613                 segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
614                 segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
615                 segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
616                 segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
617                 segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
618                 segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
619                 VectorAdd(start, boxmins, boxstartmins);
620                 VectorAdd(start, boxmaxs, boxstartmaxs);
621                 VectorAdd(end, boxmins, boxendmins);
622                 VectorAdd(end, boxmaxs, boxendmaxs);
623                 thisbrush_start = Collision_BrushForBox(&identitymatrix, boxstartmins, boxstartmaxs, 0, 0, NULL);
624                 thisbrush_end = Collision_BrushForBox(&identitymatrix, boxendmins, boxendmaxs, 0, 0, NULL);
625                 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
626                 {
627                         if (maxvertices < model->surfmesh.num_vertices)
628                         {
629                                 if (vertex3f)
630                                         Z_Free(vertex3f);
631                                 maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
632                                 vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3]));
633                         }
634                         model->AnimateVertices(model, frameblend, vertex3f, NULL, NULL, NULL);
635                         Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, SUPERCONTENTS_SOLID, 0, surface->texture, segmentmins, segmentmaxs);
636                 }
637         }
638 }
639
640 static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
641 {
642         int i, j;
643         for (i = 0;i < inverts;i++)
644         {
645                 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
646                         continue;
647                 j = vertremap[i]; // not onseam
648                 if (j >= 0)
649                         out[j] = v[i];
650                 j = vertremap[i+inverts]; // onseam
651                 if (j >= 0)
652                         out[j] = v[i];
653         }
654 }
655
656 static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
657 {
658         int i, f, pose, groupframes;
659         float interval;
660         daliasframetype_t *pframetype;
661         daliasframe_t *pinframe;
662         daliasgroup_t *group;
663         daliasinterval_t *intervals;
664         animscene_t *scene;
665         pose = 0;
666         scene = loadmodel->animscenes;
667         for (f = 0;f < loadmodel->numframes;f++)
668         {
669                 pframetype = (daliasframetype_t *)datapointer;
670                 datapointer += sizeof(daliasframetype_t);
671                 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
672                 {
673                         // a single frame is still treated as a group
674                         interval = 0.1f;
675                         groupframes = 1;
676                 }
677                 else
678                 {
679                         // read group header
680                         group = (daliasgroup_t *)datapointer;
681                         datapointer += sizeof(daliasgroup_t);
682                         groupframes = LittleLong (group->numframes);
683
684                         // intervals (time per frame)
685                         intervals = (daliasinterval_t *)datapointer;
686                         datapointer += sizeof(daliasinterval_t) * groupframes;
687
688                         interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
689                         if (interval < 0.01f)
690                         {
691                                 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
692                                 interval = 0.1f;
693                         }
694                 }
695
696                 // get scene name from first frame
697                 pinframe = (daliasframe_t *)datapointer;
698
699                 strlcpy(scene->name, pinframe->name, sizeof(scene->name));
700                 scene->firstframe = pose;
701                 scene->framecount = groupframes;
702                 scene->framerate = 1.0f / interval;
703                 scene->loop = true;
704                 scene++;
705
706                 // read frames
707                 for (i = 0;i < groupframes;i++)
708                 {
709                         pinframe = (daliasframe_t *)datapointer;
710                         datapointer += sizeof(daliasframe_t);
711                         Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
712                         datapointer += sizeof(trivertx_t) * inverts;
713                         pose++;
714                 }
715         }
716 }
717
718 static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *skinframe)
719 {
720         if (cls.state == ca_dedicated)
721                 return;
722         // hack
723         if (!skinframe)
724                 skinframe = R_SkinFrame_LoadMissing();
725         memset(texture, 0, sizeof(*texture));
726         texture->currentframe = texture;
727         //texture->animated = false;
728         texture->numskinframes = 1;
729         texture->skinframerate = 1;
730         texture->skinframes[0] = skinframe;
731         texture->currentskinframe = skinframe;
732         //texture->backgroundnumskinframes = 0;
733         //texture->customblendfunc[0] = 0;
734         //texture->customblendfunc[1] = 0;
735         //texture->surfaceflags = 0;
736         //texture->supercontents = 0;
737         //texture->surfaceparms = 0;
738         //texture->textureflags = 0;
739
740         texture->basematerialflags = MATERIALFLAG_WALL;
741         if (texture->currentskinframe->fog)
742                 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
743         texture->currentmaterialflags = texture->basematerialflags;
744 }
745
746 static void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, char *meshname, char *shadername)
747 {
748         int i;
749         skinfileitem_t *skinfileitem;
750         if (skinfile)
751         {
752                 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
753                 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
754                 {
755                         memset(skin, 0, sizeof(*skin));
756                         // see if a mesh
757                         for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
758                         {
759                                 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
760                                 if (!strcmp(skinfileitem->name, meshname))
761                                 {
762                                         Mod_LoadTextureFromQ3Shader(skin, skinfileitem->replacement, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP | TEXF_COMPRESS);
763                                         break;
764                                 }
765                         }
766                         if (!skinfileitem)
767                         {
768                                 // don't render unmentioned meshes
769                                 Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
770                                 skin->basematerialflags = skin->currentmaterialflags = 0;
771                         }
772                 }
773         }
774         else
775                 Mod_LoadTextureFromQ3Shader(skin, shadername, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP | TEXF_COMPRESS);
776 }
777
778 #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);
779 #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);
780 void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
781 {
782         int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
783         float scales, scalet, interval;
784         msurface_t *surface;
785         unsigned char *data;
786         mdl_t *pinmodel;
787         stvert_t *pinstverts;
788         dtriangle_t *pintriangles;
789         daliasskintype_t *pinskintype;
790         daliasskingroup_t *pinskingroup;
791         daliasskininterval_t *pinskinintervals;
792         daliasframetype_t *pinframetype;
793         daliasgroup_t *pinframegroup;
794         unsigned char *datapointer, *startframes, *startskins;
795         char name[MAX_QPATH];
796         skinframe_t *tempskinframe;
797         animscene_t *tempskinscenes;
798         texture_t *tempaliasskins;
799         float *vertst;
800         int *vertonseam, *vertremap;
801         skinfile_t *skinfiles;
802
803         datapointer = (unsigned char *)buffer;
804         pinmodel = (mdl_t *)datapointer;
805         datapointer += sizeof(mdl_t);
806
807         version = LittleLong (pinmodel->version);
808         if (version != ALIAS_VERSION)
809                 Host_Error ("%s has wrong version number (%i should be %i)",
810                                  loadmodel->name, version, ALIAS_VERSION);
811
812         loadmodel->modeldatatypestring = "MDL";
813
814         loadmodel->type = mod_alias;
815         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
816         loadmodel->DrawSky = NULL;
817         loadmodel->DrawAddWaterPlanes = NULL;
818         loadmodel->Draw = R_Q1BSP_Draw;
819         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
820         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
821         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
822         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
823         loadmodel->DrawLight = R_Q1BSP_DrawLight;
824         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
825         loadmodel->PointSuperContents = NULL;
826
827         loadmodel->num_surfaces = 1;
828         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
829         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
830         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
831         loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
832         loadmodel->surfacelist[0] = 0;
833
834         loadmodel->numskins = LittleLong(pinmodel->numskins);
835         BOUNDI(loadmodel->numskins,0,65536);
836         skinwidth = LittleLong (pinmodel->skinwidth);
837         BOUNDI(skinwidth,0,65536);
838         skinheight = LittleLong (pinmodel->skinheight);
839         BOUNDI(skinheight,0,65536);
840         numverts = LittleLong(pinmodel->numverts);
841         BOUNDI(numverts,0,65536);
842         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
843         BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
844         loadmodel->numframes = LittleLong(pinmodel->numframes);
845         BOUNDI(loadmodel->numframes,0,65536);
846         loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
847         BOUNDI(loadmodel->synctype,0,2);
848         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
849         i = LittleLong (pinmodel->flags);
850         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
851
852         for (i = 0;i < 3;i++)
853         {
854                 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
855                 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
856         }
857
858         startskins = datapointer;
859         totalskins = 0;
860         for (i = 0;i < loadmodel->numskins;i++)
861         {
862                 pinskintype = (daliasskintype_t *)datapointer;
863                 datapointer += sizeof(daliasskintype_t);
864                 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
865                         groupskins = 1;
866                 else
867                 {
868                         pinskingroup = (daliasskingroup_t *)datapointer;
869                         datapointer += sizeof(daliasskingroup_t);
870                         groupskins = LittleLong(pinskingroup->numskins);
871                         datapointer += sizeof(daliasskininterval_t) * groupskins;
872                 }
873
874                 for (j = 0;j < groupskins;j++)
875                 {
876                         datapointer += skinwidth * skinheight;
877                         totalskins++;
878                 }
879         }
880
881         pinstverts = (stvert_t *)datapointer;
882         datapointer += sizeof(stvert_t) * numverts;
883
884         pintriangles = (dtriangle_t *)datapointer;
885         datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
886
887         startframes = datapointer;
888         loadmodel->surfmesh.num_morphframes = 0;
889         for (i = 0;i < loadmodel->numframes;i++)
890         {
891                 pinframetype = (daliasframetype_t *)datapointer;
892                 datapointer += sizeof(daliasframetype_t);
893                 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
894                         groupframes = 1;
895                 else
896                 {
897                         pinframegroup = (daliasgroup_t *)datapointer;
898                         datapointer += sizeof(daliasgroup_t);
899                         groupframes = LittleLong(pinframegroup->numframes);
900                         datapointer += sizeof(daliasinterval_t) * groupframes;
901                 }
902
903                 for (j = 0;j < groupframes;j++)
904                 {
905                         datapointer += sizeof(daliasframe_t);
906                         datapointer += sizeof(trivertx_t) * numverts;
907                         loadmodel->surfmesh.num_morphframes++;
908                 }
909         }
910         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
911
912         // store texture coordinates into temporary array, they will be stored
913         // after usage is determined (triangle data)
914         vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
915         vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
916         vertonseam = vertremap + numverts * 2;
917
918         scales = 1.0 / skinwidth;
919         scalet = 1.0 / skinheight;
920         for (i = 0;i < numverts;i++)
921         {
922                 vertonseam[i] = LittleLong(pinstverts[i].onseam);
923                 vertst[i*2+0] = (LittleLong(pinstverts[i].s) + 0.5) * scales;
924                 vertst[i*2+1] = (LittleLong(pinstverts[i].t) + 0.5) * scalet;
925                 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
926                 vertst[(i+numverts)*2+1] = vertst[i*2+1];
927         }
928
929 // load triangle data
930         loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
931
932         // read the triangle elements
933         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
934                 for (j = 0;j < 3;j++)
935                         loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
936         // validate (note numverts is used because this is the original data)
937         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
938         // now butcher the elements according to vertonseam and tri->facesfront
939         // and then compact the vertex set to remove duplicates
940         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
941                 if (!LittleLong(pintriangles[i].facesfront)) // backface
942                         for (j = 0;j < 3;j++)
943                                 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
944                                         loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
945         // count the usage
946         // (this uses vertremap to count usage to save some memory)
947         for (i = 0;i < numverts*2;i++)
948                 vertremap[i] = 0;
949         for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
950                 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
951         // build remapping table and compact array
952         loadmodel->surfmesh.num_vertices = 0;
953         for (i = 0;i < numverts*2;i++)
954         {
955                 if (vertremap[i])
956                 {
957                         vertremap[i] = loadmodel->surfmesh.num_vertices;
958                         vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
959                         vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
960                         loadmodel->surfmesh.num_vertices++;
961                 }
962                 else
963                         vertremap[i] = -1; // not used at all
964         }
965         // remap the elements to the new vertex set
966         for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
967                 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
968         // store the texture coordinates
969         loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
970         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
971         {
972                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
973                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
974         }
975
976         // generate ushort elements array if possible
977         if (loadmodel->surfmesh.num_vertices <= 65536)
978         {
979                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
980                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
981                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
982         }
983
984 // load the frames
985         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
986         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
987         loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
988         Mod_MDL_LoadFrames (startframes, numverts, vertremap);
989         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
990         Mod_Alias_CalculateBoundingBox();
991         Mod_Alias_MorphMesh_CompileFrames();
992
993         Mem_Free(vertst);
994         Mem_Free(vertremap);
995
996         // load the skins
997         skinfiles = Mod_LoadSkinFiles();
998         if (skinfiles)
999         {
1000                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1001                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1002                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1003                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1004                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1005                 Mod_FreeSkinFiles(skinfiles);
1006                 for (i = 0;i < loadmodel->numskins;i++)
1007                 {
1008                         loadmodel->skinscenes[i].firstframe = i;
1009                         loadmodel->skinscenes[i].framecount = 1;
1010                         loadmodel->skinscenes[i].loop = true;
1011                         loadmodel->skinscenes[i].framerate = 10;
1012                 }
1013         }
1014         else
1015         {
1016                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1017                 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1018                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1019                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1020                 totalskins = 0;
1021                 datapointer = startskins;
1022                 for (i = 0;i < loadmodel->numskins;i++)
1023                 {
1024                         pinskintype = (daliasskintype_t *)datapointer;
1025                         datapointer += sizeof(daliasskintype_t);
1026
1027                         if (pinskintype->type == ALIAS_SKIN_SINGLE)
1028                         {
1029                                 groupskins = 1;
1030                                 interval = 0.1f;
1031                         }
1032                         else
1033                         {
1034                                 pinskingroup = (daliasskingroup_t *)datapointer;
1035                                 datapointer += sizeof(daliasskingroup_t);
1036
1037                                 groupskins = LittleLong (pinskingroup->numskins);
1038
1039                                 pinskinintervals = (daliasskininterval_t *)datapointer;
1040                                 datapointer += sizeof(daliasskininterval_t) * groupskins;
1041
1042                                 interval = LittleFloat(pinskinintervals[0].interval);
1043                                 if (interval < 0.01f)
1044                                 {
1045                                         Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1046                                         interval = 0.1f;
1047                                 }
1048                         }
1049
1050                         dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1051                         loadmodel->skinscenes[i].firstframe = totalskins;
1052                         loadmodel->skinscenes[i].framecount = groupskins;
1053                         loadmodel->skinscenes[i].framerate = 1.0f / interval;
1054                         loadmodel->skinscenes[i].loop = true;
1055
1056                         for (j = 0;j < groupskins;j++)
1057                         {
1058                                 if (groupskins > 1)
1059                                         dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1060                                 else
1061                                         dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1062                                 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))
1063                                         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));
1064                                 datapointer += skinwidth * skinheight;
1065                                 totalskins++;
1066                         }
1067                 }
1068                 // check for skins that don't exist in the model, but do exist as external images
1069                 // (this was added because yummyluv kept pestering me about support for it)
1070                 // TODO: support shaders here?
1071                 while ((tempskinframe = R_SkinFrame_LoadExternal(va("%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false)))
1072                 {
1073                         // expand the arrays to make room
1074                         tempskinscenes = loadmodel->skinscenes;
1075                         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1076                         memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1077                         Mem_Free(tempskinscenes);
1078
1079                         tempaliasskins = loadmodel->data_textures;
1080                         loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1081                         memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1082                         Mem_Free(tempaliasskins);
1083
1084                         // store the info about the new skin
1085                         Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
1086                         strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1087                         loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1088                         loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1089                         loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1090                         loadmodel->skinscenes[loadmodel->numskins].loop = true;
1091
1092                         //increase skin counts
1093                         loadmodel->numskins++;
1094                         totalskins++;
1095
1096                         // fix up the pointers since they are pointing at the old textures array
1097                         // FIXME: this is a hack!
1098                         for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1099                                 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1100                 }
1101         }
1102
1103         surface = loadmodel->data_surfaces;
1104         surface->texture = loadmodel->data_textures;
1105         surface->num_firsttriangle = 0;
1106         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1107         surface->num_firstvertex = 0;
1108         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1109
1110         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1111 }
1112
1113 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1114 {
1115         int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1116         float iskinwidth, iskinheight;
1117         unsigned char *data;
1118         msurface_t *surface;
1119         md2_t *pinmodel;
1120         unsigned char *base, *datapointer;
1121         md2frame_t *pinframe;
1122         char *inskin;
1123         md2triangle_t *intri;
1124         unsigned short *inst;
1125         struct md2verthash_s
1126         {
1127                 struct md2verthash_s *next;
1128                 unsigned short xyz;
1129                 unsigned short st;
1130         }
1131         *hash, **md2verthash, *md2verthashdata;
1132         skinfile_t *skinfiles;
1133
1134         pinmodel = (md2_t *)buffer;
1135         base = (unsigned char *)buffer;
1136
1137         version = LittleLong (pinmodel->version);
1138         if (version != MD2ALIAS_VERSION)
1139                 Host_Error ("%s has wrong version number (%i should be %i)",
1140                         loadmodel->name, version, MD2ALIAS_VERSION);
1141
1142         loadmodel->modeldatatypestring = "MD2";
1143
1144         loadmodel->type = mod_alias;
1145         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1146         loadmodel->DrawSky = NULL;
1147         loadmodel->DrawAddWaterPlanes = NULL;
1148         loadmodel->Draw = R_Q1BSP_Draw;
1149         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1150         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1151         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1152         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1153         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1154         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1155         loadmodel->PointSuperContents = NULL;
1156
1157         if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1158                 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1159         if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1160                 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1161         if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1162                 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1163         if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1164                 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1165
1166         end = LittleLong(pinmodel->ofs_end);
1167         if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1168                 Host_Error ("%s is not a valid model", loadmodel->name);
1169         if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1170                 Host_Error ("%s is not a valid model", loadmodel->name);
1171         if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1172                 Host_Error ("%s is not a valid model", loadmodel->name);
1173         if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1174                 Host_Error ("%s is not a valid model", loadmodel->name);
1175         if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1176                 Host_Error ("%s is not a valid model", loadmodel->name);
1177
1178         loadmodel->numskins = LittleLong(pinmodel->num_skins);
1179         numxyz = LittleLong(pinmodel->num_xyz);
1180         numst = LittleLong(pinmodel->num_st);
1181         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1182         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1183         loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1184         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1185         skinwidth = LittleLong(pinmodel->skinwidth);
1186         skinheight = LittleLong(pinmodel->skinheight);
1187         iskinwidth = 1.0f / skinwidth;
1188         iskinheight = 1.0f / skinheight;
1189
1190         loadmodel->num_surfaces = 1;
1191         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1192         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]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1193         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1194         loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1195         loadmodel->surfacelist[0] = 0;
1196         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1197         loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1198         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1199         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1200
1201         loadmodel->synctype = ST_RAND;
1202
1203         // load the skins
1204         inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1205         skinfiles = Mod_LoadSkinFiles();
1206         if (skinfiles)
1207         {
1208                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1209                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1210                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1211                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1212                 Mod_FreeSkinFiles(skinfiles);
1213         }
1214         else if (loadmodel->numskins)
1215         {
1216                 // skins found (most likely not a player model)
1217                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1218                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1219                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1220                 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1221                         Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP | TEXF_COMPRESS);
1222         }
1223         else
1224         {
1225                 // no skins (most likely a player model)
1226                 loadmodel->numskins = 1;
1227                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1228                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1229                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1230                 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL);
1231         }
1232
1233         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1234         for (i = 0;i < loadmodel->numskins;i++)
1235         {
1236                 loadmodel->skinscenes[i].firstframe = i;
1237                 loadmodel->skinscenes[i].framecount = 1;
1238                 loadmodel->skinscenes[i].loop = true;
1239                 loadmodel->skinscenes[i].framerate = 10;
1240         }
1241
1242         // load the triangles and stvert data
1243         inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1244         intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1245         md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1246         md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1247         // swap the triangle list
1248         loadmodel->surfmesh.num_vertices = 0;
1249         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1250         {
1251                 for (j = 0;j < 3;j++)
1252                 {
1253                         xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1254                         st = (unsigned short) LittleShort (intri[i].index_st[j]);
1255                         if (xyz >= numxyz)
1256                         {
1257                                 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1258                                 xyz = 0;
1259                         }
1260                         if (st >= numst)
1261                         {
1262                                 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1263                                 st = 0;
1264                         }
1265                         hashindex = (xyz * 256 + st) & 65535;
1266                         for (hash = md2verthash[hashindex];hash;hash = hash->next)
1267                                 if (hash->xyz == xyz && hash->st == st)
1268                                         break;
1269                         if (hash == NULL)
1270                         {
1271                                 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1272                                 hash->xyz = xyz;
1273                                 hash->st = st;
1274                                 hash->next = md2verthash[hashindex];
1275                                 md2verthash[hashindex] = hash;
1276                         }
1277                         loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1278                 }
1279         }
1280
1281         vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1282         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));
1283         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1284         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1285         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1286         {
1287                 int sts, stt;
1288                 hash = md2verthashdata + i;
1289                 vertremap[i] = hash->xyz;
1290                 sts = LittleShort(inst[hash->st*2+0]);
1291                 stt = LittleShort(inst[hash->st*2+1]);
1292                 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1293                 {
1294                         Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1295                         sts = 0;
1296                         stt = 0;
1297                 }
1298                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1299                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1300         }
1301
1302         Mem_Free(md2verthash);
1303         Mem_Free(md2verthashdata);
1304
1305         // generate ushort elements array if possible
1306         if (loadmodel->surfmesh.num_vertices <= 65536)
1307         {
1308                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1309                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1310                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1311         }
1312
1313         // load the frames
1314         datapointer = (base + LittleLong(pinmodel->ofs_frames));
1315         for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1316         {
1317                 int k;
1318                 trivertx_t *v;
1319                 trivertx_t *out;
1320                 pinframe = (md2frame_t *)datapointer;
1321                 datapointer += sizeof(md2frame_t);
1322                 // store the frame scale/translate into the appropriate array
1323                 for (j = 0;j < 3;j++)
1324                 {
1325                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1326                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1327                 }
1328                 // convert the vertices
1329                 v = (trivertx_t *)datapointer;
1330                 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1331                 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1332                         out[k] = v[vertremap[k]];
1333                 datapointer += numxyz * sizeof(trivertx_t);
1334
1335                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1336                 loadmodel->animscenes[i].firstframe = i;
1337                 loadmodel->animscenes[i].framecount = 1;
1338                 loadmodel->animscenes[i].framerate = 10;
1339                 loadmodel->animscenes[i].loop = true;
1340         }
1341
1342         Mem_Free(vertremap);
1343
1344         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1345         Mod_Alias_CalculateBoundingBox();
1346         Mod_Alias_MorphMesh_CompileFrames();
1347
1348         surface = loadmodel->data_surfaces;
1349         surface->texture = loadmodel->data_textures;
1350         surface->num_firsttriangle = 0;
1351         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1352         surface->num_firstvertex = 0;
1353         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1354
1355         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1356 }
1357
1358 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1359 {
1360         int i, j, k, version, meshvertices, meshtriangles;
1361         unsigned char *data;
1362         msurface_t *surface;
1363         md3modelheader_t *pinmodel;
1364         md3frameinfo_t *pinframe;
1365         md3mesh_t *pinmesh;
1366         md3tag_t *pintag;
1367         skinfile_t *skinfiles;
1368
1369         pinmodel = (md3modelheader_t *)buffer;
1370
1371         if (memcmp(pinmodel->identifier, "IDP3", 4))
1372                 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1373         version = LittleLong (pinmodel->version);
1374         if (version != MD3VERSION)
1375                 Host_Error ("%s has wrong version number (%i should be %i)",
1376                         loadmodel->name, version, MD3VERSION);
1377
1378         skinfiles = Mod_LoadSkinFiles();
1379         if (loadmodel->numskins < 1)
1380                 loadmodel->numskins = 1;
1381
1382         loadmodel->modeldatatypestring = "MD3";
1383
1384         loadmodel->type = mod_alias;
1385         loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1386         loadmodel->DrawSky = NULL;
1387         loadmodel->DrawAddWaterPlanes = NULL;
1388         loadmodel->Draw = R_Q1BSP_Draw;
1389         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1390         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1391         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1392         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1393         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1394         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1395         loadmodel->PointSuperContents = NULL;
1396         loadmodel->synctype = ST_RAND;
1397         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1398         i = LittleLong (pinmodel->flags);
1399         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1400
1401         // set up some global info about the model
1402         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1403         loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1404
1405         // make skinscenes for the skins (no groups)
1406         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1407         for (i = 0;i < loadmodel->numskins;i++)
1408         {
1409                 loadmodel->skinscenes[i].firstframe = i;
1410                 loadmodel->skinscenes[i].framecount = 1;
1411                 loadmodel->skinscenes[i].loop = true;
1412                 loadmodel->skinscenes[i].framerate = 10;
1413         }
1414
1415         // load frameinfo
1416         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1417         for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1418         {
1419                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1420                 loadmodel->animscenes[i].firstframe = i;
1421                 loadmodel->animscenes[i].framecount = 1;
1422                 loadmodel->animscenes[i].framerate = 10;
1423                 loadmodel->animscenes[i].loop = true;
1424         }
1425
1426         // load tags
1427         loadmodel->num_tagframes = loadmodel->numframes;
1428         loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1429         loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1430         for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1431         {
1432                 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1433                 for (j = 0;j < 9;j++)
1434                         loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1435                 for (j = 0;j < 3;j++)
1436                         loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1437                 //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);
1438         }
1439
1440         // load meshes
1441         meshvertices = 0;
1442         meshtriangles = 0;
1443         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)))
1444         {
1445                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1446                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1447                 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1448                         Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1449                 meshvertices += LittleLong(pinmesh->num_vertices);
1450                 meshtriangles += LittleLong(pinmesh->num_triangles);
1451         }
1452
1453         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1454         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1455         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1456         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]) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[2]) + meshvertices * loadmodel->numframes * sizeof(md3vertex_t));
1457         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1458         loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1459         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1460         loadmodel->surfmesh.num_vertices = meshvertices;
1461         loadmodel->surfmesh.num_triangles = meshtriangles;
1462         loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1463         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1464         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1465         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1466         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1467         loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1468         if (meshvertices <= 65536)
1469         {
1470                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1471                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1472                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1473         }
1474
1475         meshvertices = 0;
1476         meshtriangles = 0;
1477         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)))
1478         {
1479                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1480                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1481                 loadmodel->surfacelist[i] = i;
1482                 surface = loadmodel->data_surfaces + i;
1483                 surface->texture = loadmodel->data_textures + i;
1484                 surface->num_firsttriangle = meshtriangles;
1485                 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1486                 surface->num_firstvertex = meshvertices;
1487                 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1488                 meshvertices += surface->num_vertices;
1489                 meshtriangles += surface->num_triangles;
1490
1491                 for (j = 0;j < surface->num_triangles * 3;j++)
1492                         loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1493                 for (j = 0;j < surface->num_vertices;j++)
1494                 {
1495                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1496                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1497                 }
1498                 for (j = 0;j < loadmodel->numframes;j++)
1499                 {
1500                         const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1501                         md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1502                         for (k = 0;k < surface->num_vertices;k++, in++, out++)
1503                         {
1504                                 out->origin[0] = LittleShort(in->origin[0]);
1505                                 out->origin[1] = LittleShort(in->origin[1]);
1506                                 out->origin[2] = LittleShort(in->origin[2]);
1507                                 out->pitch = in->pitch;
1508                                 out->yaw = in->yaw;
1509                         }
1510                 }
1511
1512                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1513
1514                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1515         }
1516         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1517         Mod_Alias_MorphMesh_CompileFrames();
1518         Mod_Alias_CalculateBoundingBox();
1519         Mod_FreeSkinFiles(skinfiles);
1520
1521         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1
1522              || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
1523 }
1524
1525 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1526 {
1527         zymtype1header_t *pinmodel, *pheader;
1528         unsigned char *pbase;
1529         int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1530         float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose;
1531         zymvertex_t *verts, *vertdata;
1532         zymscene_t *scene;
1533         zymbone_t *bone;
1534         char *shadername;
1535         skinfile_t *skinfiles;
1536         unsigned char *data;
1537         msurface_t *surface;
1538
1539         pinmodel = (zymtype1header_t *)buffer;
1540         pbase = (unsigned char *)buffer;
1541         if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1542                 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1543         if (BigLong(pinmodel->type) != 1)
1544                 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1545
1546         loadmodel->modeldatatypestring = "ZYM";
1547
1548         loadmodel->type = mod_alias;
1549         loadmodel->synctype = ST_RAND;
1550
1551         // byteswap header
1552         pheader = pinmodel;
1553         pheader->type = BigLong(pinmodel->type);
1554         pheader->filesize = BigLong(pinmodel->filesize);
1555         pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1556         pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1557         pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1558         pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1559         pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1560         pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1561         pheader->radius = BigFloat(pinmodel->radius);
1562         pheader->numverts = BigLong(pinmodel->numverts);
1563         pheader->numtris = BigLong(pinmodel->numtris);
1564         pheader->numshaders = BigLong(pinmodel->numshaders);
1565         pheader->numbones = BigLong(pinmodel->numbones);
1566         pheader->numscenes = BigLong(pinmodel->numscenes);
1567         pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1568         pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1569         pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1570         pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1571         pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1572         pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1573         pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1574         pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1575         pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1576         pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1577         pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1578         pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1579         pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1580         pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1581         pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1582         pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1583         pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1584         pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1585
1586         if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1587         {
1588                 Con_Printf("%s has no geometry\n", loadmodel->name);
1589                 return;
1590         }
1591         if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1592         {
1593                 Con_Printf("%s has no animations\n", loadmodel->name);
1594                 return;
1595         }
1596
1597         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1598         loadmodel->DrawSky = NULL;
1599         loadmodel->DrawAddWaterPlanes = NULL;
1600         loadmodel->Draw = R_Q1BSP_Draw;
1601         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1602         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1603         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1604         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1605         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1606         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1607         loadmodel->PointSuperContents = NULL;
1608
1609         loadmodel->numframes = pheader->numscenes;
1610         loadmodel->num_surfaces = pheader->numshaders;
1611
1612         skinfiles = Mod_LoadSkinFiles();
1613         if (loadmodel->numskins < 1)
1614                 loadmodel->numskins = 1;
1615
1616         // make skinscenes for the skins (no groups)
1617         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1618         for (i = 0;i < loadmodel->numskins;i++)
1619         {
1620                 loadmodel->skinscenes[i].firstframe = i;
1621                 loadmodel->skinscenes[i].framecount = 1;
1622                 loadmodel->skinscenes[i].loop = true;
1623                 loadmodel->skinscenes[i].framerate = 10;
1624         }
1625
1626         // model bbox
1627         modelradius = pheader->radius;
1628         for (i = 0;i < 3;i++)
1629         {
1630                 loadmodel->normalmins[i] = pheader->mins[i];
1631                 loadmodel->normalmaxs[i] = pheader->maxs[i];
1632                 loadmodel->rotatedmins[i] = -modelradius;
1633                 loadmodel->rotatedmaxs[i] = modelradius;
1634         }
1635         corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1636         corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1637         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1638         if (loadmodel->yawmaxs[0] > modelradius)
1639                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1640         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1641         loadmodel->yawmins[2] = loadmodel->normalmins[2];
1642         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1643         loadmodel->radius = modelradius;
1644         loadmodel->radius2 = modelradius * modelradius;
1645
1646         // go through the lumps, swapping things
1647
1648         //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1649         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1650         scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1651         numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1652         for (i = 0;i < pheader->numscenes;i++)
1653         {
1654                 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1655                 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1656                 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1657                 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1658                 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1659                 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1660                         Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1661                 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1662                         Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1663                 if (loadmodel->animscenes[i].framerate < 0)
1664                         Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1665                 scene++;
1666         }
1667
1668         //zymlump_t lump_bones; // zymbone_t bone[numbones];
1669         loadmodel->num_bones = pheader->numbones;
1670         loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, pheader->numbones * sizeof(aliasbone_t));
1671         bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1672         for (i = 0;i < pheader->numbones;i++)
1673         {
1674                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1675                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1676                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1677                 if (loadmodel->data_bones[i].parent >= i)
1678                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1679         }
1680
1681         //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1682         vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1683         bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1684         for (i = 0;i < pheader->numverts;i++)
1685         {
1686                 vertbonecounts[i] = BigLong(bonecount[i]);
1687                 if (vertbonecounts[i] != 1)
1688                         Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1689         }
1690
1691         loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]);
1692
1693         meshvertices = pheader->numverts;
1694         meshtriangles = pheader->numtris;
1695
1696         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1697         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1698         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1699         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]) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[14]) + meshvertices * sizeof(int[4]) + meshvertices * sizeof(float[4]) + loadmodel->num_poses * sizeof(float[12]) + loadmodel->num_bones * sizeof(float[12]));
1700         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1701         loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1702         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1703         loadmodel->surfmesh.num_vertices = meshvertices;
1704         loadmodel->surfmesh.num_triangles = meshtriangles;
1705         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1706         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1707         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1708         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1709         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1710         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1711         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1712         loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += meshvertices * sizeof(int[4]);
1713         loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += meshvertices * sizeof(float[4]);
1714         loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]);
1715         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1716         if (loadmodel->surfmesh.num_vertices <= 65536)
1717         {
1718                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1719                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1720                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1721         }
1722
1723         //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1724         poses = (float *) (pheader->lump_poses.start + pbase);
1725         for (i = 0;i < pheader->lump_poses.length / 4;i++)
1726                 loadmodel->data_poses[i] = BigFloat(poses[i]);
1727
1728         //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
1729         verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
1730         vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
1731         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
1732         // (converting from weight-blending skeletal animation to
1733         //  deformation-based skeletal animation)
1734         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
1735         for (i = 0;i < loadmodel->num_bones;i++)
1736         {
1737                 const float *m = loadmodel->data_poses + i * 12;
1738                 if (loadmodel->data_bones[i].parent >= 0)
1739                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
1740                 else
1741                         for (k = 0;k < 12;k++)
1742                                 bonepose[12*i+k] = m[k];
1743         }
1744         for (j = 0;j < pheader->numverts;j++)
1745         {
1746                 // this format really should have had a per vertexweight weight value...
1747                 // but since it does not, the weighting is completely ignored and
1748                 // only one weight is allowed per vertex
1749                 int boneindex = BigLong(vertdata[j].bonenum);
1750                 const float *m = bonepose + 12 * boneindex;
1751                 float relativeorigin[3];
1752                 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
1753                 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
1754                 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
1755                 // transform the vertex bone weight into the base mesh
1756                 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
1757                 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
1758                 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
1759                 // store the weight as the primary weight on this vertex
1760                 loadmodel->surfmesh.data_vertexweightindex4i[j*4+0] = boneindex;
1761                 loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+0] = 1;
1762         }
1763         Z_Free(bonepose);
1764         // normals and tangents are calculated after elements are loaded
1765
1766         //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
1767         outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
1768         intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
1769         for (i = 0;i < pheader->numverts;i++)
1770         {
1771                 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
1772                 // flip T coordinate for OpenGL
1773                 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
1774         }
1775
1776         //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
1777         //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
1778         //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
1779
1780         //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
1781         //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)
1782         // byteswap, validate, and swap winding order of tris
1783         count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
1784         if (pheader->lump_render.length != count)
1785                 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
1786         renderlist = (int *) (pheader->lump_render.start + pbase);
1787         renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
1788         meshtriangles = 0;
1789         for (i = 0;i < loadmodel->num_surfaces;i++)
1790         {
1791                 int firstvertex, lastvertex;
1792                 if (renderlist >= renderlistend)
1793                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
1794                 count = BigLong(*renderlist);renderlist++;
1795                 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
1796                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
1797
1798                 loadmodel->surfacelist[i] = i;
1799                 surface = loadmodel->data_surfaces + i;
1800                 surface->texture = loadmodel->data_textures + i;
1801                 surface->num_firsttriangle = meshtriangles;
1802                 surface->num_triangles = count;
1803                 meshtriangles += surface->num_triangles;
1804
1805                 // load the elements
1806                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1807                 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
1808                 {
1809                         outelements[j*3+2] = BigLong(renderlist[0]);
1810                         outelements[j*3+1] = BigLong(renderlist[1]);
1811                         outelements[j*3+0] = BigLong(renderlist[2]);
1812                 }
1813                 // validate the elements and find the used vertex range
1814                 firstvertex = meshvertices;
1815                 lastvertex = 0;
1816                 for (j = 0;j < surface->num_triangles * 3;j++)
1817                 {
1818                         if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
1819                                 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
1820                         firstvertex = min(firstvertex, outelements[j]);
1821                         lastvertex = max(lastvertex, outelements[j]);
1822                 }
1823                 surface->num_firstvertex = firstvertex;
1824                 surface->num_vertices = lastvertex + 1 - firstvertex;
1825
1826                 // since zym models do not have named sections, reuse their shader
1827                 // name as the section name
1828                 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
1829                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
1830         }
1831         Mod_FreeSkinFiles(skinfiles);
1832         Mem_Free(vertbonecounts);
1833         Mem_Free(verts);
1834
1835         // compute all the mesh information that was not loaded from the file
1836         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
1837         Mod_BuildBaseBonePoses();
1838         Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true);
1839         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, true);
1840         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1841
1842         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1843 }
1844
1845 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1846 {
1847         dpmheader_t *pheader;
1848         dpmframe_t *frame;
1849         dpmbone_t *bone;
1850         dpmmesh_t *dpmmesh;
1851         unsigned char *pbase;
1852         int i, j, k, meshvertices, meshtriangles;
1853         skinfile_t *skinfiles;
1854         unsigned char *data;
1855         float *bonepose;
1856
1857         pheader = (dpmheader_t *)buffer;
1858         pbase = (unsigned char *)buffer;
1859         if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
1860                 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
1861         if (BigLong(pheader->type) != 2)
1862                 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1863
1864         loadmodel->modeldatatypestring = "DPM";
1865
1866         loadmodel->type = mod_alias;
1867         loadmodel->synctype = ST_RAND;
1868
1869         // byteswap header
1870         pheader->type = BigLong(pheader->type);
1871         pheader->filesize = BigLong(pheader->filesize);
1872         pheader->mins[0] = BigFloat(pheader->mins[0]);
1873         pheader->mins[1] = BigFloat(pheader->mins[1]);
1874         pheader->mins[2] = BigFloat(pheader->mins[2]);
1875         pheader->maxs[0] = BigFloat(pheader->maxs[0]);
1876         pheader->maxs[1] = BigFloat(pheader->maxs[1]);
1877         pheader->maxs[2] = BigFloat(pheader->maxs[2]);
1878         pheader->yawradius = BigFloat(pheader->yawradius);
1879         pheader->allradius = BigFloat(pheader->allradius);
1880         pheader->num_bones = BigLong(pheader->num_bones);
1881         pheader->num_meshs = BigLong(pheader->num_meshs);
1882         pheader->num_frames = BigLong(pheader->num_frames);
1883         pheader->ofs_bones = BigLong(pheader->ofs_bones);
1884         pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
1885         pheader->ofs_frames = BigLong(pheader->ofs_frames);
1886
1887         if (pheader->num_bones < 1 || pheader->num_meshs < 1)
1888         {
1889                 Con_Printf("%s has no geometry\n", loadmodel->name);
1890                 return;
1891         }
1892         if (pheader->num_frames < 1)
1893         {
1894                 Con_Printf("%s has no frames\n", loadmodel->name);
1895                 return;
1896         }
1897
1898         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1899         loadmodel->DrawSky = NULL;
1900         loadmodel->DrawAddWaterPlanes = NULL;
1901         loadmodel->Draw = R_Q1BSP_Draw;
1902         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1903         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1904         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1905         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1906         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1907         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1908         loadmodel->PointSuperContents = NULL;
1909
1910         // model bbox
1911         for (i = 0;i < 3;i++)
1912         {
1913                 loadmodel->normalmins[i] = pheader->mins[i];
1914                 loadmodel->normalmaxs[i] = pheader->maxs[i];
1915                 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
1916                 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
1917                 loadmodel->rotatedmins[i] = -pheader->allradius;
1918                 loadmodel->rotatedmaxs[i] = pheader->allradius;
1919         }
1920         loadmodel->radius = pheader->allradius;
1921         loadmodel->radius2 = pheader->allradius * pheader->allradius;
1922
1923         // load external .skin files if present
1924         skinfiles = Mod_LoadSkinFiles();
1925         if (loadmodel->numskins < 1)
1926                 loadmodel->numskins = 1;
1927
1928         meshvertices = 0;
1929         meshtriangles = 0;
1930
1931         // gather combined statistics from the meshes
1932         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
1933         for (i = 0;i < (int)pheader->num_meshs;i++)
1934         {
1935                 int numverts = BigLong(dpmmesh->num_verts);
1936                 meshvertices += numverts;
1937                 meshtriangles += BigLong(dpmmesh->num_tris);
1938                 dpmmesh++;
1939         }
1940
1941         loadmodel->numframes = pheader->num_frames;
1942         loadmodel->num_bones = pheader->num_bones;
1943         loadmodel->num_poses = loadmodel->num_bones * loadmodel->numframes;
1944         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
1945         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1946         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1947         // do most allocations as one merged chunk
1948         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) + meshtriangles * sizeof(int[3]) + meshvertices * (sizeof(float[14]) + sizeof(int[4]) + sizeof(float[4])) + loadmodel->num_poses * sizeof(float[12]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t));
1949         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1950         loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1951         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1952         loadmodel->surfmesh.num_vertices = meshvertices;
1953         loadmodel->surfmesh.num_triangles = meshtriangles;
1954         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1955         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1956         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1957         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1958         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1959         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1960         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1961         loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += meshvertices * sizeof(int[4]);
1962         loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += meshvertices * sizeof(float[4]);
1963         loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]);
1964         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1965         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
1966         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
1967         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1968         if (meshvertices <= 65536)
1969         {
1970                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1971                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1972                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1973         }
1974
1975         for (i = 0;i < loadmodel->numskins;i++)
1976         {
1977                 loadmodel->skinscenes[i].firstframe = i;
1978                 loadmodel->skinscenes[i].framecount = 1;
1979                 loadmodel->skinscenes[i].loop = true;
1980                 loadmodel->skinscenes[i].framerate = 10;
1981         }
1982
1983         // load the bone info
1984         bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
1985         for (i = 0;i < loadmodel->num_bones;i++)
1986         {
1987                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1988                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1989                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1990                 if (loadmodel->data_bones[i].parent >= i)
1991                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1992         }
1993
1994         // load the frames
1995         frame = (dpmframe_t *) (pbase + pheader->ofs_frames);
1996         for (i = 0;i < loadmodel->numframes;i++)
1997         {
1998                 const float *poses;
1999                 memcpy(loadmodel->animscenes[i].name, frame->name, sizeof(frame->name));
2000                 loadmodel->animscenes[i].firstframe = i;
2001                 loadmodel->animscenes[i].framecount = 1;
2002                 loadmodel->animscenes[i].loop = true;
2003                 loadmodel->animscenes[i].framerate = 10;
2004                 // load the bone poses for this frame
2005                 poses = (float *) (pbase + BigLong(frame->ofs_bonepositions));
2006                 for (j = 0;j < loadmodel->num_bones*12;j++)
2007                         loadmodel->data_poses[i * loadmodel->num_bones*12 + j] = BigFloat(poses[j]);
2008                 // stuff not processed here: mins, maxs, yawradius, allradius
2009                 frame++;
2010         }
2011
2012         // load the meshes now
2013         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2014         meshvertices = 0;
2015         meshtriangles = 0;
2016         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2017         // (converting from weight-blending skeletal animation to
2018         //  deformation-based skeletal animation)
2019         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2020         for (i = 0;i < loadmodel->num_bones;i++)
2021         {
2022                 const float *m = loadmodel->data_poses + i * 12;
2023                 if (loadmodel->data_bones[i].parent >= 0)
2024                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2025                 else
2026                         for (k = 0;k < 12;k++)
2027                                 bonepose[12*i+k] = m[k];
2028         }
2029         for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2030         {
2031                 const int *inelements;
2032                 int *outelements;
2033                 const float *intexcoord;
2034                 msurface_t *surface;
2035
2036                 loadmodel->surfacelist[i] = i;
2037                 surface = loadmodel->data_surfaces + i;
2038                 surface->texture = loadmodel->data_textures + i;
2039                 surface->num_firsttriangle = meshtriangles;
2040                 surface->num_triangles = BigLong(dpmmesh->num_tris);
2041                 surface->num_firstvertex = meshvertices;
2042                 surface->num_vertices = BigLong(dpmmesh->num_verts);
2043                 meshvertices += surface->num_vertices;
2044                 meshtriangles += surface->num_triangles;
2045
2046                 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2047                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2048                 for (j = 0;j < surface->num_triangles;j++)
2049                 {
2050                         // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2051                         outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2052                         outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2053                         outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2054                         inelements += 3;
2055                         outelements += 3;
2056                 }
2057
2058                 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2059                 for (j = 0;j < surface->num_vertices*2;j++)
2060                         loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2061
2062                 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2063                 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2064                 {
2065                         float sum;
2066                         int l;
2067                         int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2068                         data += sizeof(dpmvertex_t);
2069                         for (k = 0;k < numweights;k++)
2070                         {
2071                                 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2072                                 int boneindex = BigLong(vert->bonenum);
2073                                 const float *m = bonepose + 12 * boneindex;
2074                                 float influence = BigFloat(vert->influence);
2075                                 float relativeorigin[3], relativenormal[3];
2076                                 relativeorigin[0] = BigFloat(vert->origin[0]);
2077                                 relativeorigin[1] = BigFloat(vert->origin[1]);
2078                                 relativeorigin[2] = BigFloat(vert->origin[2]);
2079                                 relativenormal[0] = BigFloat(vert->normal[0]);
2080                                 relativenormal[1] = BigFloat(vert->normal[1]);
2081                                 relativenormal[2] = BigFloat(vert->normal[2]);
2082                                 // blend the vertex bone weights into the base mesh
2083                                 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2084                                 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2085                                 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2086                                 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2087                                 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2088                                 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2089                                 if (!k)
2090                                 {
2091                                         // store the first (and often only) weight
2092                                         loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+0] = influence;
2093                                         loadmodel->surfmesh.data_vertexweightindex4i[j*4+0] = boneindex;
2094                                 }
2095                                 else
2096                                 {
2097                                         // sort the new weight into this vertex's weight table
2098                                         // (which only accepts up to 4 bones per vertex)
2099                                         for (l = 0;l < 4;l++)
2100                                         {
2101                                                 if (loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] < influence)
2102                                                 {
2103                                                         // move weaker influence weights out of the way first
2104                                                         int l2;
2105                                                         for (l2 = 3;l2 > l;l2--)
2106                                                         {
2107                                                                 loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l2] = loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l2-1];
2108                                                                 loadmodel->surfmesh.data_vertexweightindex4i[j*4+l2] = loadmodel->surfmesh.data_vertexweightindex4i[j*4+l2-1];
2109                                                         }
2110                                                         // store the new weight
2111                                                         loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] = influence;
2112                                                         loadmodel->surfmesh.data_vertexweightindex4i[j*4+l] = boneindex;
2113                                                         break;
2114                                                 }
2115                                         }
2116                                 }
2117                                 data += sizeof(dpmbonevert_t);
2118                         }
2119                         sum = 0;
2120                         for (l = 0;l < 4;l++)
2121                                 sum += loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l];
2122                         if (sum && fabs(sum - 1) > (1.0f / 256.0f))
2123                         {
2124                                 float f = 1.0f / sum;
2125                                 for (l = 0;l < 4;l++)
2126                                         loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] *= f;
2127                         }
2128                 }
2129
2130                 // since dpm models do not have named sections, reuse their shader name as the section name
2131                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2132
2133                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2134         }
2135         Z_Free(bonepose);
2136         Mod_FreeSkinFiles(skinfiles);
2137
2138         // compute all the mesh information that was not loaded from the file
2139         Mod_BuildBaseBonePoses();
2140         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, true);
2141         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2142
2143         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
2144 }
2145
2146 // no idea why PSK/PSA files contain weird quaternions but they do...
2147 #define PSKQUATNEGATIONS
2148 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2149 {
2150         int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2151         int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2152         fs_offset_t filesize;
2153         pskpnts_t *pnts;
2154         pskvtxw_t *vtxw;
2155         pskface_t *faces;
2156         pskmatt_t *matts;
2157         pskboneinfo_t *bones;
2158         pskrawweights_t *rawweights;
2159         pskboneinfo_t *animbones;
2160         pskaniminfo_t *anims;
2161         pskanimkeys_t *animkeys;
2162         void *animfilebuffer, *animbuffer, *animbufferend;
2163         unsigned char *data;
2164         pskchunk_t *pchunk;
2165         skinfile_t *skinfiles;
2166         char animname[MAX_QPATH];
2167         size_t size;
2168
2169         pchunk = (pskchunk_t *)buffer;
2170         if (strcmp(pchunk->id, "ACTRHEAD"))
2171                 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2172
2173         loadmodel->modeldatatypestring = "PSK";
2174
2175         loadmodel->type = mod_alias;
2176         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2177         loadmodel->DrawSky = NULL;
2178         loadmodel->DrawAddWaterPlanes = NULL;
2179         loadmodel->Draw = R_Q1BSP_Draw;
2180         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2181         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2182         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2183         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2184         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2185         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2186         loadmodel->PointSuperContents = NULL;
2187         loadmodel->synctype = ST_RAND;
2188
2189         FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2190         strlcat(animname, ".psa", sizeof(animname));
2191         animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2192         animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2193         if (animbuffer == NULL)
2194                 Host_Error("%s: can't find .psa file (%s)", loadmodel->name, animname);
2195
2196         numpnts = 0;
2197         pnts = NULL;
2198         numvtxw = 0;
2199         vtxw = NULL;
2200         numfaces = 0;
2201         faces = NULL;
2202         nummatts = 0;
2203         matts = NULL;
2204         numbones = 0;
2205         bones = NULL;
2206         numrawweights = 0;
2207         rawweights = NULL;
2208         numanims = 0;
2209         anims = NULL;
2210         numanimkeys = 0;
2211         animkeys = NULL;
2212
2213         while (buffer < bufferend)
2214         {
2215                 pchunk = (pskchunk_t *)buffer;
2216                 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2217                 version = LittleLong(pchunk->version);
2218                 recordsize = LittleLong(pchunk->recordsize);
2219                 numrecords = LittleLong(pchunk->numrecords);
2220                 if (developer.integer >= 100)
2221                         Con_Printf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2222                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2223                         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);
2224                 if (!strcmp(pchunk->id, "ACTRHEAD"))
2225                 {
2226                         // nothing to do
2227                 }
2228                 else if (!strcmp(pchunk->id, "PNTS0000"))
2229                 {
2230                         pskpnts_t *p;
2231                         if (recordsize != sizeof(*p))
2232                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2233                         // byteswap in place and keep the pointer
2234                         numpnts = numrecords;
2235                         pnts = (pskpnts_t *)buffer;
2236                         for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2237                         {
2238                                 p->origin[0] = LittleFloat(p->origin[0]);
2239                                 p->origin[1] = LittleFloat(p->origin[1]);
2240                                 p->origin[2] = LittleFloat(p->origin[2]);
2241                         }
2242                         buffer = p;
2243                 }
2244                 else if (!strcmp(pchunk->id, "VTXW0000"))
2245                 {
2246                         pskvtxw_t *p;
2247                         if (recordsize != sizeof(*p))
2248                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2249                         // byteswap in place and keep the pointer
2250                         numvtxw = numrecords;
2251                         vtxw = (pskvtxw_t *)buffer;
2252                         for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2253                         {
2254                                 p->pntsindex = LittleShort(p->pntsindex);
2255                                 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2256                                 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2257                                 if (p->pntsindex >= numpnts)
2258                                 {
2259                                         Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2260                                         p->pntsindex = 0;
2261                                 }
2262                         }
2263                         buffer = p;
2264                 }
2265                 else if (!strcmp(pchunk->id, "FACE0000"))
2266                 {
2267                         pskface_t *p;
2268                         if (recordsize != sizeof(*p))
2269                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2270                         // byteswap in place and keep the pointer
2271                         numfaces = numrecords;
2272                         faces = (pskface_t *)buffer;
2273                         for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2274                         {
2275                                 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2276                                 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2277                                 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2278                                 p->group = LittleLong(p->group);
2279                                 if (p->vtxwindex[0] >= numvtxw)
2280                                 {
2281                                         Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2282                                         p->vtxwindex[0] = 0;
2283                                 }
2284                                 if (p->vtxwindex[1] >= numvtxw)
2285                                 {
2286                                         Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2287                                         p->vtxwindex[1] = 0;
2288                                 }
2289                                 if (p->vtxwindex[2] >= numvtxw)
2290                                 {
2291                                         Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2292                                         p->vtxwindex[2] = 0;
2293                                 }
2294                         }
2295                         buffer = p;
2296                 }
2297                 else if (!strcmp(pchunk->id, "MATT0000"))
2298                 {
2299                         pskmatt_t *p;
2300                         if (recordsize != sizeof(*p))
2301                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2302                         // byteswap in place and keep the pointer
2303                         nummatts = numrecords;
2304                         matts = (pskmatt_t *)buffer;
2305                         for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2306                         {
2307                                 // nothing to do
2308                         }
2309                         buffer = p;
2310                 }
2311                 else if (!strcmp(pchunk->id, "REFSKELT"))
2312                 {
2313                         pskboneinfo_t *p;
2314                         if (recordsize != sizeof(*p))
2315                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2316                         // byteswap in place and keep the pointer
2317                         numbones = numrecords;
2318                         bones = (pskboneinfo_t *)buffer;
2319                         for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2320                         {
2321                                 p->numchildren = LittleLong(p->numchildren);
2322                                 p->parent = LittleLong(p->parent);
2323                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2324                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2325                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2326                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2327                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2328                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2329                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2330                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2331                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2332                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2333                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2334 #ifdef PSKQUATNEGATIONS
2335                                 if (index)
2336                                 {
2337                                         p->basepose.quat[0] *= -1;
2338                                         p->basepose.quat[1] *= -1;
2339                                         p->basepose.quat[2] *= -1;
2340                                 }
2341                                 else
2342                                 {
2343                                         p->basepose.quat[0] *=  1;
2344                                         p->basepose.quat[1] *= -1;
2345                                         p->basepose.quat[2] *=  1;
2346                                 }
2347 #endif
2348                                 if (p->parent < 0 || p->parent >= numbones)
2349                                 {
2350                                         Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2351                                         p->parent = 0;
2352                                 }
2353                         }
2354                         buffer = p;
2355                 }
2356                 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2357                 {
2358                         pskrawweights_t *p;
2359                         if (recordsize != sizeof(*p))
2360                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2361                         // byteswap in place and keep the pointer
2362                         numrawweights = numrecords;
2363                         rawweights = (pskrawweights_t *)buffer;
2364                         for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2365                         {
2366                                 p->weight = LittleFloat(p->weight);
2367                                 p->pntsindex = LittleLong(p->pntsindex);
2368                                 p->boneindex = LittleLong(p->boneindex);
2369                                 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2370                                 {
2371                                         Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2372                                         p->pntsindex = 0;
2373                                 }
2374                                 if (p->boneindex < 0 || p->boneindex >= numbones)
2375                                 {
2376                                         Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2377                                         p->boneindex = 0;
2378                                 }
2379                         }
2380                         buffer = p;
2381                 }
2382         }
2383
2384         while (animbuffer < animbufferend)
2385         {
2386                 pchunk = (pskchunk_t *)animbuffer;
2387                 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2388                 version = LittleLong(pchunk->version);
2389                 recordsize = LittleLong(pchunk->recordsize);
2390                 numrecords = LittleLong(pchunk->numrecords);
2391                 if (developer.integer >= 100)
2392                         Con_Printf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2393                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2394                         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);
2395                 if (!strcmp(pchunk->id, "ANIMHEAD"))
2396                 {
2397                         // nothing to do
2398                 }
2399                 else if (!strcmp(pchunk->id, "BONENAMES"))
2400                 {
2401                         pskboneinfo_t *p;
2402                         if (recordsize != sizeof(*p))
2403                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2404                         // byteswap in place and keep the pointer
2405                         numanimbones = numrecords;
2406                         animbones = (pskboneinfo_t *)animbuffer;
2407                         // NOTE: supposedly psa does not need to match the psk model, the
2408                         // bones missing from the psa would simply use their base
2409                         // positions from the psk, but this is hard for me to implement
2410                         // and people can easily make animations that match.
2411                         if (numanimbones != numbones)
2412                                 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2413                         for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2414                         {
2415                                 p->numchildren = LittleLong(p->numchildren);
2416                                 p->parent = LittleLong(p->parent);
2417                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2418                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2419                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2420                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2421                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2422                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2423                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2424                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2425                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2426                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2427                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2428 #ifdef PSKQUATNEGATIONS
2429                                 if (index)
2430                                 {
2431                                         p->basepose.quat[0] *= -1;
2432                                         p->basepose.quat[1] *= -1;
2433                                         p->basepose.quat[2] *= -1;
2434                                 }
2435                                 else
2436                                 {
2437                                         p->basepose.quat[0] *=  1;
2438                                         p->basepose.quat[1] *= -1;
2439                                         p->basepose.quat[2] *=  1;
2440                                 }
2441 #endif
2442                                 if (p->parent < 0 || p->parent >= numanimbones)
2443                                 {
2444                                         Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2445                                         p->parent = 0;
2446                                 }
2447                                 // check that bones are the same as in the base
2448                                 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2449                                         Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2450                         }
2451                         animbuffer = p;
2452                 }
2453                 else if (!strcmp(pchunk->id, "ANIMINFO"))
2454                 {
2455                         pskaniminfo_t *p;
2456                         if (recordsize != sizeof(*p))
2457                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2458                         // byteswap in place and keep the pointer
2459                         numanims = numrecords;
2460                         anims = (pskaniminfo_t *)animbuffer;
2461                         for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2462                         {
2463                                 p->numbones = LittleLong(p->numbones);
2464                                 p->playtime = LittleFloat(p->playtime);
2465                                 p->fps = LittleFloat(p->fps);
2466                                 p->firstframe = LittleLong(p->firstframe);
2467                                 p->numframes = LittleLong(p->numframes);
2468                                 if (p->numbones != numbones)
2469                                         Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2470                         }
2471                         animbuffer = p;
2472                 }
2473                 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2474                 {
2475                         pskanimkeys_t *p;
2476                         if (recordsize != sizeof(*p))
2477                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2478                         numanimkeys = numrecords;
2479                         animkeys = (pskanimkeys_t *)animbuffer;
2480                         for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2481                         {
2482                                 p->origin[0] = LittleFloat(p->origin[0]);
2483                                 p->origin[1] = LittleFloat(p->origin[1]);
2484                                 p->origin[2] = LittleFloat(p->origin[2]);
2485                                 p->quat[0] = LittleFloat(p->quat[0]);
2486                                 p->quat[1] = LittleFloat(p->quat[1]);
2487                                 p->quat[2] = LittleFloat(p->quat[2]);
2488                                 p->quat[3] = LittleFloat(p->quat[3]);
2489                                 p->frametime = LittleFloat(p->frametime);
2490 #ifdef PSKQUATNEGATIONS
2491                                 if (index % numbones)
2492                                 {
2493                                         p->quat[0] *= -1;
2494                                         p->quat[1] *= -1;
2495                                         p->quat[2] *= -1;
2496                                 }
2497                                 else
2498                                 {
2499                                         p->quat[0] *=  1;
2500                                         p->quat[1] *= -1;
2501                                         p->quat[2] *=  1;
2502                                 }
2503 #endif
2504                         }
2505                         animbuffer = p;
2506                         // TODO: allocate bonepose stuff
2507                 }
2508                 else
2509                         Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2510         }
2511
2512         if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights || !numanims || !anims || !numanimkeys || !animkeys)
2513                 Host_Error("%s: missing required chunks", loadmodel->name);
2514
2515         loadmodel->numframes = 0;
2516         for (index = 0;index < numanims;index++)
2517                 loadmodel->numframes += anims[index].numframes;
2518
2519         if (numanimkeys != numbones * loadmodel->numframes)
2520                 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2521
2522         meshvertices = numvtxw;
2523         meshtriangles = numfaces;
2524
2525         // load external .skin files if present
2526         skinfiles = Mod_LoadSkinFiles();
2527         if (loadmodel->numskins < 1)
2528                 loadmodel->numskins = 1;
2529         loadmodel->num_bones = numbones;
2530         loadmodel->num_poses = loadmodel->num_bones * loadmodel->numframes;
2531         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2532         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2533         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2534         loadmodel->surfmesh.num_vertices = meshvertices;
2535         loadmodel->surfmesh.num_triangles = meshtriangles;
2536         // do most allocations as one merged chunk
2537         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]) + loadmodel->surfmesh.num_triangles * sizeof(int[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[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * sizeof(int[4]) + loadmodel->surfmesh.num_vertices * sizeof(float[4]) + /*loadmodel->num_poses * sizeof(float[12]) + */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);
2538         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2539         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2540         loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2541         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2542         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2543         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2544         loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2545         loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2546         loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2547         loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2548         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2549         loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += loadmodel->surfmesh.num_vertices * sizeof(int[4]);
2550         loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
2551         //loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]);
2552         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2553         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2554         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2555         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2556         if (loadmodel->surfmesh.num_vertices <= 65536)
2557         {
2558                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2559                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2560                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2561         }
2562         loadmodel->data_poses = Mem_Alloc(loadmodel->mempool, loadmodel->num_poses * sizeof(float[12]));
2563
2564         for (i = 0;i < loadmodel->numskins;i++)
2565         {
2566                 loadmodel->skinscenes[i].firstframe = i;
2567                 loadmodel->skinscenes[i].framecount = 1;
2568                 loadmodel->skinscenes[i].loop = true;
2569                 loadmodel->skinscenes[i].framerate = 10;
2570         }
2571
2572         // create surfaces
2573         for (index = 0, i = 0;index < nummatts;index++)
2574         {
2575                 // since psk models do not have named sections, reuse their shader name as the section name
2576                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2577                 loadmodel->surfacelist[index] = index;
2578                 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2579                 loadmodel->data_surfaces[index].num_firstvertex = 0;
2580                 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2581         }
2582
2583         // copy over the vertex locations and texcoords
2584         for (index = 0;index < numvtxw;index++)
2585         {
2586                 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2587                 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2588                 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2589                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2590                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
2591         }
2592
2593         // loading the faces is complicated because we need to sort them into surfaces by mattindex
2594         for (index = 0;index < numfaces;index++)
2595                 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
2596         for (index = 0, i = 0;index < nummatts;index++)
2597         {
2598                 loadmodel->data_surfaces[index].num_firsttriangle = i;
2599                 i += loadmodel->data_surfaces[index].num_triangles;
2600                 loadmodel->data_surfaces[index].num_triangles = 0;
2601         }
2602         for (index = 0;index < numfaces;index++)
2603         {
2604                 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
2605                 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
2606                 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
2607                 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
2608         }
2609
2610         // copy over the bones
2611         for (index = 0;index < numbones;index++)
2612         {
2613                 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
2614                 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
2615                 if (loadmodel->data_bones[index].parent >= index)
2616                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
2617         }
2618
2619         // sort the psk point weights into the vertex weight tables
2620         // (which only accept up to 4 bones per vertex)
2621         for (index = 0;index < numvtxw;index++)
2622         {
2623                 int l;
2624                 float sum;
2625                 for (j = 0;j < numrawweights;j++)
2626                 {
2627                         if (rawweights[j].pntsindex == vtxw[index].pntsindex)
2628                         {
2629                                 int boneindex = rawweights[j].boneindex;
2630                                 float influence = rawweights[j].weight;
2631                                 for (l = 0;l < 4;l++)
2632                                 {
2633                                         if (loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] < influence)
2634                                         {
2635                                                 // move lower influence weights out of the way first
2636                                                 int l2;
2637                                                 for (l2 = 3;l2 > l;l2--)
2638                                                 {
2639                                                         loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l2] = loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l2-1];
2640                                                         loadmodel->surfmesh.data_vertexweightindex4i[index*4+l2] = loadmodel->surfmesh.data_vertexweightindex4i[index*4+l2-1];
2641                                                 }
2642                                                 // store the new weight
2643                                                 loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] = influence;
2644                                                 loadmodel->surfmesh.data_vertexweightindex4i[index*4+l] = boneindex;
2645                                                 break;
2646                                         }
2647                                 }
2648                         }
2649                 }
2650                 sum = 0;
2651                 for (l = 0;l < 4;l++)
2652                         sum += loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l];
2653                 if (sum && fabs(sum - 1) > (1.0f / 256.0f))
2654                 {
2655                         float f = 1.0f / sum;
2656                         for (l = 0;l < 4;l++)
2657                                 loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] *= f;
2658                 }
2659         }
2660
2661         // set up the animscenes based on the anims
2662         for (index = 0, i = 0;index < numanims;index++)
2663         {
2664                 for (j = 0;j < anims[index].numframes;j++, i++)
2665                 {
2666                         dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
2667                         loadmodel->animscenes[i].firstframe = i;
2668                         loadmodel->animscenes[i].framecount = 1;
2669                         loadmodel->animscenes[i].loop = true;
2670                         loadmodel->animscenes[i].framerate = 10;
2671                 }
2672         }
2673
2674         // load the poses from the animkeys
2675         for (index = 0;index < numanimkeys;index++)
2676         {
2677                 pskanimkeys_t *k = animkeys + index;
2678                 matrix4x4_t matrix;
2679                 Matrix4x4_FromOriginQuat(&matrix, k->origin[0], k->origin[1], k->origin[2], k->quat[0], k->quat[1], k->quat[2], k->quat[3]);
2680                 Matrix4x4_ToArray12FloatD3D(&matrix, loadmodel->data_poses + index*12);
2681         }
2682         Mod_FreeSkinFiles(skinfiles);
2683         Mem_Free(animfilebuffer);
2684
2685         // compute all the mesh information that was not loaded from the file
2686         // TODO: honor smoothing groups somehow?
2687         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2688         Mod_BuildBaseBonePoses();
2689         Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true);
2690         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, true);
2691         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2692         Mod_Alias_CalculateBoundingBox();
2693
2694         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
2695 }
2696