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