2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
25 void Mod_AliasInit (void)
29 static void Mod_MDLMD2MD3_TraceBox(model_t *model, int frame, trace_t *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs, int hitsupercontentsmask)
32 float segmentmins[3], segmentmaxs[3];
33 colbrushf_t *thisbrush_start, *thisbrush_end;
34 matrix4x4_t startmatrix, endmatrix;
35 memset(trace, 0, sizeof(*trace));
37 trace->realfraction = 1;
38 trace->hitsupercontentsmask = hitsupercontentsmask;
39 segmentmins[0] = min(boxstartmins[0], boxendmins[0]);
40 segmentmins[1] = min(boxstartmins[1], boxendmins[1]);
41 segmentmins[2] = min(boxstartmins[2], boxendmins[2]);
42 segmentmaxs[0] = max(boxstartmaxs[0], boxendmaxs[0]);
43 segmentmaxs[1] = max(boxstartmaxs[1], boxendmaxs[1]);
44 segmentmaxs[2] = max(boxstartmaxs[2], boxendmaxs[2]);
45 if (VectorCompare(boxstartmins, boxstartmaxs) && VectorCompare(boxendmins, boxendmaxs))
48 for (i = 0;i < model->alias.aliasnum_meshes;i++)
51 if (framenum < 0 || framenum > model->alias.aliasdata_meshes[i].num_morphframes)
53 if (model->alias.aliasdata_meshes[i].data_morphvertex3f)
54 Collision_TraceLineTriangleMeshFloat(trace, boxstartmins, boxendmins, model->alias.aliasdata_meshes[i].num_triangles, model->alias.aliasdata_meshes[i].data_element3i, model->alias.aliasdata_meshes[i].data_morphvertex3f + framenum * model->alias.aliasdata_meshes[i].num_vertices * 3, SUPERCONTENTS_SOLID, segmentmins, segmentmaxs);
56 // FIXME!!! this needs to handle skeletal!
61 // box trace, performed as brush trace
62 Matrix4x4_CreateIdentity(&startmatrix);
63 Matrix4x4_CreateIdentity(&endmatrix);
64 thisbrush_start = Collision_BrushForBox(&startmatrix, boxstartmins, boxstartmaxs);
65 thisbrush_end = Collision_BrushForBox(&endmatrix, boxendmins, boxendmaxs);
66 for (i = 0;i < model->alias.aliasnum_meshes;i++)
69 if (framenum < 0 || framenum > model->alias.aliasdata_meshes[i].num_morphframes)
71 if (model->alias.aliasdata_meshes[i].data_morphvertex3f)
72 Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, model->alias.aliasdata_meshes[i].num_triangles, model->alias.aliasdata_meshes[i].data_element3i, model->alias.aliasdata_meshes[i].data_morphvertex3f + framenum * model->alias.aliasdata_meshes[i].num_vertices * 3, SUPERCONTENTS_SOLID, segmentmins, segmentmaxs);
74 // FIXME!!! this needs to handle skeletal!
79 static void Mod_CalcAliasModelBBoxes (void)
82 float dist, yawradius, radius;
85 VectorClear(loadmodel->normalmins);
86 VectorClear(loadmodel->normalmaxs);
89 for (meshnum = 0, mesh = loadmodel->alias.aliasdata_meshes;meshnum < loadmodel->alias.aliasnum_meshes;meshnum++, mesh++)
91 for (vnum = 0, v = mesh->data_morphvertex3f;vnum < mesh->num_vertices * mesh->num_morphframes;vnum++, v += 3)
93 if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
94 if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
95 if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
96 if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
97 if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
98 if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
99 dist = v[0] * v[0] + v[1] * v[1];
100 if (yawradius < dist)
107 radius = sqrt(radius);
108 yawradius = sqrt(yawradius);
109 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
110 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius;
111 loadmodel->yawmins[2] = loadmodel->normalmins[2];
112 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
113 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
114 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
115 loadmodel->radius = radius;
116 loadmodel->radius2 = radius * radius;
119 static void Mod_ConvertAliasVerts (int inverts, vec3_t scale, vec3_t translate, trivertx_t *v, float *out3f, int *vertremap)
123 for (i = 0;i < inverts;i++)
125 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
127 temp[0] = v[i].v[0] * scale[0] + translate[0];
128 temp[1] = v[i].v[1] * scale[1] + translate[1];
129 temp[2] = v[i].v[2] * scale[2] + translate[2];
130 j = vertremap[i]; // not onseam
132 VectorCopy(temp, out3f + j * 3);
133 j = vertremap[i+inverts]; // onseam
135 VectorCopy(temp, out3f + j * 3);
139 static void Mod_MDL_LoadFrames (qbyte* datapointer, int inverts, vec3_t scale, vec3_t translate, int *vertremap)
141 int i, f, pose, groupframes;
143 daliasframetype_t *pframetype;
144 daliasframe_t *pinframe;
145 daliasgroup_t *group;
146 daliasinterval_t *intervals;
149 scene = loadmodel->animscenes;
150 for (f = 0;f < loadmodel->numframes;f++)
152 pframetype = (daliasframetype_t *)datapointer;
153 datapointer += sizeof(daliasframetype_t);
154 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
156 // a single frame is still treated as a group
163 group = (daliasgroup_t *)datapointer;
164 datapointer += sizeof(daliasgroup_t);
165 groupframes = LittleLong (group->numframes);
167 // intervals (time per frame)
168 intervals = (daliasinterval_t *)datapointer;
169 datapointer += sizeof(daliasinterval_t) * groupframes;
171 interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
172 if (interval < 0.01f)
174 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
179 // get scene name from first frame
180 pinframe = (daliasframe_t *)datapointer;
182 strcpy(scene->name, pinframe->name);
183 scene->firstframe = pose;
184 scene->framecount = groupframes;
185 scene->framerate = 1.0f / interval;
190 for (i = 0;i < groupframes;i++)
192 pinframe = (daliasframe_t *)datapointer;
193 datapointer += sizeof(daliasframe_t);
194 Mod_ConvertAliasVerts(inverts, scale, translate, (trivertx_t *)datapointer, loadmodel->alias.aliasdata_meshes->data_morphvertex3f + pose * loadmodel->alias.aliasdata_meshes->num_vertices * 3, vertremap);
195 datapointer += sizeof(trivertx_t) * inverts;
201 static skinframe_t missingskinframe;
202 aliaslayer_t mod_alias_layersbuffer[16]; // 7 currently used
203 void Mod_BuildAliasSkinFromSkinFrame(aliasskin_t *skin, skinframe_t *skinframe)
208 if (skinframe == NULL)
210 skinframe = &missingskinframe;
211 memset(skinframe, 0, sizeof(*skinframe));
212 skinframe->base = r_notexture;
215 memset(&mod_alias_layersbuffer, 0, sizeof(mod_alias_layersbuffer));
216 layer = mod_alias_layersbuffer;
217 layer->flags = ALIASLAYER_SPECULAR;
218 layer->texture = skinframe->gloss;
219 layer->nmap = skinframe->nmap;
221 if (skinframe->merged != NULL)
223 layer->flags = ALIASLAYER_DIFFUSE | ALIASLAYER_NODRAW_IF_COLORMAPPED;
224 layer->texture = skinframe->merged;
225 layer->nmap = skinframe->nmap;
228 if (skinframe->base != NULL)
230 layer->flags = ALIASLAYER_DIFFUSE;
231 if (skinframe->merged != NULL)
232 layer->flags |= ALIASLAYER_NODRAW_IF_NOTCOLORMAPPED;
233 layer->texture = skinframe->base;
234 layer->nmap = skinframe->nmap;
237 if (skinframe->pants != NULL)
239 layer->flags = ALIASLAYER_DIFFUSE | ALIASLAYER_NODRAW_IF_NOTCOLORMAPPED | ALIASLAYER_COLORMAP_PANTS;
240 layer->texture = skinframe->pants;
241 layer->nmap = skinframe->nmap;
244 if (skinframe->shirt != NULL)
246 layer->flags = ALIASLAYER_DIFFUSE | ALIASLAYER_NODRAW_IF_NOTCOLORMAPPED | ALIASLAYER_COLORMAP_SHIRT;
247 layer->texture = skinframe->shirt;
248 layer->nmap = skinframe->nmap;
252 if (skinframe->glow != NULL)
255 layer->texture = skinframe->glow;
259 layer->flags = ALIASLAYER_FOG | ALIASLAYER_FORCEDRAW_IF_FIRSTPASS;
260 layer->texture = skinframe->fog;
264 // fog texture only exists if some pixels are transparent...
265 if (skinframe->fog != NULL)
266 skin->flags |= ALIASSKIN_TRANSPARENT;
268 skin->num_layers = layer - mod_alias_layersbuffer;
269 skin->data_layers = Mem_Alloc(loadmodel->mempool, skin->num_layers * sizeof(aliaslayer_t));
270 memcpy(skin->data_layers, mod_alias_layersbuffer, skin->num_layers * sizeof(aliaslayer_t));
273 void Mod_BuildAliasSkinsFromSkinFiles(aliasskin_t *skin, skinfile_t *skinfile, char *meshname, char *shadername)
276 skinfileitem_t *skinfileitem;
277 skinframe_t tempskinframe;
280 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin++)
282 memset(skin, 0, sizeof(*skin));
283 for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
285 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
286 if (!strcmp(skinfileitem->name, meshname) && strcmp(skinfileitem->replacement, "common/nodraw") && strcmp(skinfileitem->replacement, "textures/common/nodraw"))
288 memset(&tempskinframe, 0, sizeof(tempskinframe));
289 if (Mod_LoadSkinFrame(&tempskinframe, skinfileitem->replacement, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_CLAMP | TEXF_PRECACHE | TEXF_PICMIP, true, false, true))
290 Mod_BuildAliasSkinFromSkinFrame(skin, &tempskinframe);
293 Con_Printf("mesh \"%s\": failed to load skin #%i \"%s\", falling back to mesh's internal shader name \"%s\"\n", meshname, i, skinfileitem->replacement, shadername);
294 if (Mod_LoadSkinFrame(&tempskinframe, shadername, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_CLAMP | TEXF_PRECACHE | TEXF_PICMIP, true, false, true))
295 Mod_BuildAliasSkinFromSkinFrame(skin, &tempskinframe);
298 Con_Printf("failed to load skin \"%s\"\n", shadername);
299 Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
308 memset(&tempskinframe, 0, sizeof(tempskinframe));
309 if (Mod_LoadSkinFrame(&tempskinframe, shadername, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_CLAMP | TEXF_PRECACHE | TEXF_PICMIP, true, false, true))
310 Mod_BuildAliasSkinFromSkinFrame(skin, &tempskinframe);
313 Con_Printf("failed to load mesh \"%s\" shader \"%s\"\n", meshname, shadername);
314 Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
319 #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);
320 #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);
321 extern void R_Model_Alias_Draw(entity_render_t *ent);
322 extern void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist);
323 extern void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap, int numsurfaces, const int *surfacelist);
324 void Mod_IDP0_Load(model_t *mod, void *buffer)
326 int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
327 float scales, scalet, scale[3], translate[3], interval;
329 stvert_t *pinstverts;
330 dtriangle_t *pintriangles;
331 daliasskintype_t *pinskintype;
332 daliasskingroup_t *pinskingroup;
333 daliasskininterval_t *pinskinintervals;
334 daliasframetype_t *pinframetype;
335 daliasgroup_t *pinframegroup;
336 qbyte *datapointer, *startframes, *startskins;
337 char name[MAX_QPATH];
338 skinframe_t tempskinframe;
339 animscene_t *tempskinscenes;
340 aliasskin_t *tempaliasskins;
342 int *vertonseam, *vertremap;
343 skinfile_t *skinfiles;
345 datapointer = buffer;
346 pinmodel = (mdl_t *)datapointer;
347 datapointer += sizeof(mdl_t);
349 version = LittleLong (pinmodel->version);
350 if (version != ALIAS_VERSION)
351 Host_Error ("%s has wrong version number (%i should be %i)",
352 loadmodel->name, version, ALIAS_VERSION);
354 loadmodel->type = mod_alias;
355 loadmodel->DrawSky = NULL;
356 loadmodel->Draw = R_Model_Alias_Draw;
357 loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume;
358 loadmodel->DrawLight = R_Model_Alias_DrawLight;
359 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
361 loadmodel->alias.aliasnum_meshes = 1;
362 loadmodel->alias.aliasdata_meshes = Mem_Alloc(loadmodel->mempool, sizeof(aliasmesh_t));
364 loadmodel->numskins = LittleLong(pinmodel->numskins);
365 BOUNDI(loadmodel->numskins,0,65536);
366 skinwidth = LittleLong (pinmodel->skinwidth);
367 BOUNDI(skinwidth,0,65536);
368 skinheight = LittleLong (pinmodel->skinheight);
369 BOUNDI(skinheight,0,65536);
370 numverts = LittleLong(pinmodel->numverts);
371 BOUNDI(numverts,0,65536);
372 loadmodel->alias.aliasdata_meshes->num_triangles = LittleLong(pinmodel->numtris);
373 BOUNDI(loadmodel->alias.aliasdata_meshes->num_triangles,0,65536);
374 loadmodel->numframes = LittleLong(pinmodel->numframes);
375 BOUNDI(loadmodel->numframes,0,65536);
376 loadmodel->synctype = LittleLong (pinmodel->synctype);
377 BOUNDI(loadmodel->synctype,0,2);
378 loadmodel->flags = LittleLong (pinmodel->flags);
380 for (i = 0;i < 3;i++)
382 scale[i] = LittleFloat (pinmodel->scale[i]);
383 translate[i] = LittleFloat (pinmodel->scale_origin[i]);
386 startskins = datapointer;
388 for (i = 0;i < loadmodel->numskins;i++)
390 pinskintype = (daliasskintype_t *)datapointer;
391 datapointer += sizeof(daliasskintype_t);
392 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
396 pinskingroup = (daliasskingroup_t *)datapointer;
397 datapointer += sizeof(daliasskingroup_t);
398 groupskins = LittleLong(pinskingroup->numskins);
399 datapointer += sizeof(daliasskininterval_t) * groupskins;
402 for (j = 0;j < groupskins;j++)
404 datapointer += skinwidth * skinheight;
409 pinstverts = (stvert_t *)datapointer;
410 datapointer += sizeof(stvert_t) * numverts;
412 pintriangles = (dtriangle_t *)datapointer;
413 datapointer += sizeof(dtriangle_t) * loadmodel->alias.aliasdata_meshes->num_triangles;
415 startframes = datapointer;
416 loadmodel->alias.aliasdata_meshes->num_morphframes = 0;
417 for (i = 0;i < loadmodel->numframes;i++)
419 pinframetype = (daliasframetype_t *)datapointer;
420 datapointer += sizeof(daliasframetype_t);
421 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
425 pinframegroup = (daliasgroup_t *)datapointer;
426 datapointer += sizeof(daliasgroup_t);
427 groupframes = LittleLong(pinframegroup->numframes);
428 datapointer += sizeof(daliasinterval_t) * groupframes;
431 for (j = 0;j < groupframes;j++)
433 datapointer += sizeof(daliasframe_t);
434 datapointer += sizeof(trivertx_t) * numverts;
435 loadmodel->alias.aliasdata_meshes->num_morphframes++;
439 // store texture coordinates into temporary array, they will be stored
440 // after usage is determined (triangle data)
441 vertst = Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
442 vertremap = Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
443 vertonseam = vertremap + numverts * 2;
445 scales = 1.0 / skinwidth;
446 scalet = 1.0 / skinheight;
447 for (i = 0;i < numverts;i++)
449 vertonseam[i] = LittleLong(pinstverts[i].onseam);
450 vertst[i*2+0] = (LittleLong(pinstverts[i].s) + 0.5) * scales;
451 vertst[i*2+1] = (LittleLong(pinstverts[i].t) + 0.5) * scalet;
452 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
453 vertst[(i+numverts)*2+1] = vertst[i*2+1];
456 // load triangle data
457 loadmodel->alias.aliasdata_meshes->data_element3i = Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->alias.aliasdata_meshes->num_triangles);
459 // read the triangle elements
460 for (i = 0;i < loadmodel->alias.aliasdata_meshes->num_triangles;i++)
461 for (j = 0;j < 3;j++)
462 loadmodel->alias.aliasdata_meshes->data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
463 // validate (note numverts is used because this is the original data)
464 Mod_ValidateElements(loadmodel->alias.aliasdata_meshes->data_element3i, loadmodel->alias.aliasdata_meshes->num_triangles, numverts, __FILE__, __LINE__);
465 // now butcher the elements according to vertonseam and tri->facesfront
466 // and then compact the vertex set to remove duplicates
467 for (i = 0;i < loadmodel->alias.aliasdata_meshes->num_triangles;i++)
468 if (!LittleLong(pintriangles[i].facesfront)) // backface
469 for (j = 0;j < 3;j++)
470 if (vertonseam[loadmodel->alias.aliasdata_meshes->data_element3i[i*3+j]])
471 loadmodel->alias.aliasdata_meshes->data_element3i[i*3+j] += numverts;
473 // (this uses vertremap to count usage to save some memory)
474 for (i = 0;i < numverts*2;i++)
476 for (i = 0;i < loadmodel->alias.aliasdata_meshes->num_triangles*3;i++)
477 vertremap[loadmodel->alias.aliasdata_meshes->data_element3i[i]]++;
478 // build remapping table and compact array
479 loadmodel->alias.aliasdata_meshes->num_vertices = 0;
480 for (i = 0;i < numverts*2;i++)
484 vertremap[i] = loadmodel->alias.aliasdata_meshes->num_vertices;
485 vertst[loadmodel->alias.aliasdata_meshes->num_vertices*2+0] = vertst[i*2+0];
486 vertst[loadmodel->alias.aliasdata_meshes->num_vertices*2+1] = vertst[i*2+1];
487 loadmodel->alias.aliasdata_meshes->num_vertices++;
490 vertremap[i] = -1; // not used at all
492 // remap the elements to the new vertex set
493 for (i = 0;i < loadmodel->alias.aliasdata_meshes->num_triangles * 3;i++)
494 loadmodel->alias.aliasdata_meshes->data_element3i[i] = vertremap[loadmodel->alias.aliasdata_meshes->data_element3i[i]];
495 // store the texture coordinates
496 loadmodel->alias.aliasdata_meshes->data_texcoord2f = Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->alias.aliasdata_meshes->num_vertices);
497 for (i = 0;i < loadmodel->alias.aliasdata_meshes->num_vertices;i++)
499 loadmodel->alias.aliasdata_meshes->data_texcoord2f[i*2+0] = vertst[i*2+0];
500 loadmodel->alias.aliasdata_meshes->data_texcoord2f[i*2+1] = vertst[i*2+1];
504 loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
505 loadmodel->alias.aliasdata_meshes->data_morphvertex3f = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * loadmodel->alias.aliasdata_meshes->num_morphframes * loadmodel->alias.aliasdata_meshes->num_vertices);
506 loadmodel->alias.aliasdata_meshes->data_neighbor3i = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_triangles * sizeof(int[3]));
507 Mod_MDL_LoadFrames (startframes, numverts, scale, translate, vertremap);
508 Mod_BuildTriangleNeighbors(loadmodel->alias.aliasdata_meshes->data_neighbor3i, loadmodel->alias.aliasdata_meshes->data_element3i, loadmodel->alias.aliasdata_meshes->num_triangles);
509 Mod_CalcAliasModelBBoxes();
515 if ((skinfiles = Mod_LoadSkinFiles()))
517 loadmodel->alias.aliasdata_meshes->num_skins = totalskins = loadmodel->numskins;
518 loadmodel->alias.aliasdata_meshes->data_skins = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_skins * sizeof(aliasskin_t));
519 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->alias.aliasdata_meshes->data_skins, skinfiles, "default", "");
520 Mod_FreeSkinFiles(skinfiles);
521 loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
522 for (i = 0;i < loadmodel->numskins;i++)
524 loadmodel->skinscenes[i].firstframe = i;
525 loadmodel->skinscenes[i].framecount = 1;
526 loadmodel->skinscenes[i].loop = true;
527 loadmodel->skinscenes[i].framerate = 10;
532 loadmodel->alias.aliasdata_meshes->num_skins = totalskins;
533 loadmodel->alias.aliasdata_meshes->data_skins = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_skins * sizeof(aliasskin_t));
534 loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
536 datapointer = startskins;
537 for (i = 0;i < loadmodel->numskins;i++)
539 pinskintype = (daliasskintype_t *)datapointer;
540 datapointer += sizeof(daliasskintype_t);
542 if (pinskintype->type == ALIAS_SKIN_SINGLE)
549 pinskingroup = (daliasskingroup_t *)datapointer;
550 datapointer += sizeof(daliasskingroup_t);
552 groupskins = LittleLong (pinskingroup->numskins);
554 pinskinintervals = (daliasskininterval_t *)datapointer;
555 datapointer += sizeof(daliasskininterval_t) * groupskins;
557 interval = LittleFloat(pinskinintervals[0].interval);
558 if (interval < 0.01f)
560 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
565 sprintf(loadmodel->skinscenes[i].name, "skin %i", i);
566 loadmodel->skinscenes[i].firstframe = totalskins;
567 loadmodel->skinscenes[i].framecount = groupskins;
568 loadmodel->skinscenes[i].framerate = 1.0f / interval;
569 loadmodel->skinscenes[i].loop = true;
571 for (j = 0;j < groupskins;j++)
574 sprintf (name, "%s_%i_%i", loadmodel->name, i, j);
576 sprintf (name, "%s_%i", loadmodel->name, i);
577 if (!Mod_LoadSkinFrame(&tempskinframe, name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_CLAMP | TEXF_ALPHA | TEXF_PICMIP, true, false, true))
578 Mod_LoadSkinFrame_Internal(&tempskinframe, name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_CLAMP | TEXF_ALPHA | TEXF_PICMIP, true, false, r_fullbrights.integer, (qbyte *)datapointer, skinwidth, skinheight);
579 Mod_BuildAliasSkinFromSkinFrame(loadmodel->alias.aliasdata_meshes->data_skins + totalskins, &tempskinframe);
580 datapointer += skinwidth * skinheight;
584 // check for skins that don't exist in the model, but do exist as external images
585 // (this was added because yummyluv kept pestering me about support for it)
586 while (Mod_LoadSkinFrame(&tempskinframe, va("%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_CLAMP | TEXF_ALPHA | TEXF_PICMIP, true, false, true))
588 // expand the arrays to make room
589 tempskinscenes = loadmodel->skinscenes;
590 loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
591 memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
592 Mem_Free(tempskinscenes);
594 tempaliasskins = loadmodel->alias.aliasdata_meshes->data_skins;
595 loadmodel->alias.aliasdata_meshes->data_skins = Mem_Alloc(loadmodel->mempool, (totalskins + 1) * sizeof(aliasskin_t));
596 memcpy(loadmodel->alias.aliasdata_meshes->data_skins, tempaliasskins, totalskins * sizeof(aliasskin_t));
597 Mem_Free(tempaliasskins);
599 // store the info about the new skin
600 Mod_BuildAliasSkinFromSkinFrame(loadmodel->alias.aliasdata_meshes->data_skins + totalskins, &tempskinframe);
601 strcpy(loadmodel->skinscenes[loadmodel->numskins].name, name);
602 loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
603 loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
604 loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
605 loadmodel->skinscenes[loadmodel->numskins].loop = true;
607 //increase skin counts
608 loadmodel->alias.aliasdata_meshes->num_skins++;
609 loadmodel->numskins++;
615 static void Mod_MD2_ConvertVerts (vec3_t scale, vec3_t translate, trivertx_t *v, float *out3f, int numverts, int *vertremap)
619 for (i = 0;i < numverts;i++, out3f += 3)
621 in = v + vertremap[i];
622 out3f[0] = in->v[0] * scale[0] + translate[0];
623 out3f[1] = in->v[1] * scale[1] + translate[1];
624 out3f[2] = in->v[2] * scale[2] + translate[2];
628 void Mod_IDP2_Load(model_t *mod, void *buffer)
630 int i, j, k, hashindex, num, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end, numverts;
631 float *stverts, s, t, scale[3], translate[3];
633 qbyte *base, *datapointer;
634 md2frame_t *pinframe;
636 md2triangle_t *intri;
637 unsigned short *inst;
640 struct md2verthash_s *next;
644 *hash, **md2verthash, *md2verthashdata;
645 skinframe_t tempskinframe;
646 skinfile_t *skinfiles;
651 version = LittleLong (pinmodel->version);
652 if (version != MD2ALIAS_VERSION)
653 Host_Error ("%s has wrong version number (%i should be %i)",
654 loadmodel->name, version, MD2ALIAS_VERSION);
656 loadmodel->type = mod_alias;
657 loadmodel->DrawSky = NULL;
658 loadmodel->Draw = R_Model_Alias_Draw;
659 loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume;
660 loadmodel->DrawLight = R_Model_Alias_DrawLight;
661 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
663 if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
664 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
665 if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
666 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
667 if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
668 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
669 if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
670 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
672 end = LittleLong(pinmodel->ofs_end);
673 if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
674 Host_Error ("%s is not a valid model", loadmodel->name);
675 if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
676 Host_Error ("%s is not a valid model", loadmodel->name);
677 if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
678 Host_Error ("%s is not a valid model", loadmodel->name);
679 if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
680 Host_Error ("%s is not a valid model", loadmodel->name);
681 if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
682 Host_Error ("%s is not a valid model", loadmodel->name);
684 loadmodel->alias.aliasnum_meshes = 1;
685 loadmodel->alias.aliasdata_meshes = Mem_Alloc(loadmodel->mempool, sizeof(aliasmesh_t));
687 loadmodel->numskins = LittleLong(pinmodel->num_skins);
688 numxyz = LittleLong(pinmodel->num_xyz);
689 numst = LittleLong(pinmodel->num_st);
690 loadmodel->alias.aliasdata_meshes->num_triangles = LittleLong(pinmodel->num_tris);
691 loadmodel->numframes = LittleLong(pinmodel->num_frames);
692 loadmodel->alias.aliasdata_meshes->num_morphframes = loadmodel->numframes;
693 loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
695 loadmodel->flags = 0; // there are no MD2 flags
696 loadmodel->synctype = ST_RAND;
699 inskin = (void*)(base + LittleLong(pinmodel->ofs_skins));
700 if ((skinfiles = Mod_LoadSkinFiles()))
702 loadmodel->alias.aliasdata_meshes->num_skins = loadmodel->numskins;
703 loadmodel->alias.aliasdata_meshes->data_skins = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_skins * sizeof(aliasskin_t));
704 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->alias.aliasdata_meshes->data_skins, skinfiles, "default", "");
705 Mod_FreeSkinFiles(skinfiles);
707 else if (loadmodel->numskins)
709 // skins found (most likely not a player model)
710 loadmodel->alias.aliasdata_meshes->num_skins = loadmodel->numskins;
711 loadmodel->alias.aliasdata_meshes->data_skins = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_skins * sizeof(aliasskin_t));
712 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
714 if (Mod_LoadSkinFrame(&tempskinframe, inskin, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_CLAMP | TEXF_PRECACHE | TEXF_PICMIP, true, false, true))
715 Mod_BuildAliasSkinFromSkinFrame(loadmodel->alias.aliasdata_meshes->data_skins + i, &tempskinframe);
718 Con_Printf("%s is missing skin \"%s\"\n", loadmodel->name, inskin);
719 Mod_BuildAliasSkinFromSkinFrame(loadmodel->alias.aliasdata_meshes->data_skins + i, NULL);
725 // no skins (most likely a player model)
726 loadmodel->numskins = 1;
727 loadmodel->alias.aliasdata_meshes->num_skins = loadmodel->numskins;
728 loadmodel->alias.aliasdata_meshes->data_skins = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_skins * sizeof(aliasskin_t));
729 Mod_BuildAliasSkinFromSkinFrame(loadmodel->alias.aliasdata_meshes->data_skins, NULL);
732 loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
733 for (i = 0;i < loadmodel->numskins;i++)
735 loadmodel->skinscenes[i].firstframe = i;
736 loadmodel->skinscenes[i].framecount = 1;
737 loadmodel->skinscenes[i].loop = true;
738 loadmodel->skinscenes[i].framerate = 10;
741 // load the triangles and stvert data
742 inst = (void*)(base + LittleLong(pinmodel->ofs_st));
743 intri = (void*)(base + LittleLong(pinmodel->ofs_tris));
744 skinwidth = LittleLong(pinmodel->skinwidth);
745 skinheight = LittleLong(pinmodel->skinheight);
747 stverts = Mem_Alloc(tempmempool, numst * sizeof(float[2]));
748 s = 1.0f / skinwidth;
749 t = 1.0f / skinheight;
750 for (i = 0;i < numst;i++)
752 j = (unsigned short) LittleShort(inst[i*2+0]);
753 k = (unsigned short) LittleShort(inst[i*2+1]);
754 if (j >= skinwidth || k >= skinheight)
756 Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, j, k, i);
760 stverts[i*2+0] = j * s;
761 stverts[i*2+1] = k * t;
764 md2verthash = Mem_Alloc(tempmempool, 256 * sizeof(hash));
765 md2verthashdata = Mem_Alloc(tempmempool, loadmodel->alias.aliasdata_meshes->num_triangles * 3 * sizeof(*hash));
766 // swap the triangle list
768 loadmodel->alias.aliasdata_meshes->data_element3i = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_triangles * sizeof(int[3]));
769 for (i = 0;i < loadmodel->alias.aliasdata_meshes->num_triangles;i++)
771 for (j = 0;j < 3;j++)
773 xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
774 st = (unsigned short) LittleShort (intri[i].index_st[j]);
777 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
782 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
787 hashindex = (xyz * 17 + st) & 255;
788 for (hash = md2verthash[hashindex];hash;hash = hash->next)
789 if (hash->xyz == xyz && hash->st[0] == s && hash->st[1] == t)
793 hash = md2verthashdata + num++;
797 hash->next = md2verthash[hashindex];
798 md2verthash[hashindex] = hash;
800 loadmodel->alias.aliasdata_meshes->data_element3i[i*3+j] = (hash - md2verthashdata);
807 loadmodel->alias.aliasdata_meshes->num_vertices = numverts;
808 vertremap = Mem_Alloc(loadmodel->mempool, num * sizeof(int));
809 loadmodel->alias.aliasdata_meshes->data_texcoord2f = Mem_Alloc(loadmodel->mempool, num * sizeof(float[2]));
810 for (i = 0;i < num;i++)
812 hash = md2verthashdata + i;
813 vertremap[i] = hash->xyz;
814 loadmodel->alias.aliasdata_meshes->data_texcoord2f[i*2+0] = hash->st[0];
815 loadmodel->alias.aliasdata_meshes->data_texcoord2f[i*2+1] = hash->st[1];
818 Mem_Free(md2verthash);
819 Mem_Free(md2verthashdata);
822 datapointer = (base + LittleLong(pinmodel->ofs_frames));
823 loadmodel->alias.aliasdata_meshes->data_morphvertex3f = Mem_Alloc(loadmodel->mempool, numverts * loadmodel->alias.aliasdata_meshes->num_morphframes * sizeof(float[3]));
824 for (i = 0;i < loadmodel->alias.aliasdata_meshes->num_morphframes;i++)
826 pinframe = (md2frame_t *)datapointer;
827 datapointer += sizeof(md2frame_t);
828 for (j = 0;j < 3;j++)
830 scale[j] = LittleFloat(pinframe->scale[j]);
831 translate[j] = LittleFloat(pinframe->translate[j]);
833 Mod_MD2_ConvertVerts(scale, translate, (void *)datapointer, loadmodel->alias.aliasdata_meshes->data_morphvertex3f + i * numverts * 3, numverts, vertremap);
834 datapointer += numxyz * sizeof(trivertx_t);
836 strcpy(loadmodel->animscenes[i].name, pinframe->name);
837 loadmodel->animscenes[i].firstframe = i;
838 loadmodel->animscenes[i].framecount = 1;
839 loadmodel->animscenes[i].framerate = 10;
840 loadmodel->animscenes[i].loop = true;
845 loadmodel->alias.aliasdata_meshes->data_neighbor3i = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_triangles * sizeof(int[3]));
846 Mod_BuildTriangleNeighbors(loadmodel->alias.aliasdata_meshes->data_neighbor3i, loadmodel->alias.aliasdata_meshes->data_element3i, loadmodel->alias.aliasdata_meshes->num_triangles);
847 Mod_CalcAliasModelBBoxes();
850 void Mod_IDP3_Load(model_t *mod, void *buffer)
852 int i, j, k, version;
853 md3modelheader_t *pinmodel;
854 md3frameinfo_t *pinframe;
858 skinfile_t *skinfiles;
862 if (memcmp(pinmodel->identifier, "IDP3", 4))
863 Host_Error ("%s is not a MD3 (IDP3) file\n", loadmodel->name);
864 version = LittleLong (pinmodel->version);
865 if (version != MD3VERSION)
866 Host_Error ("%s has wrong version number (%i should be %i)",
867 loadmodel->name, version, MD3VERSION);
869 skinfiles = Mod_LoadSkinFiles();
870 if (loadmodel->numskins < 1)
871 loadmodel->numskins = 1;
873 loadmodel->type = mod_alias;
874 loadmodel->DrawSky = NULL;
875 loadmodel->Draw = R_Model_Alias_Draw;
876 loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume;
877 loadmodel->DrawLight = R_Model_Alias_DrawLight;
878 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
879 loadmodel->flags = LittleLong(pinmodel->flags);
880 loadmodel->synctype = ST_RAND;
882 // set up some global info about the model
883 loadmodel->numframes = LittleLong(pinmodel->num_frames);
884 loadmodel->alias.aliasnum_meshes = LittleLong(pinmodel->num_meshes);
886 // make skinscenes for the skins (no groups)
887 loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
888 for (i = 0;i < loadmodel->numskins;i++)
890 loadmodel->skinscenes[i].firstframe = i;
891 loadmodel->skinscenes[i].framecount = 1;
892 loadmodel->skinscenes[i].loop = true;
893 loadmodel->skinscenes[i].framerate = 10;
897 loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
898 for (i = 0, pinframe = (md3frameinfo_t *)((qbyte *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
900 strcpy(loadmodel->animscenes[i].name, pinframe->name);
901 loadmodel->animscenes[i].firstframe = i;
902 loadmodel->animscenes[i].framecount = 1;
903 loadmodel->animscenes[i].framerate = 10;
904 loadmodel->animscenes[i].loop = true;
908 loadmodel->alias.aliasnum_tagframes = loadmodel->numframes;
909 loadmodel->alias.aliasnum_tags = LittleLong(pinmodel->num_tags);
910 loadmodel->alias.aliasdata_tags = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasnum_tagframes * loadmodel->alias.aliasnum_tags * sizeof(aliastag_t));
911 for (i = 0, pintag = (md3tag_t *)((qbyte *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->alias.aliasnum_tagframes * loadmodel->alias.aliasnum_tags;i++, pintag++)
913 strcpy(loadmodel->alias.aliasdata_tags[i].name, pintag->name);
914 Matrix4x4_CreateIdentity(&loadmodel->alias.aliasdata_tags[i].matrix);
915 for (j = 0;j < 3;j++)
917 for (k = 0;k < 3;k++)
918 loadmodel->alias.aliasdata_tags[i].matrix.m[j][k] = LittleFloat(pintag->rotationmatrix[k * 3 + j]);
919 loadmodel->alias.aliasdata_tags[i].matrix.m[j][3] = LittleFloat(pintag->origin[j]);
921 //Con_Printf("model \"%s\" frame #%i tag #%i \"%s\"\n", loadmodel->name, i / loadmodel->alias.aliasnum_tags, i % loadmodel->alias.aliasnum_tags, loadmodel->alias.aliasdata_tags[i].name);
925 loadmodel->alias.aliasdata_meshes = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasnum_meshes * sizeof(aliasmesh_t));
926 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)))
928 if (memcmp(pinmesh->identifier, "IDP3", 4))
929 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)\n");
930 mesh = loadmodel->alias.aliasdata_meshes + i;
931 mesh->num_skins = loadmodel->numskins;
932 mesh->num_morphframes = LittleLong(pinmesh->num_frames);
933 mesh->num_vertices = LittleLong(pinmesh->num_vertices);
934 mesh->num_triangles = LittleLong(pinmesh->num_triangles);
935 mesh->data_skins = Mem_Alloc(loadmodel->mempool, mesh->num_skins * sizeof(aliasskin_t));
936 mesh->data_element3i = Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
937 mesh->data_neighbor3i = Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
938 mesh->data_texcoord2f = Mem_Alloc(loadmodel->mempool, mesh->num_vertices * sizeof(float[2]));
939 mesh->data_morphvertex3f = Mem_Alloc(loadmodel->mempool, mesh->num_vertices * mesh->num_morphframes * sizeof(float[3]));
940 for (j = 0;j < mesh->num_triangles * 3;j++)
941 mesh->data_element3i[j] = LittleLong(((int *)((qbyte *)pinmesh + pinmesh->lump_elements))[j]);
942 for (j = 0;j < mesh->num_vertices;j++)
944 mesh->data_texcoord2f[j * 2 + 0] = LittleFloat(((float *)((qbyte *)pinmesh + pinmesh->lump_texcoords))[j * 2 + 0]);
945 mesh->data_texcoord2f[j * 2 + 1] = LittleFloat(((float *)((qbyte *)pinmesh + pinmesh->lump_texcoords))[j * 2 + 1]);
947 for (j = 0;j < mesh->num_vertices * mesh->num_morphframes;j++)
949 mesh->data_morphvertex3f[j * 3 + 0] = LittleShort(((short *)((qbyte *)pinmesh + pinmesh->lump_framevertices))[j * 4 + 0]) * (1.0f / 64.0f);
950 mesh->data_morphvertex3f[j * 3 + 1] = LittleShort(((short *)((qbyte *)pinmesh + pinmesh->lump_framevertices))[j * 4 + 1]) * (1.0f / 64.0f);
951 mesh->data_morphvertex3f[j * 3 + 2] = LittleShort(((short *)((qbyte *)pinmesh + pinmesh->lump_framevertices))[j * 4 + 2]) * (1.0f / 64.0f);
954 Mod_ValidateElements(mesh->data_element3i, mesh->num_triangles, mesh->num_vertices, __FILE__, __LINE__);
955 Mod_BuildTriangleNeighbors(mesh->data_neighbor3i, mesh->data_element3i, mesh->num_triangles);
957 if (LittleLong(pinmesh->num_shaders) >= 1)
958 Mod_BuildAliasSkinsFromSkinFiles(mesh->data_skins, skinfiles, pinmesh->name, ((md3shader_t *)((qbyte *) pinmesh + pinmesh->lump_shaders))->name);
960 for (j = 0;j < mesh->num_skins;j++)
961 Mod_BuildAliasSkinFromSkinFrame(mesh->data_skins + j, NULL);
963 Mod_CalcAliasModelBBoxes();
964 Mod_FreeSkinFiles(skinfiles);
967 void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer)
969 zymtype1header_t *pinmodel, *pheader;
971 int i, j, k, l, numposes, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements, *remapvertices;
972 float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f;
973 zymvertex_t *verts, *vertdata;
977 skinfile_t *skinfiles;
980 pinmodel = (void *)buffer;
982 if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
983 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model\n");
984 if (BigLong(pinmodel->type) != 1)
985 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)\n", loadmodel->name);
987 loadmodel->type = mod_alias;
988 loadmodel->DrawSky = NULL;
989 loadmodel->Draw = R_Model_Alias_Draw;
990 loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume;
991 loadmodel->DrawLight = R_Model_Alias_DrawLight;
992 //loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; // FIXME: implement collisions
993 loadmodel->flags = 0; // there are no flags on zym models
994 loadmodel->synctype = ST_RAND;
998 pheader->type = BigLong(pinmodel->type);
999 pheader->filesize = BigLong(pinmodel->filesize);
1000 pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1001 pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1002 pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1003 pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1004 pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1005 pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1006 pheader->radius = BigFloat(pinmodel->radius);
1007 pheader->numverts = BigLong(pinmodel->numverts);
1008 pheader->numtris = BigLong(pinmodel->numtris);
1009 pheader->numshaders = BigLong(pinmodel->numshaders);
1010 pheader->numbones = BigLong(pinmodel->numbones);
1011 pheader->numscenes = BigLong(pinmodel->numscenes);
1012 pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1013 pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1014 pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1015 pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1016 pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1017 pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1018 pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1019 pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1020 pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1021 pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1022 pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1023 pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1024 pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1025 pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1026 pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1027 pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1028 pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1029 pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1031 loadmodel->numframes = pheader->numscenes;
1032 loadmodel->alias.aliasnum_meshes = pheader->numshaders;
1034 skinfiles = Mod_LoadSkinFiles();
1035 if (loadmodel->numskins < 1)
1036 loadmodel->numskins = 1;
1038 // make skinscenes for the skins (no groups)
1039 loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1040 for (i = 0;i < loadmodel->numskins;i++)
1042 loadmodel->skinscenes[i].firstframe = i;
1043 loadmodel->skinscenes[i].framecount = 1;
1044 loadmodel->skinscenes[i].loop = true;
1045 loadmodel->skinscenes[i].framerate = 10;
1049 modelradius = pheader->radius;
1050 for (i = 0;i < 3;i++)
1052 loadmodel->normalmins[i] = pheader->mins[i];
1053 loadmodel->normalmaxs[i] = pheader->maxs[i];
1054 loadmodel->rotatedmins[i] = -modelradius;
1055 loadmodel->rotatedmaxs[i] = modelradius;
1057 corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1058 corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1059 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1060 if (loadmodel->yawmaxs[0] > modelradius)
1061 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1062 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1063 loadmodel->yawmins[2] = loadmodel->normalmins[2];
1064 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1065 loadmodel->radius = modelradius;
1066 loadmodel->radius2 = modelradius * modelradius;
1068 // go through the lumps, swapping things
1070 //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1071 loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1072 scene = (void *) (pheader->lump_scenes.start + pbase);
1073 numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1074 for (i = 0;i < pheader->numscenes;i++)
1076 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1077 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1078 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1079 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1080 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1081 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1082 Host_Error("%s scene->firstframe (%i) >= numposes (%i)\n", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1083 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1084 Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)\n", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1085 if (loadmodel->animscenes[i].framerate < 0)
1086 Host_Error("%s scene->framerate (%f) < 0\n", loadmodel->name, loadmodel->animscenes[i].framerate);
1090 //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1091 loadmodel->alias.aliasnum_poses = pheader->lump_poses.length / sizeof(float[3][4]);
1092 loadmodel->alias.aliasdata_poses = Mem_Alloc(loadmodel->mempool, pheader->lump_poses.length);
1093 poses = (void *) (pheader->lump_poses.start + pbase);
1094 for (i = 0;i < pheader->lump_poses.length / 4;i++)
1095 loadmodel->alias.aliasdata_poses[i] = BigFloat(poses[i]);
1097 //zymlump_t lump_bones; // zymbone_t bone[numbones];
1098 loadmodel->alias.aliasnum_bones = pheader->numbones;
1099 loadmodel->alias.aliasdata_bones = Mem_Alloc(loadmodel->mempool, pheader->numbones * sizeof(aliasbone_t));
1100 bone = (void *) (pheader->lump_bones.start + pbase);
1101 for (i = 0;i < pheader->numbones;i++)
1103 memcpy(loadmodel->alias.aliasdata_bones[i].name, bone[i].name, sizeof(bone[i].name));
1104 loadmodel->alias.aliasdata_bones[i].flags = BigLong(bone[i].flags);
1105 loadmodel->alias.aliasdata_bones[i].parent = BigLong(bone[i].parent);
1106 if (loadmodel->alias.aliasdata_bones[i].parent >= i)
1107 Host_Error("%s bone[%i].parent >= %i\n", loadmodel->name, i, i);
1110 //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1111 vertbonecounts = Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1112 bonecount = (void *) (pheader->lump_vertbonecounts.start + pbase);
1113 for (i = 0;i < pheader->numverts;i++)
1115 vertbonecounts[i] = BigLong(bonecount[i]);
1116 if (vertbonecounts[i] < 1)
1117 Host_Error("%s bonecount[%i] < 1\n", loadmodel->name, i);
1120 //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
1121 verts = Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
1122 vertdata = (void *) (pheader->lump_verts.start + pbase);
1123 for (i = 0;i < pheader->lump_verts.length / (int) sizeof(zymvertex_t);i++)
1125 verts[i].bonenum = BigLong(vertdata[i].bonenum);
1126 verts[i].origin[0] = BigFloat(vertdata[i].origin[0]);
1127 verts[i].origin[1] = BigFloat(vertdata[i].origin[1]);
1128 verts[i].origin[2] = BigFloat(vertdata[i].origin[2]);
1131 //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
1132 outtexcoord2f = Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(float[2]));
1133 intexcoord2f = (void *) (pheader->lump_texcoords.start + pbase);
1134 for (i = 0;i < pheader->numverts;i++)
1136 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
1137 // flip T coordinate for OpenGL
1138 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
1141 //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
1142 //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
1143 //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
1145 loadmodel->alias.aliasdata_meshes = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasnum_meshes * sizeof(aliasmesh_t));
1147 //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
1148 //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)
1149 // byteswap, validate, and swap winding order of tris
1150 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
1151 if (pheader->lump_render.length != count)
1152 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)\n", loadmodel->name, pheader->lump_render.length, count);
1153 renderlist = (void *) (pheader->lump_render.start + pbase);
1154 renderlistend = (void *) ((qbyte *) renderlist + pheader->lump_render.length);
1155 for (i = 0;i < loadmodel->alias.aliasnum_meshes;i++)
1157 if (renderlist >= renderlistend)
1158 Host_Error("%s corrupt renderlist (wrong size)\n", loadmodel->name);
1159 count = BigLong(*renderlist);renderlist++;
1160 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
1161 Host_Error("%s corrupt renderlist (wrong size)\n", loadmodel->name);
1162 mesh = loadmodel->alias.aliasdata_meshes + i;
1163 mesh->num_skins = loadmodel->numskins;
1164 mesh->num_triangles = count;
1165 mesh->data_skins = Mem_Alloc(loadmodel->mempool, mesh->num_skins * sizeof(aliasskin_t));
1166 mesh->data_element3i = Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
1167 mesh->data_neighbor3i = Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
1168 outelements = mesh->data_element3i;
1169 for (j = 0;j < mesh->num_triangles;j++)
1171 outelements[2] = BigLong(renderlist[0]);
1172 outelements[1] = BigLong(renderlist[1]);
1173 outelements[0] = BigLong(renderlist[2]);
1174 if ((unsigned int)outelements[0] >= (unsigned int)pheader->numverts
1175 || (unsigned int)outelements[1] >= (unsigned int)pheader->numverts
1176 || (unsigned int)outelements[2] >= (unsigned int)pheader->numverts)
1177 Host_Error("%s corrupt renderlist (out of bounds index)\n", loadmodel->name);
1181 remapvertices = Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1182 mesh->num_vertices = Mod_BuildVertexRemapTableFromElements(mesh->num_triangles * 3, mesh->data_element3i, pheader->numverts, remapvertices);
1183 for (j = 0;j < mesh->num_triangles * 3;j++)
1184 mesh->data_element3i[j] = remapvertices[mesh->data_element3i[j]];
1185 Mod_BuildTriangleNeighbors(mesh->data_neighbor3i, mesh->data_element3i, mesh->num_triangles);
1186 mesh->data_texcoord2f = Mem_Alloc(loadmodel->mempool, mesh->num_vertices * sizeof(float[2]));
1187 for (j = 0;j < pheader->numverts;j++)
1189 if (remapvertices[j] >= 0)
1191 mesh->data_texcoord2f[remapvertices[j]*2+0] = outtexcoord2f[j*2+0];
1192 mesh->data_texcoord2f[remapvertices[j]*2+1] = outtexcoord2f[j*2+1];
1195 mesh->num_vertexboneweights = 0;
1196 for (j = 0;j < mesh->num_vertices;j++)
1197 if (remapvertices[j] >= 0)
1198 mesh->num_vertexboneweights += vertbonecounts[remapvertices[j]];
1199 mesh->data_vertexboneweights = Mem_Alloc(loadmodel->mempool, mesh->num_vertexboneweights * sizeof(aliasvertexboneweight_t));
1200 mesh->num_vertexboneweights = 0;
1201 // note this vertexboneweight ordering requires that the remapvertices array is sequential numbers (separated by -1 values for omitted vertices)
1203 for (j = 0;j < mesh->num_vertices;j++)
1205 if (remapvertices[j] < 0)
1207 l += vertbonecounts[j];
1210 for (k = 0;k < vertbonecounts[j];k++)
1212 // this format really should have had a per vertexweight weight value...
1213 mesh->data_vertexboneweights[mesh->num_vertexboneweights].vertexindex = remapvertices[j];
1214 mesh->data_vertexboneweights[mesh->num_vertexboneweights].boneindex = verts[l].bonenum;
1215 mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[3] = 1.0f / vertbonecounts[j];
1216 mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[0] = verts[l].origin[0] * mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[3];
1217 mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[1] = verts[l].origin[1] * mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[3];
1218 mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[2] = verts[l].origin[2] * mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[3];
1219 mesh->num_vertexboneweights++;
1224 Mod_ValidateElements(mesh->data_element3i, mesh->num_triangles, mesh->num_vertices, __FILE__, __LINE__);
1225 Mod_BuildTriangleNeighbors(mesh->data_neighbor3i, mesh->data_element3i, mesh->num_triangles);
1227 // since zym models do not have named sections, reuse their shader
1228 // name as the section name
1229 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
1231 Mod_BuildAliasSkinsFromSkinFiles(mesh->data_skins, skinfiles, shadername, shadername);
1233 for (j = 0;j < mesh->num_skins;j++)
1234 Mod_BuildAliasSkinFromSkinFrame(mesh->data_skins + j, NULL);
1237 Mem_Free(vertbonecounts);
1239 Mem_Free(outtexcoord2f);