00001
00002
00003
00004
00005
00006
00007
00008
00009 #ifndef _MD5FRMT_H_
00010 #define _MD5FRMT_H_
00011
00012 #include "math3d.h"
00013
00014 #include <stdlib.h>
00015
00016 #include <sstream>
00017 using std::stringstream;
00018
00019 #include <iostream>
00020 using std::cout;
00021 using std::endl;
00022
00023 #include <string>
00024 using std::string;
00025
00026
00027 #define MD5COMMLINE 4096
00028 #define MD5SHADERNAME 256
00029 #define MD5JOINTNAME 64
00030 #define MD5MESHNAME 64
00031 #define MD5LINESIZE 4096
00032
00033 struct MD5Format {
00034
00035 public:
00036
00037 struct animation {
00038 int version;
00039 char commandline[MD5COMMLINE];
00040 int numJoints;
00041 int numFrames;
00042 int frameRate;
00043 int numAnimatedComponents;
00044
00045
00046
00047 };
00048
00049 struct bound {
00050 float min[3];
00051 float max[3];
00052 };
00053
00054 struct model {
00055 int version;
00056 char commandline[MD5COMMLINE];
00057 int numJoints;
00058 int numMeshes;
00059
00060
00061 };
00062
00063 struct joint {
00064 char name[MD5JOINTNAME];
00065 int parent;
00066 float v[4], q[4];
00067 };
00068
00069 struct mesh {
00070 char name[MD5MESHNAME];
00071 char shader[MD5SHADERNAME];
00072 int material;
00073 int numverts;
00074 int numtris;
00075 int numweights;
00076
00077
00078
00079 };
00080
00081 struct vert {
00082 int idx;
00083 float tmap[2];
00084 int start, length;
00085 };
00086
00087 struct tri {
00088 int idx;
00089 int a, b, c;
00090 };
00091
00092 struct weight {
00093 int idx, joint;
00094 float bias;
00095 float v[3];
00096 };
00097
00098 public:
00099
00100 static inline size_t sizeofMesh(mesh * meshptr) {
00101 return sizeof (mesh)
00102 + sizeof (vert) * meshptr->numverts
00103 + sizeof (tri) * meshptr->numtris
00104 + sizeof (weight) * meshptr->numweights;
00105 }
00106
00107 static inline size_t sizeofModel(model * modelptr) {
00108 size_t size = sizeof (model) + sizeof (joint) * modelptr->numJoints;
00109 int i = modelptr->numMeshes;
00110 mesh* m = getFirstMesh(modelptr);
00111 while (i-- > 0) {
00112 size += sizeofMesh(m);
00113 m = getNextMesh(m);
00114 }
00115 return size;
00116 }
00117
00118 static inline mesh * getMesh(model* modelptr, int idx) {
00119 char* curr = (char*) getFirstMesh(modelptr);
00120 while (idx-- > 0) curr = (char*) getNextMesh((mesh*) curr);
00121 return ((mesh*) curr);
00122 }
00123
00124 static inline mesh * getFirstMesh(model * modelptr) {
00125 joint* joints = (joint*) (modelptr + 1);
00126 mesh* first = (mesh*) (joints + modelptr->numJoints);
00127 return first;
00128 }
00129
00130 static inline mesh * getNextMesh(mesh * curr) {
00131 char* next = ((char*) curr) + sizeofMesh(curr);
00132 return ((mesh*) next);
00133 }
00134
00135 static inline joint * getJoints(model * modelptr) {
00136 return ( (joint*) (modelptr + 1));
00137 }
00138
00139 static inline vert * getVerts(mesh * meshptr) {
00140 return ( (vert*) (meshptr + 1));
00141 }
00142
00143 static inline tri * getTris(mesh * meshptr) {
00144 vert* verts = getVerts(meshptr);
00145 tri* tris = (tri*) (verts + meshptr->numverts);
00146 return tris;
00147 }
00148
00149 static inline weight * getWeights(mesh * meshptr) {
00150 tri* tris = getTris(meshptr);
00151 weight* weights = (weight*) (tris + meshptr->numtris);
00152 return weights;
00153 }
00154
00155 static inline int findJoint(model* modelptr, const char* name) {
00156 joint* joints = getJoints(modelptr);
00157 for (int i = 0; i < modelptr->numJoints; i++) {
00158 if (strcasecmp(joints[i].name, name) == 0) return i;
00159 }
00160 return -1;
00161 }
00162
00163 static string getModelStats(model * mod) {
00164 stringstream s;
00165 s << "version " << mod->version << endl;
00166 s << "numJoints " << mod->numJoints << endl;
00167 s << "numMeshes " << mod->numMeshes << endl;
00168 s << endl;
00169 joint* j = (joint*) (mod + 1);
00170 for (int i = 0; i < mod->numJoints; i++) {
00171 s << j->name << endl;
00172 j++;
00173 }
00174 mesh* m = (mesh*) j;
00175 for (int i = 0; i < mod->numMeshes; i++) {
00176 s << endl;
00177 s << m->name << endl;
00178 s << m->shader << endl;
00179 s << "numverts " << m->numverts << endl;
00180 s << "numtris " << m->numtris << endl;
00181 s << "numweights " << m->numweights << endl;
00182 m = (mesh*) (((char*) m) + sizeofMesh(m));
00183 }
00184 return s.str();
00185 }
00186
00187 protected:
00188
00189 static vert * readVerts(FILE* f, int numverts) {
00190 vert* verts = NULL;
00191 try {
00192
00193 verts = new vert[numverts];
00194 if (verts == NULL) throw "no memory for mesh verts";
00195 char line[1024];
00196 int vertcount = 0;
00197 while (vertcount != numverts) {
00198 char* result = fgets(line, sizeof (line), f);
00199 if (feof(f) != 0 || result == NULL) throw "unexpected end of file when reading mesh verts";
00200 vert v;
00201 int r = sscanf(line, " vert %i ( %f %f ) %i %i", &v.idx, (&v.tmap[0]), (&v.tmap[1]), &v.start, &v.length);
00202 if (r == 5) {
00203 memcpy(&verts[vertcount], &v, sizeof (vert));
00204 vertcount++;
00205 }
00206 }
00207 return verts;
00208
00209 } catch (...) {
00210 delete verts;
00211 throw;
00212 }
00213 }
00214
00215 static tri * readTris(FILE* f, int numtris) {
00216 tri* tris = NULL;
00217 try {
00218
00219 tris = new tri[numtris];
00220 if (tris == NULL) throw "no memory for mesh tris";
00221 char line[1024];
00222 int tricount = 0;
00223 while (tricount != numtris) {
00224 char* result = fgets(line, sizeof (line), f);
00225 if (feof(f) != 0 || result == NULL) throw "unexpected end of file when reading mesh tris";
00226 tri t;
00227 int r = sscanf(line, " tri %i %i %i %i", &t.idx, &t.a, &t.b, &t.c);
00228 if (r == 4) {
00229 memcpy(&tris[tricount], &t, sizeof (tri));
00230 tricount++;
00231 }
00232 }
00233 return tris;
00234
00235 } catch (...) {
00236 delete tris;
00237 throw;
00238 }
00239 }
00240
00241 static weight * readWeights(FILE* f, int numweights) {
00242 weight* weights = NULL;
00243 try {
00244
00245 weights = new weight[numweights];
00246 if (weights == NULL) throw "no memory for mesh weights";
00247 char line[1024];
00248 int weightcount = 0;
00249 while (weightcount != numweights) {
00250 char* result = fgets(line, sizeof (line), f);
00251 if (feof(f) != 0 || result == NULL) throw "unexpected end of file when reading mesh weights";
00252 weight w;
00253 int r = sscanf(line, " weight %i %i %f ( %f %f %f )", &w.idx, &w.joint, &w.bias, (&w.v[0]), (&w.v[1]), (&w.v[2]));
00254 if (r == 6) {
00255 memcpy(&weights[weightcount], &w, sizeof (weight));
00256 weightcount++;
00257 }
00258 }
00259 return weights;
00260
00261 } catch (...) {
00262 delete weights;
00263 throw;
00264 }
00265 }
00266
00267 static mesh * readMesh(FILE * f) {
00268 char* chunk = NULL;
00269 vert* verts = NULL;
00270 tri* tris = NULL;
00271 weight* weights = NULL;
00272
00273 try {
00274
00275 mesh m;
00276 m.name[0] = '\0';
00277 m.shader[0] = '\0';
00278 m.material = -1;
00279 m.numverts = 0;
00280 m.numtris = 0;
00281 m.numweights = 0;
00282
00283 while (1) {
00284 char line[1024];
00285 char* result = fgets(line, sizeof (line), f);
00286 if (line[0] == '}') break;
00287 if (feof(f) != 0 || result == NULL) throw "unexpected end of file when reading mesh";
00288
00289
00290
00291 int r = sscanf(line, " // meshes: %[^\n]", m.name);
00292 if (r == 1) {
00293
00294 continue;
00295 }
00296
00297
00298 r = sscanf(line, " shader \"%[^\"]\"", m.shader);
00299 if (r == 1) {
00300
00301 continue;
00302 }
00303
00304
00305 r = sscanf(line, " numverts %i", &m.numverts);
00306 if (r == 1) {
00307 if (verts != NULL) throw "duplicate vertlist";
00308
00309 verts = (vert*) readVerts(f, m.numverts);
00310 continue;
00311 }
00312
00313
00314 r = sscanf(line, " numtris %i", &m.numtris);
00315 if (r == 1) {
00316 if (tris != NULL) throw "duplicate trilist";
00317
00318 tris = (tri*) readTris(f, m.numtris);
00319 continue;
00320 }
00321
00322
00323 r = sscanf(line, " numweights %i", &m.numweights);
00324 if (r == 1) {
00325 if (weights != NULL) throw "duplicate weightlist";
00326
00327 weights = (weight*) readWeights(f, m.numweights);
00328 continue;
00329 }
00330
00331 }
00332
00333 if (verts == NULL) throw "missing verts";
00334 if (tris == NULL) throw "missing tris";
00335 if (weights == NULL) throw "missing weights";
00336
00337 chunk = new char[sizeofMesh(&m)];
00338 if (chunk == NULL) throw "no memory for mesh chunk";
00339
00340 char* chunk_ptr = chunk;
00341 memcpy(chunk_ptr, &m, sizeof (mesh));
00342
00343 chunk_ptr += sizeof (mesh);
00344 memcpy(chunk_ptr, verts, sizeof (vert) * m.numverts);
00345
00346 chunk_ptr += sizeof (vert) * m.numverts;
00347 memcpy(chunk_ptr, tris, sizeof (tri) * m.numtris);
00348
00349 chunk_ptr += sizeof (tri) * m.numtris;
00350 memcpy(chunk_ptr, weights, sizeof (weight) * m.numweights);
00351
00352 delete verts;
00353 delete tris;
00354 delete weights;
00355
00356 return (mesh*) chunk;
00357
00358 } catch (...) {
00359 delete verts;
00360 delete tris;
00361 delete weights;
00362 delete chunk;
00363 throw;
00364 }
00365 }
00366
00367 static joint * readJoints(FILE* f, int numjoints) {
00368 joint* joints = NULL;
00369
00370 try {
00371 joints = new joint[numjoints];
00372 if (joints == NULL) throw "no memory for mesh joints";
00373
00374 int jointcount = -1;
00375 while (1) {
00376 char line[1024];
00377 char* result = fgets(line, sizeof (line), f);
00378 if (line[0] == '}' || result == NULL) break;
00379 if (feof(f) != 0) throw "unexpected end of file when reading joints";
00380
00381
00382 if (jointcount == -1) {
00383 char s[1024];
00384 int r = sscanf(line, " %s {", s);
00385 if (r == 1 && strcmp("joints", s) == 0) {
00386
00387 jointcount = 0;
00388 continue;
00389 }
00390 } else {
00391 joint j;
00392 int r = sscanf(line, " \"%[^\"]\" %i ( %f %f %f ) ( %f %f %f )", j.name, &j.parent, (&j.v[0]), (&j.v[1]), (&j.v[2]), (&j.q[0]), (&j.q[1]), (&j.q[2]));
00393 if (r == 8) {
00394 j.v[3] = 0.0f;
00395 float w2 = 1.0f - (j.q[0] * j.q[0] + j.q[1] * j.q[1] + j.q[2] * j.q[2]);
00396 j.q[3] = (w2 <= 0) ? 0.0f : -sqrt(w2);
00397 if (jointcount >= numjoints) throw "too many joints";
00398 memcpy(&joints[jointcount], &j, sizeof (joint));
00399 cout << j.name << " " << j.parent << " (" << j.v[0] << " " << j.v[1] << " " << j.v[2] << " ) ( " << j.q[0] << " " << j.q[1] << " " << j.q[2] << " )" << endl;
00400 jointcount++;
00401 }
00402 }
00403 }
00404 if (jointcount < numjoints) throw "too few joints";
00405 return joints;
00406
00407 } catch (...) {
00408 delete joints;
00409 throw;
00410 }
00411 }
00412
00413 public:
00414
00415 static model * mapMD5Mesh(const char* filename) {
00416 joint* joints = NULL;
00417 mesh** meshes = NULL;
00418 char* modelchunk = NULL;
00419 model m;
00420 m.version = 0;
00421 m.commandline[0] = '\0';
00422 m.numJoints = 0;
00423 m.numMeshes = 0;
00424 try {
00425
00426 FILE* f = fopen(filename, "rt");
00427 if (f == NULL) throw "could not open file for reading";
00428 int r;
00429
00430
00431
00432 int header = 0;
00433 int flags = ( 1 + 0 + 4 + 8 );
00434 while ((header & flags) != flags) {
00435 char line[MD5LINESIZE];
00436 char* result = fgets(line, sizeof (line), f);
00437 if (feof(f) != 0 || result == NULL) throw "unexpected end of file when reading header";
00438
00439 r = sscanf(line, " MD5Version %i", &m.version);
00440 if (r == 1) header |= 1;
00441
00442 r = sscanf(line, " commandline \"%[^\"]\"", m.commandline);
00443 if (r == 1) header |= 2;
00444
00445 r = sscanf(line, " numJoints %i", &m.numJoints);
00446 if (r == 1) header |= 4;
00447
00448 r = sscanf(line, " numMeshes %i", &m.numMeshes);
00449 if (r == 1) header |= 8;
00450 }
00451
00452
00453
00454
00455
00456
00457 joints = (joint*) readJoints(f, m.numJoints);
00458
00459 unsigned long chunksize = sizeof (model) + sizeof (joint) * m.numJoints;
00460
00461
00462 typedef mesh* mesh_star;
00463 meshes = new mesh_star[m.numMeshes];
00464 if (meshes == NULL) throw "no memory for model meshes";
00465 memset(meshes, 0, sizeof (mesh_star) * m.numMeshes);
00466 for (int i = 0; i < m.numMeshes; i++) {
00467 meshes[i] = (mesh*) readMesh(f);
00468 chunksize += sizeofMesh(meshes[i]);
00469 }
00470
00471 fclose(f);
00472
00473 modelchunk = new char[chunksize];
00474 if (modelchunk == NULL) throw "no memory for model chunk";
00475
00476 char* chunk_ptr = modelchunk;
00477 memcpy(chunk_ptr, &m, sizeof (model));
00478
00479 chunk_ptr += sizeof (model);
00480 memcpy(chunk_ptr, joints, sizeof (joint) * m.numJoints);
00481
00482 chunk_ptr += sizeof (joint) * m.numJoints;
00483 for (int i = 0; i < m.numMeshes; i++) {
00484 unsigned long meshsize = sizeofMesh(meshes[i]);
00485 memcpy(chunk_ptr, meshes[i], meshsize);
00486 chunk_ptr += meshsize;
00487 }
00488
00489
00490
00491 return (model*) modelchunk;
00492
00493 } catch (...) {
00494 delete joints;
00495 delete modelchunk;
00496 if (meshes != NULL) {
00497 for (int i = 0; i < m.numMeshes; i++) delete meshes[i];
00498 delete meshes;
00499 }
00500 throw;
00501 }
00502 }
00503
00504 public:
00505
00506 static string formatJoint(float* p, float* q) {
00507 char buffer[1024];
00508 sprintf(buffer, "( %.4f %.4f %.4f ) ( %.4f %.4f %.4f %.4f )", p[0],p[1],p[2], q[0],q[1],q[2],q[3]);
00509 return string(buffer);
00510 }
00511
00512 static void testMD5MeshLoad() {
00513 cout << "MD5 Reader" << endl;
00514
00515 MD5Format::model* m = NULL;
00516 try {
00517 m = MD5Format::mapMD5Mesh("/home/benben/Desktop/workspaces/milk_workspace/diestel.md5mesh");
00518
00519 } catch (char* s) {
00520 cout << s << endl;
00521 }
00522
00523 cout << "=======================================================" << endl;
00524 cout << MD5Format::getModelStats(m) << endl;
00525
00526 cout << "=======================================================" << endl;
00527 MD5Format::joint* joints = (MD5Format::joint*) (m + 1);
00528
00529 MD5Format::toLocalJoints(m->numJoints, joints, joints);
00530 MD5Format::toGlobalJoints(m->numJoints, joints, joints);
00531 delete m;
00532 }
00533
00534 public:
00535
00536
00537 static void toLocalJoints(int numJoints, joint* joints, joint * joints_) {
00538
00539 joint* locals = joints_;
00540 if (joints == joints_) {
00541 locals = new joint[numJoints];
00542 assert(locals != NULL);
00543 }
00544 memcpy(locals, joints, sizeof (joint) * numJoints);
00545 joint* j = joints;
00546 joint* j_ = locals;
00547 for (int i = 0; i < numJoints; i++) {
00548
00549
00550 float v_local[4];
00551 float q_local[4];
00552 if (j->parent < 0) {
00553
00554 vector_cpy(v_local, j->v);
00555 quat_cpy(q_local, j->q);
00556 } else {
00557
00558 joint* p = &joints[j_->parent];
00559
00560 float p_q[4];
00561 quat_cpy(p_q, p->q);
00562 quat_conj(p_q);
00563
00564 float j_q[4];
00565 quat_cpy(j_q, j->q);
00566 quat_conj(j_q);
00567
00568
00569
00570 vector_sub(v_local, j->v, p->v);
00571 quat_apply(v_local, p_q, v_local);
00572
00573 quat_mul(q_local, j->q, p_q);
00574 }
00575
00576 quat_rectify_neg(q_local);
00577 string s = formatJoint(v_local, q_local);
00578
00579
00580 vector_cpy(j_->v, v_local);
00581 quat_cpy(j_->q, q_local);
00582
00583 j++;
00584 j_++;
00585 }
00586 if (locals != joints_) {
00587 memcpy(joints_, locals, sizeof (joint) * numJoints);
00588 delete locals;
00589 }
00590 }
00591
00592 static void toGlobalJoints(int numJoints, joint* joints, joint * joints_, joint* manipulators = NULL) {
00593
00594 joint* globals = joints_;
00595 if (joints == joints_) {
00596 globals = new joint[numJoints];
00597 assert(globals != NULL);
00598 }
00599 memcpy(globals, joints, sizeof (joint) * numJoints);
00600 joint* j = joints;
00601 joint* j_ = globals;
00602 for (int i = 0; i < numJoints; i++) {
00603
00604
00605 float v_global[4];
00606 float q_global[4];
00607 if (j->parent < 0) {
00608
00609 vector_cpy(v_global, j->v);
00610 quat_cpy(q_global, j->q);
00611 } else {
00612 joint* p = &globals[j->parent];
00613
00614
00615
00616 quat_mul(q_global, j->q, p->q);
00617
00618 quat_apply(v_global, p->q, j->v);
00619 vector_add(v_global, v_global, p->v);
00620 }
00621
00622 if (manipulators) {
00623 quat_mul(q_global, q_global, manipulators[i].q);
00624 vector_add(v_global, v_global, manipulators[i].v);
00625 }
00626
00627 quat_rectify_neg(q_global);
00628 string s = formatJoint(v_global, q_global);
00629
00630
00631 vector_cpy(j_->v, v_global);
00632 quat_cpy(j_->q, q_global);
00633
00634 j++;
00635 j_++;
00636 }
00637 if (globals != joints_) {
00638 memcpy(joints_, globals, sizeof (joint) * numJoints);
00639 delete globals;
00640 }
00641 }
00642
00643 static void animatedMeshVertices(mesh* msh, joint* joints, float* vertices) {
00644 vert* verts = getVerts(msh);
00645 weight* weights = getWeights(msh);
00646 float* v_ = vertices;
00647 int numverts = msh->numverts;
00648 vert* v = verts;
00649 while (numverts-- > 0) {
00650
00651 vector_set(v_, 0, 0, 0);
00652 weight* w = &weights[v->start];
00653
00654 int numweights = v->length;
00655 while (numweights-- > 0) {
00656 joint* j = &joints[w->joint];
00657 float q[4];
00658 quat_cpy(q, j->q);
00659 float temp[3];
00660 quat_apply(temp, q, w->v);
00661 vector_add(temp, temp, j->v);
00662 vector_scale(temp, temp, w->bias);
00663 vector_add(v_, v_, temp);
00664 w++;
00665 }
00666 v++;
00667 v_ += 3;
00668 }
00669 }
00670
00671
00672 };
00673
00674
00675 #endif
00676