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