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