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