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