diff --git a/src/client/refresh/files/models.c b/src/client/refresh/files/models.c index 167d80bb..7e5dd1d8 100644 --- a/src/client/refresh/files/models.c +++ b/src/client/refresh/files/models.c @@ -26,12 +26,316 @@ #include "../ref_shared.h" +/* +================= +Mod_LoadMDL +================= +*/ +static void * +Mod_LoadMDL (const char *mod_name, const void *buffer, int modfilelen, + vec3_t mins, vec3_t maxs, struct image_s **skins, findimage_t find_image, + modtype_t *type) +{ + const dmdlo_t *pinmodel; + int version; + dmdl_t *pheader; + void *extradata; + + /* local copy of all values */ + int skinwidth, skinheight, framesize; + int num_skins, num_xyz, num_st, num_tris, num_glcmds, num_frames; + int ofs_skins, ofs_st, ofs_tris, ofs_frames, ofs_glcmds, ofs_end; + + pinmodel = (dmdlo_t *)buffer; + + version = LittleLong (pinmodel->version); + if (version != MDL_VERSION) + { + R_Printf(PRINT_ALL, "%s: %s has wrong version number (%i should be %i)", + __func__, mod_name, version, MDL_VERSION); + return NULL; + } + + /* generate all offsets and sizes */ + num_skins = LittleLong (pinmodel->num_skins); + skinwidth = LittleLong (pinmodel->skinwidth); + skinheight = LittleLong (pinmodel->skinheight); + num_xyz = LittleLong (pinmodel->num_xyz); + num_st = num_xyz; + num_tris = LittleLong (pinmodel->num_tris); + num_glcmds = ( + (3 * num_tris) * sizeof(int) * 3 + /* 3 vert */ + (num_tris * sizeof(int)) + /* triangles count */ + sizeof(int) /* final zero */) / sizeof(int); + num_frames = LittleLong (pinmodel->num_frames); + framesize = sizeof(daliasframe_t) + sizeof (dtrivertx_t) * (num_xyz - 1); + + ofs_skins = sizeof(dmdl_t); // just skip header and go + ofs_st = ofs_skins + num_skins * MAX_SKINNAME; + ofs_tris = ofs_st + num_st * sizeof(dstvert_t); + ofs_glcmds = ofs_tris + num_tris * sizeof(dtriangle_t); + ofs_frames = ofs_glcmds + num_glcmds * sizeof(int); + /* one less as single vertx in frame by default */ + ofs_end = ofs_frames + framesize * num_frames; + + /* validate */ + if (skinheight > MAX_LBM_HEIGHT) + { + R_Printf(PRINT_ALL, "%s: model %s has a skin taller than %d", + __func__, mod_name, MAX_LBM_HEIGHT); + return NULL; + } + + if (skinwidth > MAX_LBM_HEIGHT) + { + R_Printf(PRINT_ALL, "%s: model %s has a skin wider than %d", + __func__, mod_name, MAX_LBM_HEIGHT); + return NULL; + } + + if (num_xyz <= 0) + { + R_Printf(PRINT_ALL, "%s: model %s has no vertices", + __func__, mod_name); + return NULL; + } + + if (num_xyz > MAX_VERTS) + { + R_Printf(PRINT_ALL, "%s: model %s has too many vertices", + __func__, mod_name); + return NULL; + } + + if (num_tris <= 0) + { + R_Printf(PRINT_ALL, "%s: model %s has no triangles", + __func__, mod_name); + return NULL; + } + + if (num_frames <= 0) + { + R_Printf(PRINT_ALL, "%s: model %s has no frames", + __func__, mod_name); + return NULL; + } + + if (modfilelen < ofs_end) + { + R_Printf(PRINT_ALL, "%s: model %s is too big.", + __func__, mod_name); + return NULL; + } + + extradata = Hunk_Begin(ofs_end); + pheader = Hunk_Alloc(ofs_end); + + /* copy back all values */ + pheader->ident = IDALIASHEADER; + pheader->version = ALIAS_VERSION; + pheader->skinwidth = skinwidth; + pheader->skinheight = skinheight; + pheader->framesize = framesize; + + pheader->num_skins = num_skins; + pheader->num_xyz = num_xyz; + pheader->num_st = num_st; + pheader->num_tris = num_tris; + pheader->num_glcmds = num_glcmds; + pheader->num_frames = num_frames; + + pheader->ofs_skins = ofs_skins; + pheader->ofs_st = ofs_st; + pheader->ofs_tris = ofs_tris; + pheader->ofs_frames = ofs_frames; + pheader->ofs_glcmds = ofs_glcmds; + pheader->ofs_end = ofs_end; + + { + int i; + const byte *curr_pos; + + struct mdl_triangle_t *triangles; + struct mdl_texcoord_t *texcoords; + + curr_pos = (byte*)buffer + sizeof (struct mdl_header_t); + + // register all skins + for (i = 0; i < num_skins; ++i) + { + char *out_pos; + int skin_type; + + out_pos = (char*)pheader + sizeof(dmdl_t); + snprintf(out_pos + MAX_SKINNAME * i, MAX_SKINNAME, "%s#%d.tga", mod_name, i); + + /* skip type / int */ + /* 0 = simple, !0 = group */ + /* this program can't read models composed of group frames! */ + skin_type = LittleLong (((int *)curr_pos)[0]); + curr_pos += sizeof(int); + if (skin_type) + { + R_Printf(PRINT_ALL, "%s: model %s has unsupported skin type %d", + __func__, mod_name, skin_type); + return NULL; + } + + /* skip 8bit image */ + curr_pos += skinwidth * skinheight; + } + + /* texcoordinates */ + { + dstvert_t *poutst = (dstvert_t *) ((byte *)pheader + ofs_st); + + texcoords = (struct mdl_texcoord_t *)curr_pos; + curr_pos += sizeof (struct mdl_texcoord_t) * num_st; + + for(i = 0; i < num_st; i++) + { + /* Compute texture coordinates */ + poutst[i].s = LittleLong (texcoords[i].s); + poutst[i].t = LittleLong (texcoords[i].t); + + if (texcoords[i].onseam) + { + poutst[i].s += skinwidth * 0.5f; /* Backface */ + } + + /* Scale s and t to range from 0.0 to 1.0 */ + poutst[i].s = (poutst[i].s + 0.5) / skinwidth; + poutst[i].t = (poutst[i].t + 0.5) / skinheight; + } + } + + /* triangles */ + { + dtriangle_t *pouttri = (dtriangle_t *) ((byte *)pheader + ofs_tris); + + triangles = (struct mdl_triangle_t *) curr_pos; + curr_pos += sizeof (struct mdl_triangle_t) * num_tris; + + for (i=0 ; iscale[0] = LittleFloat (pinmodel->scale[0]); + frame->scale[1] = LittleFloat (pinmodel->scale[1]); + frame->scale[2] = LittleFloat (pinmodel->scale[2]); + + frame->translate[0] = LittleFloat (pinmodel->translate[0]); + frame->translate[1] = LittleFloat (pinmodel->translate[1]); + frame->translate[2] = LittleFloat (pinmodel->translate[2]); + + /* Read frame data */ + /* skip type / int */ + /* 0 = simple, !0 = group */ + /* this program can't read models composed of group frames! */ + frame_type = LittleLong (((int *)curr_pos)[0]); + curr_pos += sizeof (frame_type); + + if (frame_type) + { + R_Printf(PRINT_ALL, "%s: model %s has unsupported frame type %d", + __func__, mod_name, frame_type); + return NULL; + } + /* skip bboxmin, bouding box min */ + curr_pos += sizeof(dtrivertx_t); + /* skip bboxmax, bouding box max */ + curr_pos += sizeof(dtrivertx_t); + + memcpy(&frame->name, curr_pos, sizeof (char) * 16); + curr_pos += sizeof (char) * 16; + + memcpy(&frame->verts[0], curr_pos, + sizeof (dtrivertx_t) * num_xyz); + curr_pos += sizeof (dtrivertx_t) * num_xyz; + } + } + + *type = mod_alias; + + mins[0] = -32; + mins[1] = -32; + mins[2] = -32; + maxs[0] = 32; + maxs[1] = 32; + maxs[2] = 32; + + return extradata; +} + /* ================= Mod_LoadAliasModel/Mod_LoadMD2 ================= */ -void * +static void * Mod_LoadMD2 (const char *mod_name, const void *buffer, int modfilelen, vec3_t mins, vec3_t maxs, struct image_s **skins, findimage_t find_image, modtype_t *type) @@ -207,6 +511,32 @@ Mod_LoadMD2 (const char *mod_name, const void *buffer, int modfilelen, return extradata; } +/* +================= +Mod_LoadAliasModel +================= +*/ +void * +Mod_LoadAliasModel (const char *mod_name, const void *buffer, int modfilelen, + vec3_t mins, vec3_t maxs, struct image_s **skins, findimage_t find_image, + modtype_t *type) +{ + switch (LittleLong(*(unsigned *)buffer)) + { + case IDALIASHEADER: + return Mod_LoadMD2(mod_name, buffer, modfilelen, mins, maxs, skins, + find_image, type); + + case IDMDLHEADER: + return Mod_LoadMDL(mod_name, buffer, modfilelen, mins, maxs, skins, + find_image, type); + + } + + return NULL; +} + + /* ============================================================================== @@ -270,6 +600,65 @@ Mod_LoadSP2 (const char *mod_name, const void *buffer, int modfilelen, return extradata; } +/* +================= +Mod_LoadFile +================= +*/ +int +Mod_LoadFile(char *name, void **buffer) +{ + const char* ext; + + *buffer = NULL; + + if (!name) + { + return -1; + } + + ext = COM_FileExtension(name); + if(!ext[0]) + { + /* file has no extension */ + return -1; + } + + if (!strcmp(ext, "md2") || + !strcmp(ext, "mdl")) + { + char namewe[256], newname[256]; + int filesize, len; + + len = strlen(name); + if (len < 5) + { + return -1; + } + + /* Remove the extension */ + memset(namewe, 0, 256); + memcpy(namewe, name, len - (strlen(ext) + 1)); + + /* Check Quake 2 model */ + snprintf(newname, sizeof(newname), "%s.md2", namewe); + filesize = ri.FS_LoadFile (newname, buffer); + if (filesize > 0) + { + return filesize; + } + + /* Check Quake model */ + snprintf(newname, sizeof(newname), "%s.mdl", namewe); + filesize = ri.FS_LoadFile (newname, buffer); + if (filesize > 0) + { + return filesize; + } + } + return ri.FS_LoadFile (name, buffer); +} + /* ================= Mod_ReLoad diff --git a/src/client/refresh/gl1/gl1_model.c b/src/client/refresh/gl1/gl1_model.c index cdf30df9..7b8cdc17 100644 --- a/src/client/refresh/gl1/gl1_model.c +++ b/src/client/refresh/gl1/gl1_model.c @@ -211,7 +211,7 @@ Mod_ForName (char *name, model_t *parent_model, qboolean crash) { case IDALIASHEADER: { - mod->extradata = Mod_LoadMD2(mod->name, buf, modfilelen, + mod->extradata = Mod_LoadAliasModel(mod->name, buf, modfilelen, mod->mins, mod->maxs, (struct image_s **)mod->skins, (findimage_t)R_FindImage, &(mod->type)); diff --git a/src/client/refresh/gl3/gl3_model.c b/src/client/refresh/gl3/gl3_model.c index 78e8c837..caaab74c 100644 --- a/src/client/refresh/gl3/gl3_model.c +++ b/src/client/refresh/gl3/gl3_model.c @@ -693,7 +693,7 @@ Mod_ForName (char *name, gl3model_t *parent_model, qboolean crash) { case IDALIASHEADER: { - mod->extradata = Mod_LoadMD2(mod->name, buf, modfilelen, + mod->extradata = Mod_LoadAliasModel(mod->name, buf, modfilelen, mod->mins, mod->maxs, (struct image_s **)mod->skins, (findimage_t)GL3_FindImage, &(mod->type)); diff --git a/src/client/refresh/ref_shared.h b/src/client/refresh/ref_shared.h index 79063178..0d445ce5 100644 --- a/src/client/refresh/ref_shared.h +++ b/src/client/refresh/ref_shared.h @@ -178,7 +178,7 @@ typedef struct mleaf_s /* Shared models func */ typedef struct image_s* (*findimage_t)(const char *name, imagetype_t type); -extern void *Mod_LoadMD2 (const char *mod_name, const void *buffer, int modfilelen, +extern void *Mod_LoadAliasModel (const char *mod_name, const void *buffer, int modfilelen, vec3_t mins, vec3_t maxs, struct image_s **skins, findimage_t find_image, modtype_t *type); extern void *Mod_LoadSP2 (const char *mod_name, const void *buffer, int modfilelen, @@ -217,6 +217,7 @@ extern mleaf_t *Mod_PointInLeaf(const vec3_t p, mnode_t *node); extern const void *Mod_LoadBSPXFindLump(const bspx_header_t *bspx_header, const char *lumpname, int *plumpsize, const byte *mod_base); extern const bspx_header_t *Mod_LoadBSPX(int filesize, const byte *mod_base); +int Mod_LoadFile(char *name, void **buffer); /* Surface logic */ #define DLIGHT_CUTOFF 64 diff --git a/src/client/refresh/soft/sw_model.c b/src/client/refresh/soft/sw_model.c index 25cef30b..7414be95 100644 --- a/src/client/refresh/soft/sw_model.c +++ b/src/client/refresh/soft/sw_model.c @@ -198,7 +198,7 @@ Mod_ForName (char *name, model_t *parent_model, qboolean crash) { case IDALIASHEADER: { - mod->extradata = Mod_LoadMD2(mod->name, buf, modfilelen, + mod->extradata = Mod_LoadAliasModel(mod->name, buf, modfilelen, mod->mins, mod->maxs, (struct image_s **)mod->skins, (findimage_t)R_FindImage, &(mod->type)); diff --git a/src/common/header/files.h b/src/common/header/files.h index 35bf1386..04592a7e 100644 --- a/src/common/header/files.h +++ b/src/common/header/files.h @@ -65,6 +65,50 @@ typedef struct unsigned char data; /* unbounded */ } pcx_t; +/* .MDL triangle model file format */ + +#define IDMDLHEADER (('O' << 24) + ('P' << 16) + ('D' << 8) + 'I') +#define MDL_VERSION 6 + +/* Texture coords */ +struct mdl_texcoord_t +{ + int onseam; + int s; + int t; +}; + +/* Triangle info */ +struct mdl_triangle_t +{ + int facesfront; /* 0 = backface, 1 = frontface */ + int vertex[3]; /* vertex indices */ +}; + +/* MDL header */ +typedef struct mdl_header_t +{ + int ident; /* magic number: "IDPO" */ + int version; /* version: 6 */ + + vec3_t scale; /* scale factor */ + vec3_t translate; /* translation vector */ + float boundingradius; + vec3_t eyeposition; /* eyes' position */ + + int num_skins; /* number of textures */ + int skinwidth; /* texture width */ + int skinheight; /* texture height */ + + int num_xyz; /* number of vertices */ + int num_tris; /* number of triangles */ + int num_frames; /* number of frames */ + + int synctype; /* 0 = synchron, 1 = random */ + int flags; /* state flag */ + float size; /* average size of triangles */ +} dmdlo_t; + /* .MD2 triangle model file format */ #define IDALIASHEADER (('2' << 24) + ('P' << 16) + ('D' << 8) + 'I')