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