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