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