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