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