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