mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2025-02-24 12:52:21 +00:00
Add Quake mdl format support
http://tfc.duke.free.fr/coding/mdl-specs-en.html
This commit is contained in:
parent
bd5685d201
commit
db436ee6e4
6 changed files with 439 additions and 5 deletions
|
@ -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 ; i<num_tris ; i++)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
pouttri[i].index_xyz[j] = LittleLong (triangles[i].vertex[j]);
|
||||
pouttri[i].index_st[j] = pouttri[i].index_xyz[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int *glcmds = (int *) ((byte *)pheader + ofs_glcmds);
|
||||
|
||||
/* commands */
|
||||
int j, *curr_com = glcmds;
|
||||
|
||||
/* Draw each triangle */
|
||||
for (i = 0; i < num_tris; ++i)
|
||||
{
|
||||
*curr_com = 3;
|
||||
curr_com++;
|
||||
|
||||
/* Draw each vertex */
|
||||
for (j = 0; j < 3; ++j)
|
||||
{
|
||||
float s,t;
|
||||
int index;
|
||||
|
||||
index = triangles[i].vertex[j];
|
||||
|
||||
/* Compute texture coordinates */
|
||||
s = LittleLong (texcoords[index].s);
|
||||
t = LittleLong (texcoords[index].t);
|
||||
|
||||
if (!triangles[i].facesfront &&
|
||||
texcoords[index].onseam)
|
||||
{
|
||||
s += skinwidth * 0.5f; /* Backface */
|
||||
}
|
||||
|
||||
/* Scale s and t to range from 0.0 to 1.0 */
|
||||
s = (s + 0.5) / skinwidth;
|
||||
t = (t + 0.5) / skinheight;
|
||||
|
||||
memcpy(curr_com, &s, sizeof(s));
|
||||
curr_com++;
|
||||
memcpy(curr_com, &t, sizeof(t));
|
||||
curr_com++;
|
||||
memcpy(curr_com, &index, sizeof(index));
|
||||
curr_com++;
|
||||
}
|
||||
}
|
||||
|
||||
*curr_com = 0;
|
||||
curr_com++;
|
||||
}
|
||||
|
||||
/* register all frames */
|
||||
for (i = 0; i < num_frames; ++i)
|
||||
{
|
||||
daliasframe_t *frame;
|
||||
int frame_type;
|
||||
|
||||
frame = (daliasframe_t *) ((byte *)pheader + ofs_frames + i * framesize);
|
||||
frame->scale[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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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')
|
||||
|
|
Loading…
Reference in a new issue