]> icculus.org git repositories - divverent/darkplaces.git/blob - model_alias.c
SDL: reduce the sound buffer size (too much lag otherwise)
[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         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
999         loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1000         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1001         loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1002         if (skinfiles)
1003         {
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                 totalskins = 0;
1017                 datapointer = startskins;
1018                 for (i = 0;i < loadmodel->numskins;i++)
1019                 {
1020                         pinskintype = (daliasskintype_t *)datapointer;
1021                         datapointer += sizeof(daliasskintype_t);
1022
1023                         if (pinskintype->type == ALIAS_SKIN_SINGLE)
1024                         {
1025                                 groupskins = 1;
1026                                 interval = 0.1f;
1027                         }
1028                         else
1029                         {
1030                                 pinskingroup = (daliasskingroup_t *)datapointer;
1031                                 datapointer += sizeof(daliasskingroup_t);
1032
1033                                 groupskins = LittleLong (pinskingroup->numskins);
1034
1035                                 pinskinintervals = (daliasskininterval_t *)datapointer;
1036                                 datapointer += sizeof(daliasskininterval_t) * groupskins;
1037
1038                                 interval = LittleFloat(pinskinintervals[0].interval);
1039                                 if (interval < 0.01f)
1040                                 {
1041                                         Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1042                                         interval = 0.1f;
1043                                 }
1044                         }
1045
1046                         dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1047                         loadmodel->skinscenes[i].firstframe = totalskins;
1048                         loadmodel->skinscenes[i].framecount = groupskins;
1049                         loadmodel->skinscenes[i].framerate = 1.0f / interval;
1050                         loadmodel->skinscenes[i].loop = true;
1051
1052                         for (j = 0;j < groupskins;j++)
1053                         {
1054                                 if (groupskins > 1)
1055                                         dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1056                                 else
1057                                         dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1058                                 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))
1059                                         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));
1060                                 datapointer += skinwidth * skinheight;
1061                                 totalskins++;
1062                         }
1063                 }
1064                 // check for skins that don't exist in the model, but do exist as external images
1065                 // (this was added because yummyluv kept pestering me about support for it)
1066                 // TODO: support shaders here?
1067                 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)))
1068                 {
1069                         // expand the arrays to make room
1070                         tempskinscenes = loadmodel->skinscenes;
1071                         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1072                         memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1073                         Mem_Free(tempskinscenes);
1074
1075                         tempaliasskins = loadmodel->data_textures;
1076                         loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1077                         memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1078                         Mem_Free(tempaliasskins);
1079
1080                         // store the info about the new skin
1081                         Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
1082                         strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1083                         loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1084                         loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1085                         loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1086                         loadmodel->skinscenes[loadmodel->numskins].loop = true;
1087
1088                         //increase skin counts
1089                         loadmodel->numskins++;
1090                         totalskins++;
1091
1092                         // fix up the pointers since they are pointing at the old textures array
1093                         // FIXME: this is a hack!
1094                         for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1095                                 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1096                 }
1097         }
1098
1099         surface = loadmodel->data_surfaces;
1100         surface->texture = loadmodel->data_textures;
1101         surface->num_firsttriangle = 0;
1102         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1103         surface->num_firstvertex = 0;
1104         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1105
1106         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1107 }
1108
1109 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1110 {
1111         int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1112         float iskinwidth, iskinheight;
1113         unsigned char *data;
1114         msurface_t *surface;
1115         md2_t *pinmodel;
1116         unsigned char *base, *datapointer;
1117         md2frame_t *pinframe;
1118         char *inskin;
1119         md2triangle_t *intri;
1120         unsigned short *inst;
1121         struct md2verthash_s
1122         {
1123                 struct md2verthash_s *next;
1124                 unsigned short xyz;
1125                 unsigned short st;
1126         }
1127         *hash, **md2verthash, *md2verthashdata;
1128         skinfile_t *skinfiles;
1129
1130         pinmodel = (md2_t *)buffer;
1131         base = (unsigned char *)buffer;
1132
1133         version = LittleLong (pinmodel->version);
1134         if (version != MD2ALIAS_VERSION)
1135                 Host_Error ("%s has wrong version number (%i should be %i)",
1136                         loadmodel->name, version, MD2ALIAS_VERSION);
1137
1138         loadmodel->modeldatatypestring = "MD2";
1139
1140         loadmodel->type = mod_alias;
1141         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1142         loadmodel->DrawSky = NULL;
1143         loadmodel->DrawAddWaterPlanes = NULL;
1144         loadmodel->Draw = R_Q1BSP_Draw;
1145         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1146         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1147         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1148         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1149         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1150         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1151         loadmodel->PointSuperContents = NULL;
1152
1153         if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1154                 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1155         if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1156                 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1157         if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1158                 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1159         if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1160                 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1161
1162         end = LittleLong(pinmodel->ofs_end);
1163         if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1164                 Host_Error ("%s is not a valid model", loadmodel->name);
1165         if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1166                 Host_Error ("%s is not a valid model", loadmodel->name);
1167         if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1168                 Host_Error ("%s is not a valid model", loadmodel->name);
1169         if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1170                 Host_Error ("%s is not a valid model", loadmodel->name);
1171         if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1172                 Host_Error ("%s is not a valid model", loadmodel->name);
1173
1174         loadmodel->numskins = LittleLong(pinmodel->num_skins);
1175         numxyz = LittleLong(pinmodel->num_xyz);
1176         numst = LittleLong(pinmodel->num_st);
1177         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1178         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1179         loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1180         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1181         skinwidth = LittleLong(pinmodel->skinwidth);
1182         skinheight = LittleLong(pinmodel->skinheight);
1183         iskinwidth = 1.0f / skinwidth;
1184         iskinheight = 1.0f / skinheight;
1185
1186         loadmodel->num_surfaces = 1;
1187         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1188         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]));
1189         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1190         loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1191         loadmodel->surfacelist[0] = 0;
1192         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1193         loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1194         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1195         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1196
1197         loadmodel->synctype = ST_RAND;
1198
1199         // load the skins
1200         inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1201         skinfiles = Mod_LoadSkinFiles();
1202         if (skinfiles)
1203         {
1204                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1205                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1206                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1207                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1208                 Mod_FreeSkinFiles(skinfiles);
1209         }
1210         else if (loadmodel->numskins)
1211         {
1212                 // skins found (most likely not a player model)
1213                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1214                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1215                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1216                 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1217                         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);
1218         }
1219         else
1220         {
1221                 // no skins (most likely a player model)
1222                 loadmodel->numskins = 1;
1223                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1224                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1225                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1226                 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL);
1227         }
1228
1229         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1230         for (i = 0;i < loadmodel->numskins;i++)
1231         {
1232                 loadmodel->skinscenes[i].firstframe = i;
1233                 loadmodel->skinscenes[i].framecount = 1;
1234                 loadmodel->skinscenes[i].loop = true;
1235                 loadmodel->skinscenes[i].framerate = 10;
1236         }
1237
1238         // load the triangles and stvert data
1239         inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1240         intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1241         md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1242         md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1243         // swap the triangle list
1244         loadmodel->surfmesh.num_vertices = 0;
1245         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1246         {
1247                 for (j = 0;j < 3;j++)
1248                 {
1249                         xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1250                         st = (unsigned short) LittleShort (intri[i].index_st[j]);
1251                         if (xyz >= numxyz)
1252                         {
1253                                 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1254                                 xyz = 0;
1255                         }
1256                         if (st >= numst)
1257                         {
1258                                 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1259                                 st = 0;
1260                         }
1261                         hashindex = (xyz * 256 + st) & 65535;
1262                         for (hash = md2verthash[hashindex];hash;hash = hash->next)
1263                                 if (hash->xyz == xyz && hash->st == st)
1264                                         break;
1265                         if (hash == NULL)
1266                         {
1267                                 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1268                                 hash->xyz = xyz;
1269                                 hash->st = st;
1270                                 hash->next = md2verthash[hashindex];
1271                                 md2verthash[hashindex] = hash;
1272                         }
1273                         loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1274                 }
1275         }
1276
1277         vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1278         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));
1279         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1280         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1281         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1282         {
1283                 int sts, stt;
1284                 hash = md2verthashdata + i;
1285                 vertremap[i] = hash->xyz;
1286                 sts = LittleShort(inst[hash->st*2+0]);
1287                 stt = LittleShort(inst[hash->st*2+1]);
1288                 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1289                 {
1290                         Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1291                         sts = 0;
1292                         stt = 0;
1293                 }
1294                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1295                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1296         }
1297
1298         Mem_Free(md2verthash);
1299         Mem_Free(md2verthashdata);
1300
1301         // generate ushort elements array if possible
1302         if (loadmodel->surfmesh.num_vertices <= 65536)
1303         {
1304                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1305                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1306                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1307         }
1308
1309         // load the frames
1310         datapointer = (base + LittleLong(pinmodel->ofs_frames));
1311         for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1312         {
1313                 int k;
1314                 trivertx_t *v;
1315                 trivertx_t *out;
1316                 pinframe = (md2frame_t *)datapointer;
1317                 datapointer += sizeof(md2frame_t);
1318                 // store the frame scale/translate into the appropriate array
1319                 for (j = 0;j < 3;j++)
1320                 {
1321                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1322                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1323                 }
1324                 // convert the vertices
1325                 v = (trivertx_t *)datapointer;
1326                 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1327                 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1328                         out[k] = v[vertremap[k]];
1329                 datapointer += numxyz * sizeof(trivertx_t);
1330
1331                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1332                 loadmodel->animscenes[i].firstframe = i;
1333                 loadmodel->animscenes[i].framecount = 1;
1334                 loadmodel->animscenes[i].framerate = 10;
1335                 loadmodel->animscenes[i].loop = true;
1336         }
1337
1338         Mem_Free(vertremap);
1339
1340         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1341         Mod_Alias_CalculateBoundingBox();
1342         Mod_Alias_MorphMesh_CompileFrames();
1343
1344         surface = loadmodel->data_surfaces;
1345         surface->texture = loadmodel->data_textures;
1346         surface->num_firsttriangle = 0;
1347         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1348         surface->num_firstvertex = 0;
1349         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1350
1351         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1352 }
1353
1354 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1355 {
1356         int i, j, k, version, meshvertices, meshtriangles;
1357         unsigned char *data;
1358         msurface_t *surface;
1359         md3modelheader_t *pinmodel;
1360         md3frameinfo_t *pinframe;
1361         md3mesh_t *pinmesh;
1362         md3tag_t *pintag;
1363         skinfile_t *skinfiles;
1364
1365         pinmodel = (md3modelheader_t *)buffer;
1366
1367         if (memcmp(pinmodel->identifier, "IDP3", 4))
1368                 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1369         version = LittleLong (pinmodel->version);
1370         if (version != MD3VERSION)
1371                 Host_Error ("%s has wrong version number (%i should be %i)",
1372                         loadmodel->name, version, MD3VERSION);
1373
1374         skinfiles = Mod_LoadSkinFiles();
1375         if (loadmodel->numskins < 1)
1376                 loadmodel->numskins = 1;
1377
1378         loadmodel->modeldatatypestring = "MD3";
1379
1380         loadmodel->type = mod_alias;
1381         loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1382         loadmodel->DrawSky = NULL;
1383         loadmodel->DrawAddWaterPlanes = NULL;
1384         loadmodel->Draw = R_Q1BSP_Draw;
1385         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1386         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1387         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1388         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1389         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1390         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1391         loadmodel->PointSuperContents = NULL;
1392         loadmodel->synctype = ST_RAND;
1393         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1394         i = LittleLong (pinmodel->flags);
1395         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1396
1397         // set up some global info about the model
1398         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1399         loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1400
1401         // make skinscenes for the skins (no groups)
1402         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1403         for (i = 0;i < loadmodel->numskins;i++)
1404         {
1405                 loadmodel->skinscenes[i].firstframe = i;
1406                 loadmodel->skinscenes[i].framecount = 1;
1407                 loadmodel->skinscenes[i].loop = true;
1408                 loadmodel->skinscenes[i].framerate = 10;
1409         }
1410
1411         // load frameinfo
1412         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1413         for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1414         {
1415                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1416                 loadmodel->animscenes[i].firstframe = i;
1417                 loadmodel->animscenes[i].framecount = 1;
1418                 loadmodel->animscenes[i].framerate = 10;
1419                 loadmodel->animscenes[i].loop = true;
1420         }
1421
1422         // load tags
1423         loadmodel->num_tagframes = loadmodel->numframes;
1424         loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1425         loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1426         for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1427         {
1428                 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1429                 for (j = 0;j < 9;j++)
1430                         loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1431                 for (j = 0;j < 3;j++)
1432                         loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1433                 //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);
1434         }
1435
1436         // load meshes
1437         meshvertices = 0;
1438         meshtriangles = 0;
1439         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)))
1440         {
1441                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1442                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1443                 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1444                         Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1445                 meshvertices += LittleLong(pinmesh->num_vertices);
1446                 meshtriangles += LittleLong(pinmesh->num_triangles);
1447         }
1448
1449         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1450         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1451         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1452         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));
1453         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1454         loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1455         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1456         loadmodel->surfmesh.num_vertices = meshvertices;
1457         loadmodel->surfmesh.num_triangles = meshtriangles;
1458         loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1459         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1460         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1461         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1462         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1463         loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1464         if (meshvertices <= 65536)
1465         {
1466                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1467                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1468                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1469         }
1470
1471         meshvertices = 0;
1472         meshtriangles = 0;
1473         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)))
1474         {
1475                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1476                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1477                 loadmodel->surfacelist[i] = i;
1478                 surface = loadmodel->data_surfaces + i;
1479                 surface->texture = loadmodel->data_textures + i;
1480                 surface->num_firsttriangle = meshtriangles;
1481                 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1482                 surface->num_firstvertex = meshvertices;
1483                 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1484                 meshvertices += surface->num_vertices;
1485                 meshtriangles += surface->num_triangles;
1486
1487                 for (j = 0;j < surface->num_triangles * 3;j++)
1488                         loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1489                 for (j = 0;j < surface->num_vertices;j++)
1490                 {
1491                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1492                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1493                 }
1494                 for (j = 0;j < loadmodel->numframes;j++)
1495                 {
1496                         const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1497                         md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1498                         for (k = 0;k < surface->num_vertices;k++, in++, out++)
1499                         {
1500                                 out->origin[0] = LittleShort(in->origin[0]);
1501                                 out->origin[1] = LittleShort(in->origin[1]);
1502                                 out->origin[2] = LittleShort(in->origin[2]);
1503                                 out->pitch = in->pitch;
1504                                 out->yaw = in->yaw;
1505                         }
1506                 }
1507
1508                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1509
1510                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1511         }
1512         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1513         Mod_Alias_MorphMesh_CompileFrames();
1514         Mod_Alias_CalculateBoundingBox();
1515         Mod_FreeSkinFiles(skinfiles);
1516
1517         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1
1518              || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
1519 }
1520
1521 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1522 {
1523         zymtype1header_t *pinmodel, *pheader;
1524         unsigned char *pbase;
1525         int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1526         float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose;
1527         zymvertex_t *verts, *vertdata;
1528         zymscene_t *scene;
1529         zymbone_t *bone;
1530         char *shadername;
1531         skinfile_t *skinfiles;
1532         unsigned char *data;
1533         msurface_t *surface;
1534
1535         pinmodel = (zymtype1header_t *)buffer;
1536         pbase = (unsigned char *)buffer;
1537         if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1538                 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1539         if (BigLong(pinmodel->type) != 1)
1540                 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1541
1542         loadmodel->modeldatatypestring = "ZYM";
1543
1544         loadmodel->type = mod_alias;
1545         loadmodel->synctype = ST_RAND;
1546
1547         // byteswap header
1548         pheader = pinmodel;
1549         pheader->type = BigLong(pinmodel->type);
1550         pheader->filesize = BigLong(pinmodel->filesize);
1551         pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1552         pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1553         pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1554         pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1555         pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1556         pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1557         pheader->radius = BigFloat(pinmodel->radius);
1558         pheader->numverts = BigLong(pinmodel->numverts);
1559         pheader->numtris = BigLong(pinmodel->numtris);
1560         pheader->numshaders = BigLong(pinmodel->numshaders);
1561         pheader->numbones = BigLong(pinmodel->numbones);
1562         pheader->numscenes = BigLong(pinmodel->numscenes);
1563         pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1564         pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1565         pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1566         pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1567         pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1568         pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1569         pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1570         pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1571         pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1572         pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1573         pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1574         pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1575         pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1576         pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1577         pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1578         pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1579         pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1580         pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1581
1582         if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1583         {
1584                 Con_Printf("%s has no geometry\n", loadmodel->name);
1585                 return;
1586         }
1587         if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1588         {
1589                 Con_Printf("%s has no animations\n", loadmodel->name);
1590                 return;
1591         }
1592
1593         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1594         loadmodel->DrawSky = NULL;
1595         loadmodel->DrawAddWaterPlanes = NULL;
1596         loadmodel->Draw = R_Q1BSP_Draw;
1597         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1598         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1599         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1600         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1601         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1602         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1603         loadmodel->PointSuperContents = NULL;
1604
1605         loadmodel->numframes = pheader->numscenes;
1606         loadmodel->num_surfaces = pheader->numshaders;
1607
1608         skinfiles = Mod_LoadSkinFiles();
1609         if (loadmodel->numskins < 1)
1610                 loadmodel->numskins = 1;
1611
1612         // make skinscenes for the skins (no groups)
1613         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1614         for (i = 0;i < loadmodel->numskins;i++)
1615         {
1616                 loadmodel->skinscenes[i].firstframe = i;
1617                 loadmodel->skinscenes[i].framecount = 1;
1618                 loadmodel->skinscenes[i].loop = true;
1619                 loadmodel->skinscenes[i].framerate = 10;
1620         }
1621
1622         // model bbox
1623         modelradius = pheader->radius;
1624         for (i = 0;i < 3;i++)
1625         {
1626                 loadmodel->normalmins[i] = pheader->mins[i];
1627                 loadmodel->normalmaxs[i] = pheader->maxs[i];
1628                 loadmodel->rotatedmins[i] = -modelradius;
1629                 loadmodel->rotatedmaxs[i] = modelradius;
1630         }
1631         corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1632         corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1633         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1634         if (loadmodel->yawmaxs[0] > modelradius)
1635                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1636         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1637         loadmodel->yawmins[2] = loadmodel->normalmins[2];
1638         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1639         loadmodel->radius = modelradius;
1640         loadmodel->radius2 = modelradius * modelradius;
1641
1642         // go through the lumps, swapping things
1643
1644         //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1645         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1646         scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1647         numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1648         for (i = 0;i < pheader->numscenes;i++)
1649         {
1650                 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1651                 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1652                 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1653                 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1654                 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1655                 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1656                         Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1657                 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1658                         Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1659                 if (loadmodel->animscenes[i].framerate < 0)
1660                         Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1661                 scene++;
1662         }
1663
1664         //zymlump_t lump_bones; // zymbone_t bone[numbones];
1665         loadmodel->num_bones = pheader->numbones;
1666         loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, pheader->numbones * sizeof(aliasbone_t));
1667         bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1668         for (i = 0;i < pheader->numbones;i++)
1669         {
1670                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1671                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1672                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1673                 if (loadmodel->data_bones[i].parent >= i)
1674                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1675         }
1676
1677         //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1678         vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1679         bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1680         for (i = 0;i < pheader->numverts;i++)
1681         {
1682                 vertbonecounts[i] = BigLong(bonecount[i]);
1683                 if (vertbonecounts[i] != 1)
1684                         Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1685         }
1686
1687         loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]);
1688
1689         meshvertices = pheader->numverts;
1690         meshtriangles = pheader->numtris;
1691
1692         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1693         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1694         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1695         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]));
1696         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1697         loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1698         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1699         loadmodel->surfmesh.num_vertices = meshvertices;
1700         loadmodel->surfmesh.num_triangles = meshtriangles;
1701         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1702         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1703         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1704         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1705         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1706         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1707         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1708         loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += meshvertices * sizeof(int[4]);
1709         loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += meshvertices * sizeof(float[4]);
1710         loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]);
1711         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1712         if (loadmodel->surfmesh.num_vertices <= 65536)
1713         {
1714                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1715                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1716                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1717         }
1718
1719         //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1720         poses = (float *) (pheader->lump_poses.start + pbase);
1721         for (i = 0;i < pheader->lump_poses.length / 4;i++)
1722                 loadmodel->data_poses[i] = BigFloat(poses[i]);
1723
1724         //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
1725         verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
1726         vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
1727         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
1728         // (converting from weight-blending skeletal animation to
1729         //  deformation-based skeletal animation)
1730         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
1731         for (i = 0;i < loadmodel->num_bones;i++)
1732         {
1733                 const float *m = loadmodel->data_poses + i * 12;
1734                 if (loadmodel->data_bones[i].parent >= 0)
1735                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
1736                 else
1737                         for (k = 0;k < 12;k++)
1738                                 bonepose[12*i+k] = m[k];
1739         }
1740         for (j = 0;j < pheader->numverts;j++)
1741         {
1742                 // this format really should have had a per vertexweight weight value...
1743                 // but since it does not, the weighting is completely ignored and
1744                 // only one weight is allowed per vertex
1745                 int boneindex = BigLong(vertdata[j].bonenum);
1746                 const float *m = bonepose + 12 * boneindex;
1747                 float relativeorigin[3];
1748                 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
1749                 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
1750                 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
1751                 // transform the vertex bone weight into the base mesh
1752                 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
1753                 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
1754                 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
1755                 // store the weight as the primary weight on this vertex
1756                 loadmodel->surfmesh.data_vertexweightindex4i[j*4+0] = boneindex;
1757                 loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+0] = 1;
1758         }
1759         Z_Free(bonepose);
1760         // normals and tangents are calculated after elements are loaded
1761
1762         //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
1763         outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
1764         intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
1765         for (i = 0;i < pheader->numverts;i++)
1766         {
1767                 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
1768                 // flip T coordinate for OpenGL
1769                 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
1770         }
1771
1772         //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
1773         //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
1774         //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
1775
1776         //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
1777         //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)
1778         // byteswap, validate, and swap winding order of tris
1779         count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
1780         if (pheader->lump_render.length != count)
1781                 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
1782         renderlist = (int *) (pheader->lump_render.start + pbase);
1783         renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
1784         meshtriangles = 0;
1785         for (i = 0;i < loadmodel->num_surfaces;i++)
1786         {
1787                 int firstvertex, lastvertex;
1788                 if (renderlist >= renderlistend)
1789                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
1790                 count = BigLong(*renderlist);renderlist++;
1791                 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
1792                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
1793
1794                 loadmodel->surfacelist[i] = i;
1795                 surface = loadmodel->data_surfaces + i;
1796                 surface->texture = loadmodel->data_textures + i;
1797                 surface->num_firsttriangle = meshtriangles;
1798                 surface->num_triangles = count;
1799                 meshtriangles += surface->num_triangles;
1800
1801                 // load the elements
1802                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1803                 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
1804                 {
1805                         outelements[j*3+2] = BigLong(renderlist[0]);
1806                         outelements[j*3+1] = BigLong(renderlist[1]);
1807                         outelements[j*3+0] = BigLong(renderlist[2]);
1808                 }
1809                 // validate the elements and find the used vertex range
1810                 firstvertex = meshvertices;
1811                 lastvertex = 0;
1812                 for (j = 0;j < surface->num_triangles * 3;j++)
1813                 {
1814                         if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
1815                                 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
1816                         firstvertex = min(firstvertex, outelements[j]);
1817                         lastvertex = max(lastvertex, outelements[j]);
1818                 }
1819                 surface->num_firstvertex = firstvertex;
1820                 surface->num_vertices = lastvertex + 1 - firstvertex;
1821
1822                 // since zym models do not have named sections, reuse their shader
1823                 // name as the section name
1824                 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
1825                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
1826         }
1827         Mod_FreeSkinFiles(skinfiles);
1828         Mem_Free(vertbonecounts);
1829         Mem_Free(verts);
1830
1831         // compute all the mesh information that was not loaded from the file
1832         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
1833         Mod_BuildBaseBonePoses();
1834         Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true);
1835         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);
1836         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1837
1838         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1839 }
1840
1841 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1842 {
1843         dpmheader_t *pheader;
1844         dpmframe_t *frame;
1845         dpmbone_t *bone;
1846         dpmmesh_t *dpmmesh;
1847         unsigned char *pbase;
1848         int i, j, k, meshvertices, meshtriangles;
1849         skinfile_t *skinfiles;
1850         unsigned char *data;
1851         float *bonepose;
1852
1853         pheader = (dpmheader_t *)buffer;
1854         pbase = (unsigned char *)buffer;
1855         if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
1856                 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
1857         if (BigLong(pheader->type) != 2)
1858                 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1859
1860         loadmodel->modeldatatypestring = "DPM";
1861
1862         loadmodel->type = mod_alias;
1863         loadmodel->synctype = ST_RAND;
1864
1865         // byteswap header
1866         pheader->type = BigLong(pheader->type);
1867         pheader->filesize = BigLong(pheader->filesize);
1868         pheader->mins[0] = BigFloat(pheader->mins[0]);
1869         pheader->mins[1] = BigFloat(pheader->mins[1]);
1870         pheader->mins[2] = BigFloat(pheader->mins[2]);
1871         pheader->maxs[0] = BigFloat(pheader->maxs[0]);
1872         pheader->maxs[1] = BigFloat(pheader->maxs[1]);
1873         pheader->maxs[2] = BigFloat(pheader->maxs[2]);
1874         pheader->yawradius = BigFloat(pheader->yawradius);
1875         pheader->allradius = BigFloat(pheader->allradius);
1876         pheader->num_bones = BigLong(pheader->num_bones);
1877         pheader->num_meshs = BigLong(pheader->num_meshs);
1878         pheader->num_frames = BigLong(pheader->num_frames);
1879         pheader->ofs_bones = BigLong(pheader->ofs_bones);
1880         pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
1881         pheader->ofs_frames = BigLong(pheader->ofs_frames);
1882
1883         if (pheader->num_bones < 1 || pheader->num_meshs < 1)
1884         {
1885                 Con_Printf("%s has no geometry\n", loadmodel->name);
1886                 return;
1887         }
1888         if (pheader->num_frames < 1)
1889         {
1890                 Con_Printf("%s has no frames\n", loadmodel->name);
1891                 return;
1892         }
1893
1894         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1895         loadmodel->DrawSky = NULL;
1896         loadmodel->DrawAddWaterPlanes = NULL;
1897         loadmodel->Draw = R_Q1BSP_Draw;
1898         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1899         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1900         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1901         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1902         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1903         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1904         loadmodel->PointSuperContents = NULL;
1905
1906         // model bbox
1907         for (i = 0;i < 3;i++)
1908         {
1909                 loadmodel->normalmins[i] = pheader->mins[i];
1910                 loadmodel->normalmaxs[i] = pheader->maxs[i];
1911                 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
1912                 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
1913                 loadmodel->rotatedmins[i] = -pheader->allradius;
1914                 loadmodel->rotatedmaxs[i] = pheader->allradius;
1915         }
1916         loadmodel->radius = pheader->allradius;
1917         loadmodel->radius2 = pheader->allradius * pheader->allradius;
1918
1919         // load external .skin files if present
1920         skinfiles = Mod_LoadSkinFiles();
1921         if (loadmodel->numskins < 1)
1922                 loadmodel->numskins = 1;
1923
1924         meshvertices = 0;
1925         meshtriangles = 0;
1926
1927         // gather combined statistics from the meshes
1928         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
1929         for (i = 0;i < (int)pheader->num_meshs;i++)
1930         {
1931                 int numverts = BigLong(dpmmesh->num_verts);
1932                 meshvertices += numverts;
1933                 meshtriangles += BigLong(dpmmesh->num_tris);
1934                 dpmmesh++;
1935         }
1936
1937         loadmodel->numframes = pheader->num_frames;
1938         loadmodel->num_bones = pheader->num_bones;
1939         loadmodel->num_poses = loadmodel->num_bones * loadmodel->numframes;
1940         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
1941         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1942         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1943         // do most allocations as one merged chunk
1944         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));
1945         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1946         loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1947         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1948         loadmodel->surfmesh.num_vertices = meshvertices;
1949         loadmodel->surfmesh.num_triangles = meshtriangles;
1950         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1951         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1952         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1953         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1954         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1955         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1956         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1957         loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += meshvertices * sizeof(int[4]);
1958         loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += meshvertices * sizeof(float[4]);
1959         loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]);
1960         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1961         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
1962         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
1963         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1964         if (meshvertices <= 65536)
1965         {
1966                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1967                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1968                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1969         }
1970
1971         for (i = 0;i < loadmodel->numskins;i++)
1972         {
1973                 loadmodel->skinscenes[i].firstframe = i;
1974                 loadmodel->skinscenes[i].framecount = 1;
1975                 loadmodel->skinscenes[i].loop = true;
1976                 loadmodel->skinscenes[i].framerate = 10;
1977         }
1978
1979         // load the bone info
1980         bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
1981         for (i = 0;i < loadmodel->num_bones;i++)
1982         {
1983                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1984                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1985                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1986                 if (loadmodel->data_bones[i].parent >= i)
1987                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1988         }
1989
1990         // load the frames
1991         frame = (dpmframe_t *) (pbase + pheader->ofs_frames);
1992         for (i = 0;i < loadmodel->numframes;i++)
1993         {
1994                 const float *poses;
1995                 memcpy(loadmodel->animscenes[i].name, frame->name, sizeof(frame->name));
1996                 loadmodel->animscenes[i].firstframe = i;
1997                 loadmodel->animscenes[i].framecount = 1;
1998                 loadmodel->animscenes[i].loop = true;
1999                 loadmodel->animscenes[i].framerate = 10;
2000                 // load the bone poses for this frame
2001                 poses = (float *) (pbase + BigLong(frame->ofs_bonepositions));
2002                 for (j = 0;j < loadmodel->num_bones*12;j++)
2003                         loadmodel->data_poses[i * loadmodel->num_bones*12 + j] = BigFloat(poses[j]);
2004                 // stuff not processed here: mins, maxs, yawradius, allradius
2005                 frame++;
2006         }
2007
2008         // load the meshes now
2009         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2010         meshvertices = 0;
2011         meshtriangles = 0;
2012         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2013         // (converting from weight-blending skeletal animation to
2014         //  deformation-based skeletal animation)
2015         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2016         for (i = 0;i < loadmodel->num_bones;i++)
2017         {
2018                 const float *m = loadmodel->data_poses + i * 12;
2019                 if (loadmodel->data_bones[i].parent >= 0)
2020                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2021                 else
2022                         for (k = 0;k < 12;k++)
2023                                 bonepose[12*i+k] = m[k];
2024         }
2025         for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2026         {
2027                 const int *inelements;
2028                 int *outelements;
2029                 const float *intexcoord;
2030                 msurface_t *surface;
2031
2032                 loadmodel->surfacelist[i] = i;
2033                 surface = loadmodel->data_surfaces + i;
2034                 surface->texture = loadmodel->data_textures + i;
2035                 surface->num_firsttriangle = meshtriangles;
2036                 surface->num_triangles = BigLong(dpmmesh->num_tris);
2037                 surface->num_firstvertex = meshvertices;
2038                 surface->num_vertices = BigLong(dpmmesh->num_verts);
2039                 meshvertices += surface->num_vertices;
2040                 meshtriangles += surface->num_triangles;
2041
2042                 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2043                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2044                 for (j = 0;j < surface->num_triangles;j++)
2045                 {
2046                         // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2047                         outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2048                         outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2049                         outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2050                         inelements += 3;
2051                         outelements += 3;
2052                 }
2053
2054                 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2055                 for (j = 0;j < surface->num_vertices*2;j++)
2056                         loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2057
2058                 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2059                 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2060                 {
2061                         float sum;
2062                         int l;
2063                         int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2064                         data += sizeof(dpmvertex_t);
2065                         for (k = 0;k < numweights;k++)
2066                         {
2067                                 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2068                                 int boneindex = BigLong(vert->bonenum);
2069                                 const float *m = bonepose + 12 * boneindex;
2070                                 float influence = BigFloat(vert->influence);
2071                                 float relativeorigin[3], relativenormal[3];
2072                                 relativeorigin[0] = BigFloat(vert->origin[0]);
2073                                 relativeorigin[1] = BigFloat(vert->origin[1]);
2074                                 relativeorigin[2] = BigFloat(vert->origin[2]);
2075                                 relativenormal[0] = BigFloat(vert->normal[0]);
2076                                 relativenormal[1] = BigFloat(vert->normal[1]);
2077                                 relativenormal[2] = BigFloat(vert->normal[2]);
2078                                 // blend the vertex bone weights into the base mesh
2079                                 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2080                                 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2081                                 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2082                                 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2083                                 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2084                                 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2085                                 if (!k)
2086                                 {
2087                                         // store the first (and often only) weight
2088                                         loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+0] = influence;
2089                                         loadmodel->surfmesh.data_vertexweightindex4i[j*4+0] = boneindex;
2090                                 }
2091                                 else
2092                                 {
2093                                         // sort the new weight into this vertex's weight table
2094                                         // (which only accepts up to 4 bones per vertex)
2095                                         for (l = 0;l < 4;l++)
2096                                         {
2097                                                 if (loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] < influence)
2098                                                 {
2099                                                         // move weaker influence weights out of the way first
2100                                                         int l2;
2101                                                         for (l2 = 3;l2 > l;l2--)
2102                                                         {
2103                                                                 loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l2] = loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l2-1];
2104                                                                 loadmodel->surfmesh.data_vertexweightindex4i[j*4+l2] = loadmodel->surfmesh.data_vertexweightindex4i[j*4+l2-1];
2105                                                         }
2106                                                         // store the new weight
2107                                                         loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] = influence;
2108                                                         loadmodel->surfmesh.data_vertexweightindex4i[j*4+l] = boneindex;
2109                                                         break;
2110                                                 }
2111                                         }
2112                                 }
2113                                 data += sizeof(dpmbonevert_t);
2114                         }
2115                         sum = 0;
2116                         for (l = 0;l < 4;l++)
2117                                 sum += loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l];
2118                         if (sum && fabs(sum - 1) > (1.0f / 256.0f))
2119                         {
2120                                 float f = 1.0f / sum;
2121                                 for (l = 0;l < 4;l++)
2122                                         loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] *= f;
2123                         }
2124                 }
2125
2126                 // since dpm models do not have named sections, reuse their shader name as the section name
2127                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2128
2129                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2130         }
2131         Z_Free(bonepose);
2132         Mod_FreeSkinFiles(skinfiles);
2133
2134         // compute all the mesh information that was not loaded from the file
2135         Mod_BuildBaseBonePoses();
2136         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);
2137         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2138
2139         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
2140 }
2141
2142 // no idea why PSK/PSA files contain weird quaternions but they do...
2143 #define PSKQUATNEGATIONS
2144 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2145 {
2146         int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2147         int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2148         fs_offset_t filesize;
2149         pskpnts_t *pnts;
2150         pskvtxw_t *vtxw;
2151         pskface_t *faces;
2152         pskmatt_t *matts;
2153         pskboneinfo_t *bones;
2154         pskrawweights_t *rawweights;
2155         pskboneinfo_t *animbones;
2156         pskaniminfo_t *anims;
2157         pskanimkeys_t *animkeys;
2158         void *animfilebuffer, *animbuffer, *animbufferend;
2159         unsigned char *data;
2160         pskchunk_t *pchunk;
2161         skinfile_t *skinfiles;
2162         char animname[MAX_QPATH];
2163         size_t size;
2164
2165         pchunk = (pskchunk_t *)buffer;
2166         if (strcmp(pchunk->id, "ACTRHEAD"))
2167                 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2168
2169         loadmodel->modeldatatypestring = "PSK";
2170
2171         loadmodel->type = mod_alias;
2172         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2173         loadmodel->DrawSky = NULL;
2174         loadmodel->DrawAddWaterPlanes = NULL;
2175         loadmodel->Draw = R_Q1BSP_Draw;
2176         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2177         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2178         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2179         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2180         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2181         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2182         loadmodel->PointSuperContents = NULL;
2183         loadmodel->synctype = ST_RAND;
2184
2185         FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2186         strlcat(animname, ".psa", sizeof(animname));
2187         animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2188         animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2189         if (animbuffer == NULL)
2190                 Host_Error("%s: can't find .psa file (%s)", loadmodel->name, animname);
2191
2192         numpnts = 0;
2193         pnts = NULL;
2194         numvtxw = 0;
2195         vtxw = NULL;
2196         numfaces = 0;
2197         faces = NULL;
2198         nummatts = 0;
2199         matts = NULL;
2200         numbones = 0;
2201         bones = NULL;
2202         numrawweights = 0;
2203         rawweights = NULL;
2204         numanims = 0;
2205         anims = NULL;
2206         numanimkeys = 0;
2207         animkeys = NULL;
2208
2209         while (buffer < bufferend)
2210         {
2211                 pchunk = (pskchunk_t *)buffer;
2212                 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2213                 version = LittleLong(pchunk->version);
2214                 recordsize = LittleLong(pchunk->recordsize);
2215                 numrecords = LittleLong(pchunk->numrecords);
2216                 if (developer.integer >= 100)
2217                         Con_Printf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2218                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2219                         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);
2220                 if (!strcmp(pchunk->id, "ACTRHEAD"))
2221                 {
2222                         // nothing to do
2223                 }
2224                 else if (!strcmp(pchunk->id, "PNTS0000"))
2225                 {
2226                         pskpnts_t *p;
2227                         if (recordsize != sizeof(*p))
2228                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2229                         // byteswap in place and keep the pointer
2230                         numpnts = numrecords;
2231                         pnts = (pskpnts_t *)buffer;
2232                         for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2233                         {
2234                                 p->origin[0] = LittleFloat(p->origin[0]);
2235                                 p->origin[1] = LittleFloat(p->origin[1]);
2236                                 p->origin[2] = LittleFloat(p->origin[2]);
2237                         }
2238                         buffer = p;
2239                 }
2240                 else if (!strcmp(pchunk->id, "VTXW0000"))
2241                 {
2242                         pskvtxw_t *p;
2243                         if (recordsize != sizeof(*p))
2244                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2245                         // byteswap in place and keep the pointer
2246                         numvtxw = numrecords;
2247                         vtxw = (pskvtxw_t *)buffer;
2248                         for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2249                         {
2250                                 p->pntsindex = LittleShort(p->pntsindex);
2251                                 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2252                                 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2253                                 if (p->pntsindex >= numpnts)
2254                                 {
2255                                         Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2256                                         p->pntsindex = 0;
2257                                 }
2258                         }
2259                         buffer = p;
2260                 }
2261                 else if (!strcmp(pchunk->id, "FACE0000"))
2262                 {
2263                         pskface_t *p;
2264                         if (recordsize != sizeof(*p))
2265                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2266                         // byteswap in place and keep the pointer
2267                         numfaces = numrecords;
2268                         faces = (pskface_t *)buffer;
2269                         for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2270                         {
2271                                 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2272                                 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2273                                 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2274                                 p->group = LittleLong(p->group);
2275                                 if (p->vtxwindex[0] >= numvtxw)
2276                                 {
2277                                         Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2278                                         p->vtxwindex[0] = 0;
2279                                 }
2280                                 if (p->vtxwindex[1] >= numvtxw)
2281                                 {
2282                                         Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2283                                         p->vtxwindex[1] = 0;
2284                                 }
2285                                 if (p->vtxwindex[2] >= numvtxw)
2286                                 {
2287                                         Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2288                                         p->vtxwindex[2] = 0;
2289                                 }
2290                         }
2291                         buffer = p;
2292                 }
2293                 else if (!strcmp(pchunk->id, "MATT0000"))
2294                 {
2295                         pskmatt_t *p;
2296                         if (recordsize != sizeof(*p))
2297                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2298                         // byteswap in place and keep the pointer
2299                         nummatts = numrecords;
2300                         matts = (pskmatt_t *)buffer;
2301                         for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2302                         {
2303                                 // nothing to do
2304                         }
2305                         buffer = p;
2306                 }
2307                 else if (!strcmp(pchunk->id, "REFSKELT"))
2308                 {
2309                         pskboneinfo_t *p;
2310                         if (recordsize != sizeof(*p))
2311                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2312                         // byteswap in place and keep the pointer
2313                         numbones = numrecords;
2314                         bones = (pskboneinfo_t *)buffer;
2315                         for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2316                         {
2317                                 p->numchildren = LittleLong(p->numchildren);
2318                                 p->parent = LittleLong(p->parent);
2319                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2320                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2321                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2322                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2323                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2324                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2325                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2326                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2327                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2328                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2329                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2330 #ifdef PSKQUATNEGATIONS
2331                                 if (index)
2332                                 {
2333                                         p->basepose.quat[0] *= -1;
2334                                         p->basepose.quat[1] *= -1;
2335                                         p->basepose.quat[2] *= -1;
2336                                 }
2337                                 else
2338                                 {
2339                                         p->basepose.quat[0] *=  1;
2340                                         p->basepose.quat[1] *= -1;
2341                                         p->basepose.quat[2] *=  1;
2342                                 }
2343 #endif
2344                                 if (p->parent < 0 || p->parent >= numbones)
2345                                 {
2346                                         Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2347                                         p->parent = 0;
2348                                 }
2349                         }
2350                         buffer = p;
2351                 }
2352                 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2353                 {
2354                         pskrawweights_t *p;
2355                         if (recordsize != sizeof(*p))
2356                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2357                         // byteswap in place and keep the pointer
2358                         numrawweights = numrecords;
2359                         rawweights = (pskrawweights_t *)buffer;
2360                         for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2361                         {
2362                                 p->weight = LittleFloat(p->weight);
2363                                 p->pntsindex = LittleLong(p->pntsindex);
2364                                 p->boneindex = LittleLong(p->boneindex);
2365                                 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2366                                 {
2367                                         Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2368                                         p->pntsindex = 0;
2369                                 }
2370                                 if (p->boneindex < 0 || p->boneindex >= numbones)
2371                                 {
2372                                         Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2373                                         p->boneindex = 0;
2374                                 }
2375                         }
2376                         buffer = p;
2377                 }
2378         }
2379
2380         while (animbuffer < animbufferend)
2381         {
2382                 pchunk = (pskchunk_t *)animbuffer;
2383                 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2384                 version = LittleLong(pchunk->version);
2385                 recordsize = LittleLong(pchunk->recordsize);
2386                 numrecords = LittleLong(pchunk->numrecords);
2387                 if (developer.integer >= 100)
2388                         Con_Printf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2389                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2390                         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);
2391                 if (!strcmp(pchunk->id, "ANIMHEAD"))
2392                 {
2393                         // nothing to do
2394                 }
2395                 else if (!strcmp(pchunk->id, "BONENAMES"))
2396                 {
2397                         pskboneinfo_t *p;
2398                         if (recordsize != sizeof(*p))
2399                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2400                         // byteswap in place and keep the pointer
2401                         numanimbones = numrecords;
2402                         animbones = (pskboneinfo_t *)animbuffer;
2403                         // NOTE: supposedly psa does not need to match the psk model, the
2404                         // bones missing from the psa would simply use their base
2405                         // positions from the psk, but this is hard for me to implement
2406                         // and people can easily make animations that match.
2407                         if (numanimbones != numbones)
2408                                 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2409                         for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2410                         {
2411                                 p->numchildren = LittleLong(p->numchildren);
2412                                 p->parent = LittleLong(p->parent);
2413                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2414                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2415                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2416                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2417                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2418                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2419                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2420                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2421                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2422                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2423                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2424 #ifdef PSKQUATNEGATIONS
2425                                 if (index)
2426                                 {
2427                                         p->basepose.quat[0] *= -1;
2428                                         p->basepose.quat[1] *= -1;
2429                                         p->basepose.quat[2] *= -1;
2430                                 }
2431                                 else
2432                                 {
2433                                         p->basepose.quat[0] *=  1;
2434                                         p->basepose.quat[1] *= -1;
2435                                         p->basepose.quat[2] *=  1;
2436                                 }
2437 #endif
2438                                 if (p->parent < 0 || p->parent >= numanimbones)
2439                                 {
2440                                         Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2441                                         p->parent = 0;
2442                                 }
2443                                 // check that bones are the same as in the base
2444                                 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2445                                         Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2446                         }
2447                         animbuffer = p;
2448                 }
2449                 else if (!strcmp(pchunk->id, "ANIMINFO"))
2450                 {
2451                         pskaniminfo_t *p;
2452                         if (recordsize != sizeof(*p))
2453                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2454                         // byteswap in place and keep the pointer
2455                         numanims = numrecords;
2456                         anims = (pskaniminfo_t *)animbuffer;
2457                         for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2458                         {
2459                                 p->numbones = LittleLong(p->numbones);
2460                                 p->playtime = LittleFloat(p->playtime);
2461                                 p->fps = LittleFloat(p->fps);
2462                                 p->firstframe = LittleLong(p->firstframe);
2463                                 p->numframes = LittleLong(p->numframes);
2464                                 if (p->numbones != numbones)
2465                                         Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2466                         }
2467                         animbuffer = p;
2468                 }
2469                 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2470                 {
2471                         pskanimkeys_t *p;
2472                         if (recordsize != sizeof(*p))
2473                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2474                         numanimkeys = numrecords;
2475                         animkeys = (pskanimkeys_t *)animbuffer;
2476                         for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2477                         {
2478                                 p->origin[0] = LittleFloat(p->origin[0]);
2479                                 p->origin[1] = LittleFloat(p->origin[1]);
2480                                 p->origin[2] = LittleFloat(p->origin[2]);
2481                                 p->quat[0] = LittleFloat(p->quat[0]);
2482                                 p->quat[1] = LittleFloat(p->quat[1]);
2483                                 p->quat[2] = LittleFloat(p->quat[2]);
2484                                 p->quat[3] = LittleFloat(p->quat[3]);
2485                                 p->frametime = LittleFloat(p->frametime);
2486 #ifdef PSKQUATNEGATIONS
2487                                 if (index % numbones)
2488                                 {
2489                                         p->quat[0] *= -1;
2490                                         p->quat[1] *= -1;
2491                                         p->quat[2] *= -1;
2492                                 }
2493                                 else
2494                                 {
2495                                         p->quat[0] *=  1;
2496                                         p->quat[1] *= -1;
2497                                         p->quat[2] *=  1;
2498                                 }
2499 #endif
2500                         }
2501                         animbuffer = p;
2502                         // TODO: allocate bonepose stuff
2503                 }
2504                 else
2505                         Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2506         }
2507
2508         if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights || !numanims || !anims || !numanimkeys || !animkeys)
2509                 Host_Error("%s: missing required chunks", loadmodel->name);
2510
2511         loadmodel->numframes = 0;
2512         for (index = 0;index < numanims;index++)
2513                 loadmodel->numframes += anims[index].numframes;
2514
2515         if (numanimkeys != numbones * loadmodel->numframes)
2516                 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2517
2518         meshvertices = numvtxw;
2519         meshtriangles = numfaces;
2520
2521         // load external .skin files if present
2522         skinfiles = Mod_LoadSkinFiles();
2523         if (loadmodel->numskins < 1)
2524                 loadmodel->numskins = 1;
2525         loadmodel->num_bones = numbones;
2526         loadmodel->num_poses = loadmodel->num_bones * loadmodel->numframes;
2527         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2528         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2529         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2530         loadmodel->surfmesh.num_vertices = meshvertices;
2531         loadmodel->surfmesh.num_triangles = meshtriangles;
2532         // do most allocations as one merged chunk
2533         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);
2534         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2535         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2536         loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2537         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2538         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2539         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2540         loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2541         loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2542         loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2543         loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2544         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2545         loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += loadmodel->surfmesh.num_vertices * sizeof(int[4]);
2546         loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
2547         //loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]);
2548         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2549         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2550         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2551         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2552         if (loadmodel->surfmesh.num_vertices <= 65536)
2553         {
2554                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2555                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2556                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2557         }
2558         loadmodel->data_poses = Mem_Alloc(loadmodel->mempool, loadmodel->num_poses * sizeof(float[12]));
2559
2560         for (i = 0;i < loadmodel->numskins;i++)
2561         {
2562                 loadmodel->skinscenes[i].firstframe = i;
2563                 loadmodel->skinscenes[i].framecount = 1;
2564                 loadmodel->skinscenes[i].loop = true;
2565                 loadmodel->skinscenes[i].framerate = 10;
2566         }
2567
2568         // create surfaces
2569         for (index = 0, i = 0;index < nummatts;index++)
2570         {
2571                 // since psk models do not have named sections, reuse their shader name as the section name
2572                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2573                 loadmodel->surfacelist[index] = index;
2574                 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2575                 loadmodel->data_surfaces[index].num_firstvertex = 0;
2576                 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2577         }
2578
2579         // copy over the vertex locations and texcoords
2580         for (index = 0;index < numvtxw;index++)
2581         {
2582                 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2583                 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2584                 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2585                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2586                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
2587         }
2588
2589         // loading the faces is complicated because we need to sort them into surfaces by mattindex
2590         for (index = 0;index < numfaces;index++)
2591                 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
2592         for (index = 0, i = 0;index < nummatts;index++)
2593         {
2594                 loadmodel->data_surfaces[index].num_firsttriangle = i;
2595                 i += loadmodel->data_surfaces[index].num_triangles;
2596                 loadmodel->data_surfaces[index].num_triangles = 0;
2597         }
2598         for (index = 0;index < numfaces;index++)
2599         {
2600                 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
2601                 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
2602                 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
2603                 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
2604         }
2605
2606         // copy over the bones
2607         for (index = 0;index < numbones;index++)
2608         {
2609                 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
2610                 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
2611                 if (loadmodel->data_bones[index].parent >= index)
2612                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
2613         }
2614
2615         // sort the psk point weights into the vertex weight tables
2616         // (which only accept up to 4 bones per vertex)
2617         for (index = 0;index < numvtxw;index++)
2618         {
2619                 int l;
2620                 float sum;
2621                 for (j = 0;j < numrawweights;j++)
2622                 {
2623                         if (rawweights[j].pntsindex == vtxw[index].pntsindex)
2624                         {
2625                                 int boneindex = rawweights[j].boneindex;
2626                                 float influence = rawweights[j].weight;
2627                                 for (l = 0;l < 4;l++)
2628                                 {
2629                                         if (loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] < influence)
2630                                         {
2631                                                 // move lower influence weights out of the way first
2632                                                 int l2;
2633                                                 for (l2 = 3;l2 > l;l2--)
2634                                                 {
2635                                                         loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l2] = loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l2-1];
2636                                                         loadmodel->surfmesh.data_vertexweightindex4i[index*4+l2] = loadmodel->surfmesh.data_vertexweightindex4i[index*4+l2-1];
2637                                                 }
2638                                                 // store the new weight
2639                                                 loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] = influence;
2640                                                 loadmodel->surfmesh.data_vertexweightindex4i[index*4+l] = boneindex;
2641                                                 break;
2642                                         }
2643                                 }
2644                         }
2645                 }
2646                 sum = 0;
2647                 for (l = 0;l < 4;l++)
2648                         sum += loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l];
2649                 if (sum && fabs(sum - 1) > (1.0f / 256.0f))
2650                 {
2651                         float f = 1.0f / sum;
2652                         for (l = 0;l < 4;l++)
2653                                 loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] *= f;
2654                 }
2655         }
2656
2657         // set up the animscenes based on the anims
2658         for (index = 0, i = 0;index < numanims;index++)
2659         {
2660                 for (j = 0;j < anims[index].numframes;j++, i++)
2661                 {
2662                         dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
2663                         loadmodel->animscenes[i].firstframe = i;
2664                         loadmodel->animscenes[i].framecount = 1;
2665                         loadmodel->animscenes[i].loop = true;
2666                         loadmodel->animscenes[i].framerate = 10;
2667                 }
2668         }
2669
2670         // load the poses from the animkeys
2671         for (index = 0;index < numanimkeys;index++)
2672         {
2673                 pskanimkeys_t *k = animkeys + index;
2674                 matrix4x4_t matrix;
2675                 Matrix4x4_FromOriginQuat(&matrix, k->origin[0], k->origin[1], k->origin[2], k->quat[0], k->quat[1], k->quat[2], k->quat[3]);
2676                 Matrix4x4_ToArray12FloatD3D(&matrix, loadmodel->data_poses + index*12);
2677         }
2678         Mod_FreeSkinFiles(skinfiles);
2679         Mem_Free(animfilebuffer);
2680
2681         // compute all the mesh information that was not loaded from the file
2682         // TODO: honor smoothing groups somehow?
2683         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2684         Mod_BuildBaseBonePoses();
2685         Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true);
2686         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);
2687         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2688         Mod_Alias_CalculateBoundingBox();
2689
2690         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
2691 }
2692