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