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