181 lines
5.4 KiB
C++
181 lines
5.4 KiB
C++
struct md3;
|
|
|
|
struct md3frame
|
|
{
|
|
vec bbmin, bbmax, origin;
|
|
float radius;
|
|
uchar name[16];
|
|
};
|
|
|
|
struct md3tag
|
|
{
|
|
char name[64];
|
|
float translation[3];
|
|
float rotation[3][3];
|
|
};
|
|
|
|
struct md3vertex
|
|
{
|
|
short vertex[3];
|
|
short normal;
|
|
};
|
|
|
|
struct md3triangle
|
|
{
|
|
int vertexindices[3];
|
|
};
|
|
|
|
struct md3header
|
|
{
|
|
char id[4];
|
|
int version;
|
|
char name[64];
|
|
int flags;
|
|
int numframes, numtags, nummeshes, numskins;
|
|
int ofs_frames, ofs_tags, ofs_meshes, ofs_eof; // offsets
|
|
};
|
|
|
|
struct md3meshheader
|
|
{
|
|
char id[4];
|
|
char name[64];
|
|
int flags;
|
|
int numframes, numshaders, numvertices, numtriangles;
|
|
int ofs_triangles, ofs_shaders, ofs_uv, ofs_vertices, meshsize; // offsets
|
|
};
|
|
|
|
struct md3 : vertloader<md3>
|
|
{
|
|
md3(const char *name) : vertloader(name) {}
|
|
|
|
static const char *formatname() { return "md3"; }
|
|
bool flipy() const { return true; }
|
|
int type() const { return MDL_MD3; }
|
|
|
|
struct md3meshgroup : vertmeshgroup
|
|
{
|
|
bool load(const char *path, float smooth)
|
|
{
|
|
stream *f = openfile(path, "rb");
|
|
if(!f) return false;
|
|
md3header header;
|
|
f->read(&header, sizeof(md3header));
|
|
lilswap(&header.version, 1);
|
|
lilswap(&header.flags, 9);
|
|
if(strncmp(header.id, "IDP3", 4) != 0 || header.version != 15) // header check
|
|
{
|
|
delete f;
|
|
conoutf(CON_ERROR, "md3: corrupted header");
|
|
return false;
|
|
}
|
|
|
|
name = newstring(path);
|
|
|
|
numframes = header.numframes;
|
|
|
|
int mesh_offset = header.ofs_meshes;
|
|
loopi(header.nummeshes)
|
|
{
|
|
vertmesh &m = *new vertmesh;
|
|
m.group = this;
|
|
meshes.add(&m);
|
|
|
|
md3meshheader mheader;
|
|
f->seek(mesh_offset, SEEK_SET);
|
|
f->read(&mheader, sizeof(md3meshheader));
|
|
lilswap(&mheader.flags, 10);
|
|
|
|
m.name = newstring(mheader.name);
|
|
|
|
m.numtris = mheader.numtriangles;
|
|
m.tris = new tri[m.numtris];
|
|
f->seek(mesh_offset + mheader.ofs_triangles, SEEK_SET);
|
|
loopj(m.numtris)
|
|
{
|
|
md3triangle tri;
|
|
f->read(&tri, sizeof(md3triangle)); // read the triangles
|
|
lilswap(tri.vertexindices, 3);
|
|
loopk(3) m.tris[j].vert[k] = (ushort)tri.vertexindices[k];
|
|
}
|
|
|
|
m.numverts = mheader.numvertices;
|
|
m.tcverts = new tcvert[m.numverts];
|
|
f->seek(mesh_offset + mheader.ofs_uv , SEEK_SET);
|
|
f->read(m.tcverts, m.numverts*2*sizeof(float)); // read the UV data
|
|
lilswap(&m.tcverts[0].tc.x, 2*m.numverts);
|
|
|
|
m.verts = new vert[numframes*m.numverts];
|
|
f->seek(mesh_offset + mheader.ofs_vertices, SEEK_SET);
|
|
loopj(numframes*m.numverts)
|
|
{
|
|
md3vertex v;
|
|
f->read(&v, sizeof(md3vertex)); // read the vertices
|
|
lilswap(v.vertex, 4);
|
|
|
|
m.verts[j].pos = vec(v.vertex[0]/64.0f, -v.vertex[1]/64.0f, v.vertex[2]/64.0f);
|
|
|
|
float lng = (v.normal&0xFF)*2*M_PI/255.0f; // decode vertex normals
|
|
float lat = ((v.normal>>8)&0xFF)*2*M_PI/255.0f;
|
|
m.verts[j].norm = vec(cosf(lat)*sinf(lng), -sinf(lat)*sinf(lng), cosf(lng));
|
|
}
|
|
|
|
m.calctangents();
|
|
|
|
mesh_offset += mheader.meshsize;
|
|
}
|
|
|
|
numtags = header.numtags;
|
|
if(numtags)
|
|
{
|
|
tags = new tag[numframes*numtags];
|
|
f->seek(header.ofs_tags, SEEK_SET);
|
|
md3tag tag;
|
|
|
|
loopi(header.numframes*header.numtags)
|
|
{
|
|
f->read(&tag, sizeof(md3tag));
|
|
lilswap(tag.translation, 12);
|
|
if(tag.name[0] && i<header.numtags) tags[i].name = newstring(tag.name);
|
|
matrix4x3 &m = tags[i].matrix;
|
|
tag.translation[1] *= -1;
|
|
// undo the -y
|
|
loopj(3) tag.rotation[1][j] *= -1;
|
|
// then restore it
|
|
loopj(3) tag.rotation[j][1] *= -1;
|
|
m.a = vec(tag.rotation[0]);
|
|
m.b = vec(tag.rotation[1]);
|
|
m.c = vec(tag.rotation[2]);
|
|
m.d = vec(tag.translation);
|
|
}
|
|
}
|
|
|
|
delete f;
|
|
return true;
|
|
}
|
|
};
|
|
|
|
vertmeshgroup *newmeshes() { return new md3meshgroup; }
|
|
|
|
bool loaddefaultparts()
|
|
{
|
|
const char *pname = parentdir(name);
|
|
part &mdl = addpart();
|
|
defformatstring(name1, "media/model/%s/tris.md3", name);
|
|
mdl.meshes = sharemeshes(path(name1));
|
|
if(!mdl.meshes)
|
|
{
|
|
defformatstring(name2, "media/model/%s/tris.md3", pname); // try md3 in parent folder (vert sharing)
|
|
mdl.meshes = sharemeshes(path(name2));
|
|
if(!mdl.meshes) return false;
|
|
}
|
|
Texture *tex, *masks;
|
|
loadskin(name, pname, tex, masks);
|
|
mdl.initskins(tex, masks);
|
|
if(tex==notexture) conoutf(CON_ERROR, "could not load model skin for %s", name1);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
vertcommands<md3> md3commands;
|
|
|