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(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 md3commands;