struct md2; static const float md2normaltable[256][3] = { { -0.525731f, 0.000000f, 0.850651f }, { -0.442863f, 0.238856f, 0.864188f }, { -0.295242f, 0.000000f, 0.955423f }, { -0.309017f, 0.500000f, 0.809017f }, { -0.162460f, 0.262866f, 0.951056f }, { 0.000000f, 0.000000f, 1.000000f }, { 0.000000f, 0.850651f, 0.525731f }, { -0.147621f, 0.716567f, 0.681718f }, { 0.147621f, 0.716567f, 0.681718f }, { 0.000000f, 0.525731f, 0.850651f }, { 0.309017f, 0.500000f, 0.809017f }, { 0.525731f, 0.000000f, 0.850651f }, { 0.295242f, 0.000000f, 0.955423f }, { 0.442863f, 0.238856f, 0.864188f }, { 0.162460f, 0.262866f, 0.951056f }, { -0.681718f, 0.147621f, 0.716567f }, { -0.809017f, 0.309017f, 0.500000f }, { -0.587785f, 0.425325f, 0.688191f }, { -0.850651f, 0.525731f, 0.000000f }, { -0.864188f, 0.442863f, 0.238856f }, { -0.716567f, 0.681718f, 0.147621f }, { -0.688191f, 0.587785f, 0.425325f }, { -0.500000f, 0.809017f, 0.309017f }, { -0.238856f, 0.864188f, 0.442863f }, { -0.425325f, 0.688191f, 0.587785f }, { -0.716567f, 0.681718f, -0.147621f }, { -0.500000f, 0.809017f, -0.309017f }, { -0.525731f, 0.850651f, 0.000000f }, { 0.000000f, 0.850651f, -0.525731f }, { -0.238856f, 0.864188f, -0.442863f }, { 0.000000f, 0.955423f, -0.295242f }, { -0.262866f, 0.951056f, -0.162460f }, { 0.000000f, 1.000000f, 0.000000f }, { 0.000000f, 0.955423f, 0.295242f }, { -0.262866f, 0.951056f, 0.162460f }, { 0.238856f, 0.864188f, 0.442863f }, { 0.262866f, 0.951056f, 0.162460f }, { 0.500000f, 0.809017f, 0.309017f }, { 0.238856f, 0.864188f, -0.442863f }, { 0.262866f, 0.951056f, -0.162460f }, { 0.500000f, 0.809017f, -0.309017f }, { 0.850651f, 0.525731f, 0.000000f }, { 0.716567f, 0.681718f, 0.147621f }, { 0.716567f, 0.681718f, -0.147621f }, { 0.525731f, 0.850651f, 0.000000f }, { 0.425325f, 0.688191f, 0.587785f }, { 0.864188f, 0.442863f, 0.238856f }, { 0.688191f, 0.587785f, 0.425325f }, { 0.809017f, 0.309017f, 0.500000f }, { 0.681718f, 0.147621f, 0.716567f }, { 0.587785f, 0.425325f, 0.688191f }, { 0.955423f, 0.295242f, 0.000000f }, { 1.000000f, 0.000000f, 0.000000f }, { 0.951056f, 0.162460f, 0.262866f }, { 0.850651f, -0.525731f, 0.000000f }, { 0.955423f, -0.295242f, 0.000000f }, { 0.864188f, -0.442863f, 0.238856f }, { 0.951056f, -0.162460f, 0.262866f }, { 0.809017f, -0.309017f, 0.500000f }, { 0.681718f, -0.147621f, 0.716567f }, { 0.850651f, 0.000000f, 0.525731f }, { 0.864188f, 0.442863f, -0.238856f }, { 0.809017f, 0.309017f, -0.500000f }, { 0.951056f, 0.162460f, -0.262866f }, { 0.525731f, 0.000000f, -0.850651f }, { 0.681718f, 0.147621f, -0.716567f }, { 0.681718f, -0.147621f, -0.716567f }, { 0.850651f, 0.000000f, -0.525731f }, { 0.809017f, -0.309017f, -0.500000f }, { 0.864188f, -0.442863f, -0.238856f }, { 0.951056f, -0.162460f, -0.262866f }, { 0.147621f, 0.716567f, -0.681718f }, { 0.309017f, 0.500000f, -0.809017f }, { 0.425325f, 0.688191f, -0.587785f }, { 0.442863f, 0.238856f, -0.864188f }, { 0.587785f, 0.425325f, -0.688191f }, { 0.688191f, 0.587785f, -0.425325f }, { -0.147621f, 0.716567f, -0.681718f }, { -0.309017f, 0.500000f, -0.809017f }, { 0.000000f, 0.525731f, -0.850651f }, { -0.525731f, 0.000000f, -0.850651f }, { -0.442863f, 0.238856f, -0.864188f }, { -0.295242f, 0.000000f, -0.955423f }, { -0.162460f, 0.262866f, -0.951056f }, { 0.000000f, 0.000000f, -1.000000f }, { 0.295242f, 0.000000f, -0.955423f }, { 0.162460f, 0.262866f, -0.951056f }, { -0.442863f, -0.238856f, -0.864188f }, { -0.309017f, -0.500000f, -0.809017f }, { -0.162460f, -0.262866f, -0.951056f }, { 0.000000f, -0.850651f, -0.525731f }, { -0.147621f, -0.716567f, -0.681718f }, { 0.147621f, -0.716567f, -0.681718f }, { 0.000000f, -0.525731f, -0.850651f }, { 0.309017f, -0.500000f, -0.809017f }, { 0.442863f, -0.238856f, -0.864188f }, { 0.162460f, -0.262866f, -0.951056f }, { 0.238856f, -0.864188f, -0.442863f }, { 0.500000f, -0.809017f, -0.309017f }, { 0.425325f, -0.688191f, -0.587785f }, { 0.716567f, -0.681718f, -0.147621f }, { 0.688191f, -0.587785f, -0.425325f }, { 0.587785f, -0.425325f, -0.688191f }, { 0.000000f, -0.955423f, -0.295242f }, { 0.000000f, -1.000000f, 0.000000f }, { 0.262866f, -0.951056f, -0.162460f }, { 0.000000f, -0.850651f, 0.525731f }, { 0.000000f, -0.955423f, 0.295242f }, { 0.238856f, -0.864188f, 0.442863f }, { 0.262866f, -0.951056f, 0.162460f }, { 0.500000f, -0.809017f, 0.309017f }, { 0.716567f, -0.681718f, 0.147621f }, { 0.525731f, -0.850651f, 0.000000f }, { -0.238856f, -0.864188f, -0.442863f }, { -0.500000f, -0.809017f, -0.309017f }, { -0.262866f, -0.951056f, -0.162460f }, { -0.850651f, -0.525731f, 0.000000f }, { -0.716567f, -0.681718f, -0.147621f }, { -0.716567f, -0.681718f, 0.147621f }, { -0.525731f, -0.850651f, 0.000000f }, { -0.500000f, -0.809017f, 0.309017f }, { -0.238856f, -0.864188f, 0.442863f }, { -0.262866f, -0.951056f, 0.162460f }, { -0.864188f, -0.442863f, 0.238856f }, { -0.809017f, -0.309017f, 0.500000f }, { -0.688191f, -0.587785f, 0.425325f }, { -0.681718f, -0.147621f, 0.716567f }, { -0.442863f, -0.238856f, 0.864188f }, { -0.587785f, -0.425325f, 0.688191f }, { -0.309017f, -0.500000f, 0.809017f }, { -0.147621f, -0.716567f, 0.681718f }, { -0.425325f, -0.688191f, 0.587785f }, { -0.162460f, -0.262866f, 0.951056f }, { 0.442863f, -0.238856f, 0.864188f }, { 0.162460f, -0.262866f, 0.951056f }, { 0.309017f, -0.500000f, 0.809017f }, { 0.147621f, -0.716567f, 0.681718f }, { 0.000000f, -0.525731f, 0.850651f }, { 0.425325f, -0.688191f, 0.587785f }, { 0.587785f, -0.425325f, 0.688191f }, { 0.688191f, -0.587785f, 0.425325f }, { -0.955423f, 0.295242f, 0.000000f }, { -0.951056f, 0.162460f, 0.262866f }, { -1.000000f, 0.000000f, 0.000000f }, { -0.850651f, 0.000000f, 0.525731f }, { -0.955423f, -0.295242f, 0.000000f }, { -0.951056f, -0.162460f, 0.262866f }, { -0.864188f, 0.442863f, -0.238856f }, { -0.951056f, 0.162460f, -0.262866f }, { -0.809017f, 0.309017f, -0.500000f }, { -0.864188f, -0.442863f, -0.238856f }, { -0.951056f, -0.162460f, -0.262866f }, { -0.809017f, -0.309017f, -0.500000f }, { -0.681718f, 0.147621f, -0.716567f }, { -0.681718f, -0.147621f, -0.716567f }, { -0.850651f, 0.000000f, -0.525731f }, { -0.688191f, 0.587785f, -0.425325f }, { -0.587785f, 0.425325f, -0.688191f }, { -0.425325f, 0.688191f, -0.587785f }, { -0.425325f, -0.688191f, -0.587785f }, { -0.587785f, -0.425325f, -0.688191f }, { -0.688191f, -0.587785f, -0.425325f } }; struct md2 : vertloader { struct md2_header { int magic; int version; int skinwidth, skinheight; int framesize; int numskins, numvertices, numtexcoords; int numtriangles, numglcommands, numframes; int offsetskins, offsettexcoords, offsettriangles; int offsetframes, offsetglcommands, offsetend; }; struct md2_vertex { uchar vertex[3], normalindex; }; struct md2_frame { float scale[3]; float translate[3]; char name[16]; }; md2(const char *name) : vertloader(name) {} static const char *formatname() { return "md2"; } static bool multiparted() { return false; } static bool multimeshed() { return false; } bool flipy() const { return true; } int type() const { return MDL_MD2; } int linktype(animmodel *m, part *p) const { return LINK_COOP; } struct md2meshgroup : vertmeshgroup { void genverts(int *glcommands, vector &tcverts, vector &vindexes, vector &tris) { hashtable tchash; vector idxs; for(int *command = glcommands; (*command)!=0;) { int numvertex = *command++; bool isfan = numvertex<0; if(isfan) numvertex = -numvertex; idxs.setsize(0); loopi(numvertex) { union { int i; float f; } u, v; u.i = *command++; v.i = *command++; int vindex = *command++; ivec tckey(u.i, v.i, vindex); int *idx = tchash.access(tckey); if(!idx) { idx = &tchash[tckey]; *idx = tcverts.length(); tcvert &tc = tcverts.add(); tc.tc = vec2(u.f, v.f); vindexes.add((ushort)vindex); } idxs.add(*idx); } loopi(numvertex-2) { tri &t = tris.add(); if(isfan) { t.vert[0] = idxs[0]; t.vert[1] = idxs[i+1]; t.vert[2] = idxs[i+2]; } else loopk(3) t.vert[k] = idxs[i&1 && k ? i+(1-(k-1))+1 : i+k]; } } } bool load(const char *filename, float smooth) { stream *file = openfile(filename, "rb"); if(!file) return false; md2_header header; file->read(&header, sizeof(md2_header)); lilswap(&header.magic, sizeof(md2_header)/sizeof(int)); if(header.magic!=844121161 || header.version!=8 || header.numframes <= 0 || header.numframes > 1000 || header.numglcommands <= 0 || header.numglcommands > (1<<20) || header.numvertices <= 0 || header.numvertices > (1<<20)) { delete file; return false; } name = newstring(filename); numframes = header.numframes; vertmesh &m = *new vertmesh; m.group = this; meshes.add(&m); int *glcommands = new int[header.numglcommands]; file->seek(header.offsetglcommands, SEEK_SET); int numglcommands = file->read(glcommands, header.numglcommands*sizeof(int))/sizeof(int); lilswap(glcommands, numglcommands); if(numglcommands < header.numglcommands) memset(&glcommands[numglcommands], 0, (header.numglcommands-numglcommands)*sizeof(int)); vector tcgen; vector vgen; vector trigen; genverts(glcommands, tcgen, vgen,trigen); delete[] glcommands; m.numverts = tcgen.length(); m.tcverts = new tcvert[m.numverts]; memcpy(m.tcverts, tcgen.getbuf(), m.numverts*sizeof(tcvert)); m.numtris = trigen.length(); m.tris = new tri[m.numtris]; memcpy(m.tris, trigen.getbuf(), m.numtris*sizeof(tri)); m.verts = new vert[m.numverts*numframes]; md2_vertex *tmpverts = new md2_vertex[header.numvertices]; int frame_offset = header.offsetframes; vert *curvert = m.verts; loopi(header.numframes) { md2_frame frame; file->seek(frame_offset, SEEK_SET); file->read(&frame, sizeof(md2_frame)); lilswap(frame.scale, 6); file->read(tmpverts, header.numvertices*sizeof(md2_vertex)); loopj(m.numverts) { const md2_vertex &v = tmpverts[vgen[j]]; curvert->pos = vec(v.vertex[0]*frame.scale[0]+frame.translate[0], -(v.vertex[1]*frame.scale[1]+frame.translate[1]), v.vertex[2]*frame.scale[2]+frame.translate[2]); const float *norm = md2normaltable[v.normalindex]; curvert->norm = vec(norm[0], -norm[1], norm[2]); ++curvert; } frame_offset += header.framesize; } delete[] tmpverts; m.calctangents(); delete file; return true; } }; vertmeshgroup *newmeshes() { return new md2meshgroup; } bool loadconfig() { return false; } bool loaddefaultparts() { part &mdl = addpart(); const char *pname = parentdir(name); defformatstring(name1, "media/model/%s/tris.md2", name); mdl.meshes = sharemeshes(path(name1)); if(!mdl.meshes) { defformatstring(name2, "media/model/%s/tris.md2", pname); // try md2 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); identflags &= ~IDF_PERSIST; defformatstring(name3, "media/model/%s/md2.cfg", name); if(!execfile(name3, false)) { formatstring(name3, "media/model/%s/md2.cfg", pname); execfile(name3, false); } identflags |= IDF_PERSIST; return true; } }; vertcommands md2commands;