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