]> icculus.org git repositories - divverent/darkplaces.git/blob - model_alias.c
support for %s_%i.skin files on alias models (I.E. progs/test.mdl_0.skin), which...
[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 void Mod_AliasInit (void)
26 {
27 }
28
29 static void Mod_CalcAliasModelBBoxes (void)
30 {
31         int vnum, meshnum;
32         float dist, yawradius, radius;
33         aliasmesh_t *mesh;
34         float *v;
35         VectorClear(loadmodel->normalmins);
36         VectorClear(loadmodel->normalmaxs);
37         yawradius = 0;
38         radius = 0;
39         for (meshnum = 0, mesh = loadmodel->alias.aliasdata_meshes;meshnum < loadmodel->alias.aliasnum_meshes;meshnum++, mesh++)
40         {
41                 for (vnum = 0, v = mesh->data_aliasvertex3f;vnum < mesh->num_vertices * mesh->num_frames;vnum++, v += 3)
42                 {
43                         if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
44                         if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
45                         if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
46                         if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
47                         if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
48                         if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
49                         dist = v[0] * v[0] + v[1] * v[1];
50                         if (yawradius < dist)
51                                 yawradius = dist;
52                         dist += v[2] * v[2];
53                         if (radius < dist)
54                                 radius = dist;
55                 }
56         }
57         radius = sqrt(radius);
58         yawradius = sqrt(yawradius);
59         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
60         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius;
61         loadmodel->yawmins[2] = loadmodel->normalmins[2];
62         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
63         loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
64         loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
65         loadmodel->radius = radius;
66         loadmodel->radius2 = radius * radius;
67 }
68
69 static void Mod_ConvertAliasVerts (int inverts, vec3_t scale, vec3_t translate, trivertx_t *v, float *out3f, int *vertremap)
70 {
71         int i, j;
72         vec3_t temp;
73         for (i = 0;i < inverts;i++)
74         {
75                 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
76                         continue;
77                 temp[0] = v[i].v[0] * scale[0] + translate[0];
78                 temp[1] = v[i].v[1] * scale[1] + translate[1];
79                 temp[2] = v[i].v[2] * scale[2] + translate[2];
80                 j = vertremap[i]; // not onseam
81                 if (j >= 0)
82                         VectorCopy(temp, out3f + j * 3);
83                 j = vertremap[i+inverts]; // onseam
84                 if (j >= 0)
85                         VectorCopy(temp, out3f + j * 3);
86         }
87 }
88
89 static void Mod_MDL_LoadFrames (qbyte* datapointer, int inverts, vec3_t scale, vec3_t translate, int *vertremap)
90 {
91         int i, f, pose, groupframes;
92         float interval;
93         daliasframetype_t *pframetype;
94         daliasframe_t *pinframe;
95         daliasgroup_t *group;
96         daliasinterval_t *intervals;
97         animscene_t *scene;
98         pose = 0;
99         scene = loadmodel->animscenes;
100         for (f = 0;f < loadmodel->numframes;f++)
101         {
102                 pframetype = (daliasframetype_t *)datapointer;
103                 datapointer += sizeof(daliasframetype_t);
104                 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
105                 {
106                         // a single frame is still treated as a group
107                         interval = 0.1f;
108                         groupframes = 1;
109                 }
110                 else
111                 {
112                         // read group header
113                         group = (daliasgroup_t *)datapointer;
114                         datapointer += sizeof(daliasgroup_t);
115                         groupframes = LittleLong (group->numframes);
116
117                         // intervals (time per frame)
118                         intervals = (daliasinterval_t *)datapointer;
119                         datapointer += sizeof(daliasinterval_t) * groupframes;
120
121                         interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
122                         if (interval < 0.01f)
123                                 Host_Error("Mod_MDL_LoadFrames: invalid interval");
124                 }
125
126                 // get scene name from first frame
127                 pinframe = (daliasframe_t *)datapointer;
128
129                 strcpy(scene->name, pinframe->name);
130                 scene->firstframe = pose;
131                 scene->framecount = groupframes;
132                 scene->framerate = 1.0f / interval;
133                 scene->loop = true;
134                 scene++;
135
136                 // read frames
137                 for (i = 0;i < groupframes;i++)
138                 {
139                         pinframe = (daliasframe_t *)datapointer;
140                         datapointer += sizeof(daliasframe_t);
141                         Mod_ConvertAliasVerts(inverts, scale, translate, (trivertx_t *)datapointer, loadmodel->alias.aliasdata_meshes->data_aliasvertex3f + pose * loadmodel->alias.aliasdata_meshes->num_vertices * 3, vertremap);
142                         Mod_BuildTextureVectorsAndNormals(loadmodel->alias.aliasdata_meshes->num_vertices, loadmodel->alias.aliasdata_meshes->num_triangles, loadmodel->alias.aliasdata_meshes->data_aliasvertex3f + pose * loadmodel->alias.aliasdata_meshes->num_vertices * 3, loadmodel->alias.aliasdata_meshes->data_texcoord2f, loadmodel->alias.aliasdata_meshes->data_element3i, loadmodel->alias.aliasdata_meshes->data_aliassvector3f + pose * loadmodel->alias.aliasdata_meshes->num_vertices * 3, loadmodel->alias.aliasdata_meshes->data_aliastvector3f + pose * loadmodel->alias.aliasdata_meshes->num_vertices * 3, loadmodel->alias.aliasdata_meshes->data_aliasnormal3f + pose * loadmodel->alias.aliasdata_meshes->num_vertices * 3);
143                         datapointer += sizeof(trivertx_t) * inverts;
144                         pose++;
145                 }
146         }
147 }
148
149 aliaslayer_t mod_alias_layersbuffer[16]; // 7 currently used
150 void Mod_BuildAliasSkinFromSkinFrame(aliasskin_t *skin, skinframe_t *skinframe)
151 {
152         aliaslayer_t *layer;
153
154         memset(&mod_alias_layersbuffer, 0, sizeof(mod_alias_layersbuffer));
155         layer = mod_alias_layersbuffer;
156         layer->flags = ALIASLAYER_SPECULAR;
157         layer->texture = skinframe->gloss;
158         layer->nmap = skinframe->nmap;
159         layer++;
160         if (skinframe->merged != NULL)
161         {
162                 layer->flags = ALIASLAYER_DIFFUSE | ALIASLAYER_NODRAW_IF_COLORMAPPED;
163                 layer->texture = skinframe->merged;
164                 layer->nmap = skinframe->nmap;
165                 layer++;
166         }
167         if (skinframe->base != NULL)
168         {
169                 layer->flags = ALIASLAYER_DIFFUSE;
170                 if (skinframe->merged != NULL)
171                         layer->flags |= ALIASLAYER_NODRAW_IF_NOTCOLORMAPPED;
172                 layer->texture = skinframe->base;
173                 layer->nmap = skinframe->nmap;
174                 layer++;
175         }
176         if (skinframe->pants != NULL)
177         {
178                 layer->flags = ALIASLAYER_DIFFUSE | ALIASLAYER_NODRAW_IF_NOTCOLORMAPPED | ALIASLAYER_COLORMAP_PANTS;
179                 layer->texture = skinframe->pants;
180                 layer->nmap = skinframe->nmap;
181                 layer++;
182         }
183         if (skinframe->shirt != NULL)
184         {
185                 layer->flags = ALIASLAYER_DIFFUSE | ALIASLAYER_NODRAW_IF_NOTCOLORMAPPED | ALIASLAYER_COLORMAP_SHIRT;
186                 layer->texture = skinframe->shirt;
187                 layer->nmap = skinframe->nmap;
188                 layer++;
189         }
190
191         if (skinframe->glow != NULL)
192         {
193                 layer->flags = 0;
194                 layer->texture = skinframe->glow;
195                 layer++;
196         }
197
198         layer->flags = ALIASLAYER_FOG | ALIASLAYER_FORCEDRAW_IF_FIRSTPASS;
199         layer->texture = skinframe->fog;
200         layer++;
201
202         skin->flags = 0;
203         // fog texture only exists if some pixels are transparent...
204         if (skinframe->fog != NULL)
205                 skin->flags |= ALIASSKIN_TRANSPARENT;
206
207         skin->num_layers = layer - mod_alias_layersbuffer;
208         skin->data_layers = Mem_Alloc(loadmodel->mempool, skin->num_layers * sizeof(aliaslayer_t));
209         memcpy(skin->data_layers, mod_alias_layersbuffer, skin->num_layers * sizeof(aliaslayer_t));
210 }
211
212 void Mod_BuildAliasSkinsFromSkinFiles(aliasskin_t *skin, skinfile_t *skinfile, char *name)
213 {
214         int i;
215         skinfileitem_t *skinfileitem;
216         skinframe_t tempskinframe;
217         if (skinfile)
218         {
219                 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin++)
220                 {
221                         for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
222                         {
223                                 if (!strcmp(skinfileitem->name, name))
224                                 {
225                                         memset(&tempskinframe, 0, sizeof(tempskinframe));
226                                         Mod_LoadSkinFrame(&tempskinframe, skinfileitem->replacement, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_CLAMP | TEXF_PRECACHE, true, false, true);
227                                         Mod_BuildAliasSkinFromSkinFrame(skin, &tempskinframe);
228                                         break;
229                                 }
230                         }
231                 }
232         }
233         else
234         {
235                 Mod_LoadSkinFrame(&tempskinframe, name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_CLAMP | TEXF_PRECACHE, true, false, true);
236                 Mod_BuildAliasSkinFromSkinFrame(skin, &tempskinframe);
237         }
238 }
239
240 #define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)\n", loadmodel->name, VALUE, MIN, MAX);
241 #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)\n", loadmodel->name, VALUE, MIN, MAX);
242 extern void R_Model_Alias_Draw(entity_render_t *ent);
243 extern void R_Model_Alias_DrawFakeShadow(entity_render_t *ent);
244 extern void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
245 extern void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
246 void Mod_IDP0_Load(model_t *mod, void *buffer)
247 {
248         int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
249         float scales, scalet, scale[3], translate[3], interval;
250         mdl_t *pinmodel;
251         stvert_t *pinstverts;
252         dtriangle_t *pintriangles;
253         daliasskintype_t *pinskintype;
254         daliasskingroup_t *pinskingroup;
255         daliasskininterval_t *pinskinintervals;
256         daliasframetype_t *pinframetype;
257         daliasgroup_t *pinframegroup;
258         qbyte *datapointer, *startframes, *startskins;
259         char name[MAX_QPATH];
260         skinframe_t tempskinframe;
261         animscene_t *tempskinscenes;
262         aliasskin_t *tempaliasskins;
263         float *vertst;
264         int *vertonseam, *vertremap;
265         skinfile_t *skinfiles;
266
267         datapointer = buffer;
268         pinmodel = (mdl_t *)datapointer;
269         datapointer += sizeof(mdl_t);
270
271         version = LittleLong (pinmodel->version);
272         if (version != ALIAS_VERSION)
273                 Host_Error ("%s has wrong version number (%i should be %i)",
274                                  loadmodel->name, version, ALIAS_VERSION);
275
276         loadmodel->type = mod_alias;
277         loadmodel->alias.aliastype = ALIASTYPE_ALIAS;
278         loadmodel->DrawSky = NULL;
279         loadmodel->Draw = R_Model_Alias_Draw;
280         loadmodel->DrawFakeShadow = R_Model_Alias_DrawFakeShadow;
281         loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume;
282         loadmodel->DrawLight = R_Model_Alias_DrawLight;
283
284         loadmodel->alias.aliasnum_meshes = 1;
285         loadmodel->alias.aliasdata_meshes = Mem_Alloc(loadmodel->mempool, sizeof(aliasmesh_t));
286
287         loadmodel->numskins = LittleLong(pinmodel->numskins);
288         BOUNDI(loadmodel->numskins,0,256);
289         skinwidth = LittleLong (pinmodel->skinwidth);
290         BOUNDI(skinwidth,0,4096);
291         skinheight = LittleLong (pinmodel->skinheight);
292         BOUNDI(skinheight,0,4096);
293         numverts = LittleLong(pinmodel->numverts);
294         BOUNDI(numverts,0,65536);
295         loadmodel->alias.aliasdata_meshes->num_triangles = LittleLong(pinmodel->numtris);
296         BOUNDI(loadmodel->alias.aliasdata_meshes->num_triangles,0,65536 / 3); // max elements limit, rather than max triangles limit
297         loadmodel->numframes = LittleLong(pinmodel->numframes);
298         BOUNDI(loadmodel->numframes,0,65536);
299         loadmodel->synctype = LittleLong (pinmodel->synctype);
300         BOUNDI(loadmodel->synctype,0,2);
301         loadmodel->flags = LittleLong (pinmodel->flags);
302
303         for (i = 0;i < 3;i++)
304         {
305                 scale[i] = LittleFloat (pinmodel->scale[i]);
306                 translate[i] = LittleFloat (pinmodel->scale_origin[i]);
307         }
308
309         startskins = datapointer;
310         totalskins = 0;
311         for (i = 0;i < loadmodel->numskins;i++)
312         {
313                 pinskintype = (daliasskintype_t *)datapointer;
314                 datapointer += sizeof(daliasskintype_t);
315                 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
316                         groupskins = 1;
317                 else
318                 {
319                         pinskingroup = (daliasskingroup_t *)datapointer;
320                         datapointer += sizeof(daliasskingroup_t);
321                         groupskins = LittleLong(pinskingroup->numskins);
322                         datapointer += sizeof(daliasskininterval_t) * groupskins;
323                 }
324
325                 for (j = 0;j < groupskins;j++)
326                 {
327                         datapointer += skinwidth * skinheight;
328                         totalskins++;
329                 }
330         }
331
332         pinstverts = (stvert_t *)datapointer;
333         datapointer += sizeof(stvert_t) * numverts;
334
335         pintriangles = (dtriangle_t *)datapointer;
336         datapointer += sizeof(dtriangle_t) * loadmodel->alias.aliasdata_meshes->num_triangles;
337
338         startframes = datapointer;
339         loadmodel->alias.aliasdata_meshes->num_frames = 0;
340         for (i = 0;i < loadmodel->numframes;i++)
341         {
342                 pinframetype = (daliasframetype_t *)datapointer;
343                 datapointer += sizeof(daliasframetype_t);
344                 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
345                         groupframes = 1;
346                 else
347                 {
348                         pinframegroup = (daliasgroup_t *)datapointer;
349                         datapointer += sizeof(daliasgroup_t);
350                         groupframes = LittleLong(pinframegroup->numframes);
351                         datapointer += sizeof(daliasinterval_t) * groupframes;
352                 }
353
354                 for (j = 0;j < groupframes;j++)
355                 {
356                         datapointer += sizeof(daliasframe_t);
357                         datapointer += sizeof(trivertx_t) * numverts;
358                         loadmodel->alias.aliasdata_meshes->num_frames++;
359                 }
360         }
361
362         // store texture coordinates into temporary array, they will be stored
363         // after usage is determined (triangle data)
364         vertst = Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
365         vertremap = Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
366         vertonseam = vertremap + numverts * 2;
367
368         scales = 1.0 / skinwidth;
369         scalet = 1.0 / skinheight;
370         for (i = 0;i < numverts;i++)
371         {
372                 vertonseam[i] = LittleLong(pinstverts[i].onseam);
373                 vertst[i*2+0] = (LittleLong(pinstverts[i].s) + 0.5) * scales;
374                 vertst[i*2+1] = (LittleLong(pinstverts[i].t) + 0.5) * scalet;
375                 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
376                 vertst[(i+numverts)*2+1] = vertst[i*2+1];
377         }
378
379 // load triangle data
380         loadmodel->alias.aliasdata_meshes->data_element3i = Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->alias.aliasdata_meshes->num_triangles);
381
382         // read the triangle elements
383         for (i = 0;i < loadmodel->alias.aliasdata_meshes->num_triangles;i++)
384                 for (j = 0;j < 3;j++)
385                         loadmodel->alias.aliasdata_meshes->data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
386         // validate (note numverts is used because this is the original data)
387         Mod_ValidateElements(loadmodel->alias.aliasdata_meshes->data_element3i, loadmodel->alias.aliasdata_meshes->num_triangles, numverts, __FILE__, __LINE__);
388         // now butcher the elements according to vertonseam and tri->facesfront
389         // and then compact the vertex set to remove duplicates
390         for (i = 0;i < loadmodel->alias.aliasdata_meshes->num_triangles;i++)
391                 if (!LittleLong(pintriangles[i].facesfront)) // backface
392                         for (j = 0;j < 3;j++)
393                                 if (vertonseam[loadmodel->alias.aliasdata_meshes->data_element3i[i*3+j]])
394                                         loadmodel->alias.aliasdata_meshes->data_element3i[i*3+j] += numverts;
395         // count the usage
396         // (this uses vertremap to count usage to save some memory)
397         for (i = 0;i < numverts*2;i++)
398                 vertremap[i] = 0;
399         for (i = 0;i < loadmodel->alias.aliasdata_meshes->num_triangles*3;i++)
400                 vertremap[loadmodel->alias.aliasdata_meshes->data_element3i[i]]++;
401         // build remapping table and compact array
402         loadmodel->alias.aliasdata_meshes->num_vertices = 0;
403         for (i = 0;i < numverts*2;i++)
404         {
405                 if (vertremap[i])
406                 {
407                         vertremap[i] = loadmodel->alias.aliasdata_meshes->num_vertices;
408                         vertst[loadmodel->alias.aliasdata_meshes->num_vertices*2+0] = vertst[i*2+0];
409                         vertst[loadmodel->alias.aliasdata_meshes->num_vertices*2+1] = vertst[i*2+1];
410                         loadmodel->alias.aliasdata_meshes->num_vertices++;
411                 }
412                 else
413                         vertremap[i] = -1; // not used at all
414         }
415         // remap the elements to the new vertex set
416         for (i = 0;i < loadmodel->alias.aliasdata_meshes->num_triangles * 3;i++)
417                 loadmodel->alias.aliasdata_meshes->data_element3i[i] = vertremap[loadmodel->alias.aliasdata_meshes->data_element3i[i]];
418         // store the texture coordinates
419         loadmodel->alias.aliasdata_meshes->data_texcoord2f = Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->alias.aliasdata_meshes->num_vertices);
420         for (i = 0;i < loadmodel->alias.aliasdata_meshes->num_vertices;i++)
421         {
422                 loadmodel->alias.aliasdata_meshes->data_texcoord2f[i*2+0] = vertst[i*2+0];
423                 loadmodel->alias.aliasdata_meshes->data_texcoord2f[i*2+1] = vertst[i*2+1];
424         }
425
426 // load the frames
427         loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
428         loadmodel->alias.aliasdata_meshes->data_aliasvertex3f = Mem_Alloc(loadmodel->mempool, sizeof(float[4][3]) * loadmodel->alias.aliasdata_meshes->num_frames * loadmodel->alias.aliasdata_meshes->num_vertices);
429         loadmodel->alias.aliasdata_meshes->data_aliassvector3f = loadmodel->alias.aliasdata_meshes->data_aliasvertex3f + loadmodel->alias.aliasdata_meshes->num_frames * loadmodel->alias.aliasdata_meshes->num_vertices * 3 * 1;
430         loadmodel->alias.aliasdata_meshes->data_aliastvector3f = loadmodel->alias.aliasdata_meshes->data_aliasvertex3f + loadmodel->alias.aliasdata_meshes->num_frames * loadmodel->alias.aliasdata_meshes->num_vertices * 3 * 2;
431         loadmodel->alias.aliasdata_meshes->data_aliasnormal3f = loadmodel->alias.aliasdata_meshes->data_aliasvertex3f + loadmodel->alias.aliasdata_meshes->num_frames * loadmodel->alias.aliasdata_meshes->num_vertices * 3 * 3;
432         Mod_MDL_LoadFrames (startframes, numverts, scale, translate, vertremap);
433         loadmodel->alias.aliasdata_meshes->data_neighbor3i = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_triangles * sizeof(int[3]));
434         Mod_BuildTriangleNeighbors(loadmodel->alias.aliasdata_meshes->data_neighbor3i, loadmodel->alias.aliasdata_meshes->data_element3i, loadmodel->alias.aliasdata_meshes->num_triangles);
435         Mod_CalcAliasModelBBoxes();
436
437         Mem_Free(vertst);
438         Mem_Free(vertremap);
439
440         // load the skins
441         if ((skinfiles = Mod_LoadSkinFiles()))
442         {
443                 loadmodel->alias.aliasdata_meshes->num_skins = totalskins = loadmodel->numskins = Mod_CountSkinFiles(skinfiles);
444                 loadmodel->alias.aliasdata_meshes->data_skins = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_skins * sizeof(aliasskin_t));
445                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->alias.aliasdata_meshes->data_skins, skinfiles, "default");
446                 Mod_FreeSkinFiles(skinfiles);
447                 loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
448                 for (i = 0;i < loadmodel->numskins;i++)
449                 {
450                         loadmodel->skinscenes[i].firstframe = i;
451                         loadmodel->skinscenes[i].framecount = 1;
452                         loadmodel->skinscenes[i].loop = true;
453                         loadmodel->skinscenes[i].framerate = 10;
454                 }
455         }
456         else
457         {
458                 loadmodel->alias.aliasdata_meshes->num_skins = totalskins;
459                 loadmodel->alias.aliasdata_meshes->data_skins = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_skins * sizeof(aliasskin_t));
460                 loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
461                 totalskins = 0;
462                 datapointer = startskins;
463                 for (i = 0;i < loadmodel->numskins;i++)
464                 {
465                         pinskintype = (daliasskintype_t *)datapointer;
466                         datapointer += sizeof(daliasskintype_t);
467
468                         if (pinskintype->type == ALIAS_SKIN_SINGLE)
469                         {
470                                 groupskins = 1;
471                                 interval = 0.1f;
472                         }
473                         else
474                         {
475                                 pinskingroup = (daliasskingroup_t *)datapointer;
476                                 datapointer += sizeof(daliasskingroup_t);
477
478                                 groupskins = LittleLong (pinskingroup->numskins);
479
480                                 pinskinintervals = (daliasskininterval_t *)datapointer;
481                                 datapointer += sizeof(daliasskininterval_t) * groupskins;
482
483                                 interval = LittleFloat(pinskinintervals[0].interval);
484                                 if (interval < 0.01f)
485                                         Host_Error("Mod_IDP0_Load: invalid interval\n");
486                         }
487
488                         sprintf(loadmodel->skinscenes[i].name, "skin %i", i);
489                         loadmodel->skinscenes[i].firstframe = totalskins;
490                         loadmodel->skinscenes[i].framecount = groupskins;
491                         loadmodel->skinscenes[i].framerate = 1.0f / interval;
492                         loadmodel->skinscenes[i].loop = true;
493
494                         for (j = 0;j < groupskins;j++)
495                         {
496                                 if (groupskins > 1)
497                                         sprintf (name, "%s_%i_%i", loadmodel->name, i, j);
498                                 else
499                                         sprintf (name, "%s_%i", loadmodel->name, i);
500                                 if (!Mod_LoadSkinFrame(&tempskinframe, name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_CLAMP | TEXF_ALPHA, true, false, true))
501                                         Mod_LoadSkinFrame_Internal(&tempskinframe, name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_CLAMP | TEXF_ALPHA, true, false, true, (qbyte *)datapointer, skinwidth, skinheight);
502                                 Mod_BuildAliasSkinFromSkinFrame(loadmodel->alias.aliasdata_meshes->data_skins + totalskins, &tempskinframe);
503                                 datapointer += skinwidth * skinheight;
504                                 totalskins++;
505                         }
506                 }
507                 // check for skins that don't exist in the model, but do exist as external images
508                 // (this was added because yummyluv kept pestering me about support for it)
509                 while (Mod_LoadSkinFrame(&tempskinframe, va("%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_CLAMP | TEXF_ALPHA, true, false, true))
510                 {
511                         // expand the arrays to make room
512                         tempskinscenes = loadmodel->skinscenes;
513                         loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
514                         memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
515                         Mem_Free(tempskinscenes);
516
517                         tempaliasskins = loadmodel->alias.aliasdata_meshes->data_skins;
518                         loadmodel->alias.aliasdata_meshes->data_skins = Mem_Alloc(loadmodel->mempool, (totalskins + 1) * sizeof(aliasskin_t));
519                         memcpy(loadmodel->alias.aliasdata_meshes->data_skins, tempaliasskins, totalskins * sizeof(aliasskin_t));
520                         Mem_Free(tempaliasskins);
521
522                         // store the info about the new skin
523                         Mod_BuildAliasSkinFromSkinFrame(loadmodel->alias.aliasdata_meshes->data_skins + totalskins, &tempskinframe);
524                         strcpy(loadmodel->skinscenes[loadmodel->numskins].name, name);
525                         loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
526                         loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
527                         loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
528                         loadmodel->skinscenes[loadmodel->numskins].loop = true;
529
530                         //increase skin counts
531                         loadmodel->alias.aliasdata_meshes->num_skins++;
532                         loadmodel->numskins++;
533                         totalskins++;
534                 }
535         }
536 }
537
538 static void Mod_MD2_ConvertVerts (vec3_t scale, vec3_t translate, trivertx_t *v, float *out3f, int numverts, int *vertremap)
539 {
540         int i;
541         trivertx_t *in;
542         for (i = 0;i < numverts;i++, out3f += 3)
543         {
544                 in = v + vertremap[i];
545                 out3f[0] = in->v[0] * scale[0] + translate[0];
546                 out3f[1] = in->v[1] * scale[1] + translate[1];
547                 out3f[2] = in->v[2] * scale[2] + translate[2];
548         }
549 }
550
551 void Mod_IDP2_Load(model_t *mod, void *buffer)
552 {
553         int i, j, k, hashindex, num, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end, numverts;
554         float *stverts, s, t, scale[3], translate[3];
555         md2_t *pinmodel;
556         qbyte *base, *datapointer;
557         md2frame_t *pinframe;
558         char *inskin;
559         md2triangle_t *intri;
560         unsigned short *inst;
561         struct md2verthash_s
562         {
563                 struct md2verthash_s *next;
564                 int xyz;
565                 float st[2];
566         }
567         *hash, **md2verthash, *md2verthashdata;
568         skinframe_t tempskinframe;
569         skinfile_t *skinfiles;
570
571         pinmodel = buffer;
572         base = buffer;
573
574         version = LittleLong (pinmodel->version);
575         if (version != MD2ALIAS_VERSION)
576                 Host_Error ("%s has wrong version number (%i should be %i)",
577                         loadmodel->name, version, MD2ALIAS_VERSION);
578
579         loadmodel->type = mod_alias;
580         loadmodel->alias.aliastype = ALIASTYPE_ALIAS;
581         loadmodel->DrawSky = NULL;
582         loadmodel->Draw = R_Model_Alias_Draw;
583         loadmodel->DrawFakeShadow = R_Model_Alias_DrawFakeShadow;
584         loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume;
585         loadmodel->DrawLight = R_Model_Alias_DrawLight;
586
587         if (LittleLong(pinmodel->num_tris < 1) || LittleLong(pinmodel->num_tris) > (65536 / 3))
588                 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
589         if (LittleLong(pinmodel->num_xyz < 1) || LittleLong(pinmodel->num_xyz) > 65536)
590                 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
591         if (LittleLong(pinmodel->num_frames < 1) || LittleLong(pinmodel->num_frames) > 65536)
592                 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
593         if (LittleLong(pinmodel->num_skins < 0) || LittleLong(pinmodel->num_skins) > 256)
594                 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
595
596         end = LittleLong(pinmodel->ofs_end);
597         if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins <= 0) || LittleLong(pinmodel->ofs_skins) >= end))
598                 Host_Error ("%s is not a valid model", loadmodel->name);
599         if (LittleLong(pinmodel->ofs_st <= 0) || LittleLong(pinmodel->ofs_st) >= end)
600                 Host_Error ("%s is not a valid model", loadmodel->name);
601         if (LittleLong(pinmodel->ofs_tris <= 0) || LittleLong(pinmodel->ofs_tris) >= end)
602                 Host_Error ("%s is not a valid model", loadmodel->name);
603         if (LittleLong(pinmodel->ofs_frames <= 0) || LittleLong(pinmodel->ofs_frames) >= end)
604                 Host_Error ("%s is not a valid model", loadmodel->name);
605         if (LittleLong(pinmodel->ofs_glcmds <= 0) || LittleLong(pinmodel->ofs_glcmds) >= end)
606                 Host_Error ("%s is not a valid model", loadmodel->name);
607
608         loadmodel->alias.aliasnum_meshes = 1;
609         loadmodel->alias.aliasdata_meshes = Mem_Alloc(loadmodel->mempool, sizeof(aliasmesh_t));
610
611         loadmodel->numskins = LittleLong(pinmodel->num_skins);
612         numxyz = LittleLong(pinmodel->num_xyz);
613         numst = LittleLong(pinmodel->num_st);
614         loadmodel->alias.aliasdata_meshes->num_triangles = LittleLong(pinmodel->num_tris);
615         loadmodel->numframes = LittleLong(pinmodel->num_frames);
616         loadmodel->alias.aliasdata_meshes->num_frames = loadmodel->numframes;
617         loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
618
619         loadmodel->flags = 0; // there are no MD2 flags
620         loadmodel->synctype = ST_RAND;
621
622         // load the skins
623         inskin = (void*)(base + LittleLong(pinmodel->ofs_skins));
624         if ((skinfiles = Mod_LoadSkinFiles()))
625         {
626                 loadmodel->alias.aliasdata_meshes->num_skins = loadmodel->numskins = Mod_CountSkinFiles(skinfiles);
627                 loadmodel->alias.aliasdata_meshes->data_skins = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_skins * sizeof(aliasskin_t));
628                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->alias.aliasdata_meshes->data_skins, skinfiles, "default");
629                 Mod_FreeSkinFiles(skinfiles);
630         }
631         else if (loadmodel->numskins)
632         {
633                 // skins found (most likely not a player model)
634                 loadmodel->alias.aliasdata_meshes->num_skins = loadmodel->numskins;
635                 loadmodel->alias.aliasdata_meshes->data_skins = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_skins * sizeof(aliasskin_t));
636                 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
637                 {
638                         Mod_LoadSkinFrame(&tempskinframe, inskin, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_CLAMP | TEXF_PRECACHE, true, false, true);
639                         Mod_BuildAliasSkinFromSkinFrame(loadmodel->alias.aliasdata_meshes->data_skins + i, &tempskinframe);
640                 }
641         }
642         else
643         {
644                 // no skins (most likely a player model)
645                 loadmodel->numskins = 1;
646                 loadmodel->alias.aliasdata_meshes->num_skins = loadmodel->numskins;
647                 loadmodel->alias.aliasdata_meshes->data_skins = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_skins * sizeof(aliasskin_t));
648         }
649
650         loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
651         for (i = 0;i < loadmodel->numskins;i++)
652         {
653                 loadmodel->skinscenes[i].firstframe = i;
654                 loadmodel->skinscenes[i].framecount = 1;
655                 loadmodel->skinscenes[i].loop = true;
656                 loadmodel->skinscenes[i].framerate = 10;
657         }
658
659         // load the triangles and stvert data
660         inst = (void*)(base + LittleLong(pinmodel->ofs_st));
661         intri = (void*)(base + LittleLong(pinmodel->ofs_tris));
662         skinwidth = LittleLong(pinmodel->skinwidth);
663         skinheight = LittleLong(pinmodel->skinheight);
664
665         stverts = Mem_Alloc(tempmempool, numst * sizeof(float[2]));
666         s = 1.0f / skinwidth;
667         t = 1.0f / skinheight;
668         for (i = 0;i < numst;i++)
669         {
670                 j = (unsigned short) LittleShort(inst[i*2+0]);
671                 k = (unsigned short) LittleShort(inst[i*2+1]);
672                 if (j >= skinwidth || k >= skinheight)
673                 {
674                         Mem_Free(stverts);
675                         Host_Error("Mod_MD2_LoadGeometry: invalid skin coordinate (%i %i) on vert %i of model %s\n", j, k, i, loadmodel->name);
676                 }
677                 stverts[i*2+0] = j * s;
678                 stverts[i*2+1] = k * t;
679         }
680
681         md2verthash = Mem_Alloc(tempmempool, 256 * sizeof(hash));
682         md2verthashdata = Mem_Alloc(tempmempool, loadmodel->alias.aliasdata_meshes->num_triangles * 3 * sizeof(*hash));
683         // swap the triangle list
684         num = 0;
685         loadmodel->alias.aliasdata_meshes->data_element3i = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_triangles * sizeof(int[3]));
686         for (i = 0;i < loadmodel->alias.aliasdata_meshes->num_triangles;i++)
687         {
688                 for (j = 0;j < 3;j++)
689                 {
690                         xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
691                         st = (unsigned short) LittleShort (intri[i].index_st[j]);
692                         if (xyz >= numxyz || st >= numst)
693                         {
694                                 Mem_Free(md2verthash);
695                                 Mem_Free(md2verthashdata);
696                                 Mem_Free(stverts);
697                                 if (xyz >= numxyz)
698                                         Host_Error("Mod_MD2_LoadGeometry: invalid xyz index (%i) on triangle %i of model %s\n", xyz, i, loadmodel->name);
699                                 if (st >= numst)
700                                         Host_Error("Mod_MD2_LoadGeometry: invalid st index (%i) on triangle %i of model %s\n", st, i, loadmodel->name);
701                         }
702                         s = stverts[st*2+0];
703                         t = stverts[st*2+1];
704                         hashindex = (xyz * 17 + st) & 255;
705                         for (hash = md2verthash[hashindex];hash;hash = hash->next)
706                                 if (hash->xyz == xyz && hash->st[0] == s && hash->st[1] == t)
707                                         break;
708                         if (hash == NULL)
709                         {
710                                 hash = md2verthashdata + num++;
711                                 hash->xyz = xyz;
712                                 hash->st[0] = s;
713                                 hash->st[1] = t;
714                                 hash->next = md2verthash[hashindex];
715                                 md2verthash[hashindex] = hash;
716                         }
717                         loadmodel->alias.aliasdata_meshes->data_element3i[i*3+j] = (hash - md2verthashdata);
718                 }
719         }
720
721         Mem_Free(stverts);
722
723         numverts = num;
724         loadmodel->alias.aliasdata_meshes->num_vertices = numverts;
725         vertremap = Mem_Alloc(loadmodel->mempool, num * sizeof(int));
726         loadmodel->alias.aliasdata_meshes->data_texcoord2f = Mem_Alloc(loadmodel->mempool, num * sizeof(float[2]));
727         for (i = 0;i < num;i++)
728         {
729                 hash = md2verthashdata + i;
730                 vertremap[i] = hash->xyz;
731                 loadmodel->alias.aliasdata_meshes->data_texcoord2f[i*2+0] = hash->st[0];
732                 loadmodel->alias.aliasdata_meshes->data_texcoord2f[i*2+1] = hash->st[1];
733         }
734
735         Mem_Free(md2verthash);
736         Mem_Free(md2verthashdata);
737
738         // load the frames
739         datapointer = (base + LittleLong(pinmodel->ofs_frames));
740         loadmodel->alias.aliasdata_meshes->data_aliasvertex3f = Mem_Alloc(loadmodel->mempool, numverts * loadmodel->alias.aliasdata_meshes->num_frames * sizeof(float[4][3]));
741         loadmodel->alias.aliasdata_meshes->data_aliassvector3f = loadmodel->alias.aliasdata_meshes->data_aliasvertex3f + numverts * loadmodel->alias.aliasdata_meshes->num_frames * 3 * 1;
742         loadmodel->alias.aliasdata_meshes->data_aliastvector3f = loadmodel->alias.aliasdata_meshes->data_aliasvertex3f + numverts * loadmodel->alias.aliasdata_meshes->num_frames * 3 * 2;
743         loadmodel->alias.aliasdata_meshes->data_aliasnormal3f = loadmodel->alias.aliasdata_meshes->data_aliasvertex3f + numverts * loadmodel->alias.aliasdata_meshes->num_frames * 3 * 3;
744         for (i = 0;i < loadmodel->alias.aliasdata_meshes->num_frames;i++)
745         {
746                 pinframe = (md2frame_t *)datapointer;
747                 datapointer += sizeof(md2frame_t);
748                 for (j = 0;j < 3;j++)
749                 {
750                         scale[j] = LittleFloat(pinframe->scale[j]);
751                         translate[j] = LittleFloat(pinframe->translate[j]);
752                 }
753                 Mod_MD2_ConvertVerts(scale, translate, (void *)datapointer, loadmodel->alias.aliasdata_meshes->data_aliasvertex3f + i * numverts * 3, numverts, vertremap);
754                 Mod_BuildTextureVectorsAndNormals(loadmodel->alias.aliasdata_meshes->num_vertices, loadmodel->alias.aliasdata_meshes->num_triangles, loadmodel->alias.aliasdata_meshes->data_aliasvertex3f + i * loadmodel->alias.aliasdata_meshes->num_vertices * 3, loadmodel->alias.aliasdata_meshes->data_texcoord2f, loadmodel->alias.aliasdata_meshes->data_element3i, loadmodel->alias.aliasdata_meshes->data_aliassvector3f + i * loadmodel->alias.aliasdata_meshes->num_vertices * 3, loadmodel->alias.aliasdata_meshes->data_aliastvector3f + i * loadmodel->alias.aliasdata_meshes->num_vertices * 3, loadmodel->alias.aliasdata_meshes->data_aliasnormal3f + i * loadmodel->alias.aliasdata_meshes->num_vertices * 3);
755                 datapointer += numxyz * sizeof(trivertx_t);
756
757                 strcpy(loadmodel->animscenes[i].name, pinframe->name);
758                 loadmodel->animscenes[i].firstframe = i;
759                 loadmodel->animscenes[i].framecount = 1;
760                 loadmodel->animscenes[i].framerate = 10;
761                 loadmodel->animscenes[i].loop = true;
762         }
763
764         Mem_Free(vertremap);
765
766         loadmodel->alias.aliasdata_meshes->data_neighbor3i = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_triangles * sizeof(int[3]));
767         Mod_BuildTriangleNeighbors(loadmodel->alias.aliasdata_meshes->data_neighbor3i, loadmodel->alias.aliasdata_meshes->data_element3i, loadmodel->alias.aliasdata_meshes->num_triangles);
768         Mod_CalcAliasModelBBoxes();
769 }
770
771 void Mod_IDP3_Load(model_t *mod, void *buffer)
772 {
773         int i, j, k, version;
774         md3modelheader_t *pinmodel;
775         md3frameinfo_t *pinframe;
776         md3mesh_t *pinmesh;
777         md3tag_t *pintag;
778         aliasmesh_t *mesh;
779         skinfile_t *skinfiles;
780
781         pinmodel = buffer;
782
783         if (memcmp(pinmodel->identifier, "IDP3", 4))
784                 Host_Error ("%s is not a MD3 (IDP3) file\n", loadmodel->name);
785         version = LittleLong (pinmodel->version);
786         if (version != MD3VERSION)
787                 Host_Error ("%s has wrong version number (%i should be %i)",
788                         loadmodel->name, version, MD3VERSION);
789
790         skinfiles = Mod_LoadSkinFiles();
791         loadmodel->numskins = Mod_CountSkinFiles(skinfiles);
792         if (loadmodel->numskins < 1)
793                 loadmodel->numskins = 1;
794
795         loadmodel->type = mod_alias;
796         loadmodel->alias.aliastype = ALIASTYPE_ALIAS;
797         loadmodel->DrawSky = NULL;
798         loadmodel->Draw = R_Model_Alias_Draw;
799         loadmodel->DrawFakeShadow = R_Model_Alias_DrawFakeShadow;
800         loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume;
801         loadmodel->DrawLight = R_Model_Alias_DrawLight;
802         loadmodel->flags = 0;
803         loadmodel->synctype = ST_RAND;
804
805         // set up some global info about the model
806         loadmodel->numframes = LittleLong(pinmodel->num_frames);
807         loadmodel->alias.aliasnum_meshes = LittleLong(pinmodel->num_meshes);
808
809         // make skinscenes for the skins (no groups)
810         loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
811         for (i = 0;i < loadmodel->numskins;i++)
812         {
813                 loadmodel->skinscenes[i].firstframe = i;
814                 loadmodel->skinscenes[i].framecount = 1;
815                 loadmodel->skinscenes[i].loop = true;
816                 loadmodel->skinscenes[i].framerate = 10;
817         }
818
819         // load frameinfo
820         loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
821         for (i = 0, pinframe = (md3frameinfo_t *)((qbyte *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
822         {
823                 strcpy(loadmodel->animscenes[i].name, pinframe->name);
824                 loadmodel->animscenes[i].firstframe = i;
825                 loadmodel->animscenes[i].framecount = 1;
826                 loadmodel->animscenes[i].framerate = 10;
827                 loadmodel->animscenes[i].loop = true;
828         }
829
830         // load tags
831         loadmodel->alias.aliasnum_tagframes = loadmodel->numframes;
832         loadmodel->alias.aliasnum_tags = LittleLong(pinmodel->num_tags);
833         loadmodel->alias.aliasdata_tags = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasnum_tagframes * loadmodel->alias.aliasnum_tags * sizeof(aliastag_t));
834         for (i = 0, pintag = (md3tag_t *)((qbyte *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->alias.aliasnum_tagframes * loadmodel->alias.aliasnum_tags;i++, pinframe++)
835         {
836                 strcpy(loadmodel->alias.aliasdata_tags[i].name, pintag->name);
837                 Matrix4x4_CreateIdentity(&loadmodel->alias.aliasdata_tags[i].matrix);
838                 for (j = 0;j < 3;j++)
839                 {
840                         for (k = 0;k < 3;k++)
841                                 loadmodel->alias.aliasdata_tags[i].matrix.m[k][j] = LittleLong(pintag->rotationmatrix[j * 3 + k]);
842                         loadmodel->alias.aliasdata_tags[i].matrix.m[j][3] = LittleLong(pintag->origin[j]);
843                 }
844         }
845
846         // load meshes
847         loadmodel->alias.aliasdata_meshes = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasnum_meshes * sizeof(aliasmesh_t));
848         for (i = 0, pinmesh = (md3mesh_t *)((qbyte *)pinmodel + LittleLong(pinmodel->lump_meshes));i < loadmodel->alias.aliasnum_meshes;i++, pinmesh = (md3mesh_t *)((qbyte *)pinmesh + LittleLong(pinmesh->lump_end)))
849         {
850                 if (memcmp(pinmesh->identifier, "IDP3", 4))
851                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)\n");
852                 mesh = loadmodel->alias.aliasdata_meshes + i;
853                 mesh->num_skins = loadmodel->numskins;
854                 mesh->num_frames = LittleLong(pinmesh->num_frames);
855                 mesh->num_vertices = LittleLong(pinmesh->num_vertices);
856                 mesh->num_triangles = LittleLong(pinmesh->num_triangles);
857                 mesh->data_skins = Mem_Alloc(loadmodel->mempool, mesh->num_skins * sizeof(aliasskin_t));
858                 mesh->data_element3i = Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
859                 mesh->data_neighbor3i = Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
860                 mesh->data_texcoord2f = Mem_Alloc(loadmodel->mempool, mesh->num_vertices * sizeof(float[2]));
861                 mesh->data_aliasvertex3f = Mem_Alloc(loadmodel->mempool, mesh->num_vertices * mesh->num_frames * sizeof(float[4][3]));
862                 mesh->data_aliassvector3f = mesh->data_aliasvertex3f + mesh->num_vertices * mesh->num_frames * 3 * 1;
863                 mesh->data_aliastvector3f = mesh->data_aliasvertex3f + mesh->num_vertices * mesh->num_frames * 3 * 2;
864                 mesh->data_aliasnormal3f = mesh->data_aliasvertex3f + mesh->num_vertices * mesh->num_frames * 3 * 3;
865                 for (j = 0;j < mesh->num_triangles * 3;j++)
866                         mesh->data_element3i[j] = LittleLong(((int *)((qbyte *)pinmesh + pinmesh->lump_elements))[j]);
867                 for (j = 0;j < mesh->num_vertices;j++)
868                 {
869                         mesh->data_texcoord2f[j * 2 + 0] = LittleLong(((float *)((qbyte *)pinmesh + pinmesh->lump_texcoords))[j * 2 + 0]);
870                         mesh->data_texcoord2f[j * 2 + 1] = LittleLong(((float *)((qbyte *)pinmesh + pinmesh->lump_texcoords))[j * 2 + 1]);
871                 }
872                 for (j = 0;j < mesh->num_vertices * mesh->num_frames;j++)
873                 {
874                         mesh->data_aliasvertex3f[j * 3 + 0] = LittleShort(((short *)((qbyte *)pinmesh + pinmesh->lump_framevertices))[j * 4 + 0]) * (1.0f / 64.0f);
875                         mesh->data_aliasvertex3f[j * 3 + 1] = LittleShort(((short *)((qbyte *)pinmesh + pinmesh->lump_framevertices))[j * 4 + 1]) * (1.0f / 64.0f);
876                         mesh->data_aliasvertex3f[j * 3 + 2] = LittleShort(((short *)((qbyte *)pinmesh + pinmesh->lump_framevertices))[j * 4 + 2]) * (1.0f / 64.0f);
877                 }
878                 for (j = 0;j < mesh->num_frames;j++)
879                         Mod_BuildTextureVectorsAndNormals(mesh->num_vertices, mesh->num_triangles, mesh->data_aliasvertex3f + j * mesh->num_vertices * 3, mesh->data_texcoord2f, mesh->data_element3i, mesh->data_aliassvector3f + j * mesh->num_vertices * 3, mesh->data_aliastvector3f + j * mesh->num_vertices * 3, mesh->data_aliasnormal3f + j * mesh->num_vertices * 3);
880
881                 Mod_ValidateElements(mesh->data_element3i, mesh->num_triangles, mesh->num_vertices, __FILE__, __LINE__);
882                 Mod_BuildTriangleNeighbors(mesh->data_neighbor3i, mesh->data_element3i, mesh->num_triangles);
883
884                 if (LittleLong(pinmesh->num_shaders) >= 1 && ((md3shader_t *)((qbyte *) pinmesh + pinmesh->lump_shaders))->name[0])
885                         Mod_BuildAliasSkinsFromSkinFiles(mesh->data_skins, skinfiles, ((md3shader_t *)((qbyte *) pinmesh + pinmesh->lump_shaders))->name);
886         }
887         Mod_CalcAliasModelBBoxes();
888         Mod_FreeSkinFiles(skinfiles);
889 }
890
891 extern void R_Model_Zymotic_DrawSky(entity_render_t *ent);
892 extern void R_Model_Zymotic_Draw(entity_render_t *ent);
893 extern void R_Model_Zymotic_DrawFakeShadow(entity_render_t *ent);
894 extern void R_Model_Zymotic_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
895 extern void R_Model_Zymotic_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
896 void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer)
897 {
898         zymtype1header_t *pinmodel, *pheader;
899         qbyte *pbase;
900
901         pinmodel = (void *)buffer;
902         pbase = buffer;
903         if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
904                 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model\n");
905         if (BigLong(pinmodel->type) != 1)
906                 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)\n", loadmodel->name);
907
908         loadmodel->type = mod_alias;
909         loadmodel->alias.aliastype = ALIASTYPE_ZYM;
910         loadmodel->DrawSky = NULL;
911         loadmodel->Draw = R_Model_Zymotic_Draw;
912         loadmodel->DrawFakeShadow = NULL;//R_Model_Zymotic_DrawFakeShadow;
913         loadmodel->DrawShadowVolume = NULL;//R_Model_Zymotic_DrawShadowVolume;
914         loadmodel->DrawLight = NULL;//R_Model_Zymotic_DrawLight;
915
916         // byteswap header
917         pheader = pinmodel;
918         pheader->type = BigLong(pinmodel->type);
919         pheader->filesize = BigLong(pinmodel->filesize);
920         pheader->mins[0] = BigFloat(pinmodel->mins[0]);
921         pheader->mins[1] = BigFloat(pinmodel->mins[1]);
922         pheader->mins[2] = BigFloat(pinmodel->mins[2]);
923         pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
924         pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
925         pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
926         pheader->radius = BigFloat(pinmodel->radius);
927         pheader->numverts = loadmodel->alias.zymnum_verts = BigLong(pinmodel->numverts);
928         pheader->numtris = loadmodel->alias.zymnum_tris = BigLong(pinmodel->numtris);
929         pheader->numshaders = loadmodel->alias.zymnum_shaders = BigLong(pinmodel->numshaders);
930         pheader->numbones = loadmodel->alias.zymnum_bones = BigLong(pinmodel->numbones);
931         pheader->numscenes = loadmodel->alias.zymnum_scenes = BigLong(pinmodel->numscenes);
932         pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
933         pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
934         pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
935         pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
936         pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
937         pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
938         pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
939         pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
940         pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
941         pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
942         pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
943         pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
944         pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
945         pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
946         pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
947         pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
948         pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
949         pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
950
951         loadmodel->flags = 0; // there are no flags
952         loadmodel->numframes = pheader->numscenes;
953         loadmodel->synctype = ST_SYNC;
954         //loadmodel->numtris = pheader->numtris;
955         //loadmodel->numverts = 0;
956
957         {
958                 unsigned int i;
959                 float modelradius, corner[2];
960                 // model bbox
961                 modelradius = pheader->radius;
962                 for (i = 0;i < 3;i++)
963                 {
964                         loadmodel->normalmins[i] = pheader->mins[i];
965                         loadmodel->normalmaxs[i] = pheader->maxs[i];
966                         loadmodel->rotatedmins[i] = -modelradius;
967                         loadmodel->rotatedmaxs[i] = modelradius;
968                 }
969                 corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
970                 corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
971                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
972                 if (loadmodel->yawmaxs[0] > modelradius)
973                         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
974                 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
975                 loadmodel->yawmins[2] = loadmodel->normalmins[2];
976                 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
977                 loadmodel->radius = modelradius;
978                 loadmodel->radius2 = modelradius * modelradius;
979         }
980
981         {
982                 // FIXME: add shaders, and make them switchable shader sets and...
983                 loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t));
984                 loadmodel->skinscenes[0].firstframe = 0;
985                 loadmodel->skinscenes[0].framecount = 1;
986                 loadmodel->skinscenes[0].loop = true;
987                 loadmodel->skinscenes[0].framerate = 10;
988                 loadmodel->numskins = 1;
989         }
990
991         // go through the lumps, swapping things
992
993         {
994                 int i, numposes;
995                 zymscene_t *scene;
996         //      zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
997                 loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
998                 scene = (void *) (pheader->lump_scenes.start + pbase);
999                 numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1000                 for (i = 0;i < pheader->numscenes;i++)
1001                 {
1002                         memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1003                         loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1004                         loadmodel->animscenes[i].framecount = BigLong(scene->length);
1005                         loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1006                         loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1007                         if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1008                                 Host_Error("Mod_ZYMOTICMODEL_Load: scene firstframe (%i) >= numposes (%i)\n", loadmodel->animscenes[i].firstframe, numposes);
1009                         if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1010                                 Host_Error("Mod_ZYMOTICMODEL_Load: scene firstframe (%i) + framecount (%i) >= numposes (%i)\n", loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1011                         if (loadmodel->animscenes[i].framerate < 0)
1012                                 Host_Error("Mod_ZYMOTICMODEL_Load: scene framerate (%f) < 0\n", loadmodel->animscenes[i].framerate);
1013                         scene++;
1014                 }
1015         }
1016
1017         {
1018                 int i;
1019                 float *poses;
1020         //      zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1021                 loadmodel->alias.zymdata_poses = Mem_Alloc(loadmodel->mempool, pheader->lump_poses.length);
1022                 poses = (void *) (pheader->lump_poses.start + pbase);
1023                 for (i = 0;i < pheader->lump_poses.length / 4;i++)
1024                         loadmodel->alias.zymdata_poses[i] = BigFloat(poses[i]);
1025         }
1026
1027         {
1028                 int i;
1029                 zymbone_t *bone;
1030         //      zymlump_t lump_bones; // zymbone_t bone[numbones];
1031                 loadmodel->alias.zymdata_bones = Mem_Alloc(loadmodel->mempool, pheader->numbones * sizeof(zymbone_t));
1032                 bone = (void *) (pheader->lump_bones.start + pbase);
1033                 for (i = 0;i < pheader->numbones;i++)
1034                 {
1035                         memcpy(loadmodel->alias.zymdata_bones[i].name, bone[i].name, sizeof(bone[i].name));
1036                         loadmodel->alias.zymdata_bones[i].flags = BigLong(bone[i].flags);
1037                         loadmodel->alias.zymdata_bones[i].parent = BigLong(bone[i].parent);
1038                         if (loadmodel->alias.zymdata_bones[i].parent >= i)
1039                                 Host_Error("Mod_ZYMOTICMODEL_Load: bone[%i].parent >= %i in %s\n", i, i, loadmodel->name);
1040                 }
1041         }
1042
1043         {
1044                 int i, *bonecount;
1045         //      zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1046                 loadmodel->alias.zymdata_vertbonecounts = Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1047                 bonecount = (void *) (pheader->lump_vertbonecounts.start + pbase);
1048                 for (i = 0;i < pheader->numverts;i++)
1049                 {
1050                         loadmodel->alias.zymdata_vertbonecounts[i] = BigLong(bonecount[i]);
1051                         if (loadmodel->alias.zymdata_vertbonecounts[i] < 1)
1052                                 Host_Error("Mod_ZYMOTICMODEL_Load: bone vertex count < 1 in %s\n", loadmodel->name);
1053                 }
1054         }
1055
1056         {
1057                 int i;
1058                 zymvertex_t *vertdata;
1059         //      zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
1060                 loadmodel->alias.zymdata_verts = Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
1061                 vertdata = (void *) (pheader->lump_verts.start + pbase);
1062                 for (i = 0;i < pheader->lump_verts.length / (int) sizeof(zymvertex_t);i++)
1063                 {
1064                         loadmodel->alias.zymdata_verts[i].bonenum = BigLong(vertdata[i].bonenum);
1065                         loadmodel->alias.zymdata_verts[i].origin[0] = BigFloat(vertdata[i].origin[0]);
1066                         loadmodel->alias.zymdata_verts[i].origin[1] = BigFloat(vertdata[i].origin[1]);
1067                         loadmodel->alias.zymdata_verts[i].origin[2] = BigFloat(vertdata[i].origin[2]);
1068                 }
1069         }
1070
1071         {
1072                 int i;
1073                 float *intexcoord2f, *outtexcoord2f;
1074         //      zymlump_t lump_texcoords; // float texcoords[numvertices][2];
1075                 loadmodel->alias.zymdata_texcoords = outtexcoord2f = Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(float[2]));
1076                 intexcoord2f = (void *) (pheader->lump_texcoords.start + pbase);
1077                 for (i = 0;i < pheader->numverts;i++)
1078                 {
1079                         outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
1080                         // flip T coordinate for OpenGL
1081                         outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
1082                 }
1083         }
1084
1085         {
1086                 int i, count, *renderlist, *renderlistend, *outrenderlist;
1087         //      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)
1088                 loadmodel->alias.zymdata_renderlist = Mem_Alloc(loadmodel->mempool, pheader->lump_render.length);
1089                 // byteswap, validate, and swap winding order of tris
1090                 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
1091                 if (pheader->lump_render.length != count)
1092                         Host_Error("Mod_ZYMOTICMODEL_Load: renderlist is wrong size in %s (is %i bytes, should be %i bytes)\n", loadmodel->name, pheader->lump_render.length, count);
1093                 outrenderlist = loadmodel->alias.zymdata_renderlist = Mem_Alloc(loadmodel->mempool, count);
1094                 renderlist = (void *) (pheader->lump_render.start + pbase);
1095                 renderlistend = (void *) ((qbyte *) renderlist + pheader->lump_render.length);
1096                 for (i = 0;i < pheader->numshaders;i++)
1097                 {
1098                         if (renderlist >= renderlistend)
1099                                 Host_Error("Mod_ZYMOTICMODEL_Load: corrupt renderlist in %s (wrong size)\n", loadmodel->name);
1100                         count = BigLong(*renderlist);renderlist++;
1101                         if (renderlist + count * 3 > renderlistend)
1102                                 Host_Error("Mod_ZYMOTICMODEL_Load: corrupt renderlist in %s (wrong size)\n", loadmodel->name);
1103                         *outrenderlist++ = count;
1104                         while (count--)
1105                         {
1106                                 outrenderlist[2] = BigLong(renderlist[0]);
1107                                 outrenderlist[1] = BigLong(renderlist[1]);
1108                                 outrenderlist[0] = BigLong(renderlist[2]);
1109                                 if ((unsigned int)outrenderlist[0] >= (unsigned int)pheader->numverts
1110                                  || (unsigned int)outrenderlist[1] >= (unsigned int)pheader->numverts
1111                                  || (unsigned int)outrenderlist[2] >= (unsigned int)pheader->numverts)
1112                                         Host_Error("Mod_ZYMOTICMODEL_Load: corrupt renderlist in %s (out of bounds index)\n", loadmodel->name);
1113                                 renderlist += 3;
1114                                 outrenderlist += 3;
1115                         }
1116                 }
1117         }
1118
1119         {
1120                 int i;
1121                 char *shadername;
1122         //      zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
1123                 loadmodel->alias.zymdata_textures = Mem_Alloc(loadmodel->mempool, pheader->numshaders * sizeof(rtexture_t *));
1124                 shadername = (void *) (pheader->lump_shaders.start + pbase);
1125                 for (i = 0;i < pheader->numshaders;i++)
1126                         loadmodel->alias.zymdata_textures[i] = loadtextureimage(loadmodel->texturepool, shadername + i * 32, 0, 0, true, TEXF_ALPHA | TEXF_PRECACHE | (r_mipskins.integer ? TEXF_MIPMAP : 0));
1127         }
1128
1129         {
1130         //      zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
1131                 loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
1132                 memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
1133         }
1134 }
1135