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