X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2Fmoof%2Fmesh.cc;fp=src%2Fmoof%2Fmesh.cc;h=eac6ef9151a74fb25767613d6f6ce847f1fa3c4b;hp=32550f7fcfb3361aff55ea7e2748c0c2c62531df;hb=62f3ceaff75a6b08cb1aec9a465773bb81a2d79d;hpb=44b3014bce798789e795242d1556cb7449e6386a diff --git a/src/moof/mesh.cc b/src/moof/mesh.cc index 32550f7..eac6ef9 100644 --- a/src/moof/mesh.cc +++ b/src/moof/mesh.cc @@ -16,21 +16,21 @@ #include #include +#include "compression.hh" #include "debug.hh" #include "log.hh" #include "mesh.hh" #include "opengl.hh" -// TODO: this file needs to be cleaned up - #define AC3D_FORMAT_VERSION 0x0b -#define ZLIB_BUF_SIZE 262114 namespace moof { MOOF_REGISTER_RESOURCE(mesh, ac, models); +MOOF_REGISTER_RESOURCE(mesh, acz, models); + static std::string read_string(std::istream& stream) { @@ -74,9 +74,9 @@ static int read_hex(std::istream& stream) static vector2 read_pair(std::istream& stream) { - vector2 triplet; - stream >> triplet[0] >> triplet[1]; - return triplet; + vector2 pair; + stream >> pair[0] >> pair[1]; + return pair; } static vector3 read_triplet(std::istream& stream) @@ -94,74 +94,47 @@ static vector4 read_color(std::istream& stream) return color; } -void mesh::import(std::istream& stream) + +static inline void throw_invalid_atom(const std::string& atom) { - std::string atom; - object_ptr obj; - std::stack kids; + throw std::runtime_error("unexpected atom: " + atom); +} + +void mesh::load(std::istream& stream) +{ // read and verify the AC3D header - { - char magic[5]; - unsigned version = 0; + char magic[5]; + unsigned version = 0; - stream.get(magic, sizeof(magic)); - if (!stream || strncmp(magic, "AC3D", 4) != 0) - { - throw std::runtime_error("invalid mesh header"); - } + stream.get(magic, sizeof(magic)); + if (!stream || strncmp(magic, "AC3D", 4) != 0) + { + throw std::runtime_error("invalid mesh header"); + } - version = read_hex(stream); - if (version > AC3D_FORMAT_VERSION) - { - throw std::runtime_error("wrong mesh file format version"); - } + version = read_hex(stream); + if (version > AC3D_FORMAT_VERSION) + { + throw std::runtime_error("wrong mesh file format version"); } + std::string atom; + object_ptr obj; + std::stack kids; + while (stream) { stream >> atom; if (!stream) break; - if (atom == "MATERIAL") + if (atom == "OBJECT") { - materials_.push_back(material(read_string(stream))); - - stream >> atom; - materials_.back().diffuse = read_color(stream); - stream >> atom; - materials_.back().ambient = read_color(stream); - stream >> atom; - materials_.back().emissive = read_color(stream); - stream >> atom; - materials_.back().specular = read_color(stream); - - stream >> atom >> materials_.back().shininess; - stream >> atom >> materials_.back().diffuse[3]; - materials_.back().diffuse[3] = SCALAR(1.0) - - materials_.back().diffuse[3]; + obj = load_object(stream, obj); } - else if (atom == "OBJECT") + else if (atom == "MATERIAL") { - stream >> atom; - if (atom != "world" && atom != "group" && atom != "poly") - { - throw std::runtime_error("unexpected object type " + atom); - } - - object_ptr newObj = object::alloc(*this); - - if (obj) - { - obj->kids.push_back(newObj); - newObj->parent = obj; - } - else - { - objects_.push_back(newObj); - } - - obj = newObj; + load_material(stream); } else if (atom == "name") { @@ -171,7 +144,10 @@ void mesh::import(std::istream& stream) object_ptr parent = obj->parent.lock(); if (parent) parent->kids_byname.insert(std::make_pair(obj->name, obj)); } - else throw std::runtime_error("unexpected atom: " + atom); + else + { + throw_invalid_atom(atom); + } } else if (atom == "data") { @@ -185,7 +161,7 @@ void mesh::import(std::istream& stream) else if (atom == "texrep") { if (obj) obj->texrep = read_pair(stream); - else throw std::runtime_error("unexpected atom: " + atom); + else throw_invalid_atom(atom); } else if (atom == "rot") { @@ -200,11 +176,11 @@ void mesh::import(std::istream& stream) else if (atom == "url") { if (obj) std::getline(stream, obj->url); - else throw std::runtime_error("unexpected atom: " + atom); + else throw_invalid_atom(atom); } else if (atom == "numvert") { - if (!obj) throw std::runtime_error("unexpected atom: " + atom); + if (!obj) throw_invalid_atom(atom); int numvert = 0; stream >> numvert; @@ -216,7 +192,7 @@ void mesh::import(std::istream& stream) } else if (atom == "numsurf") { - if (!obj) throw std::runtime_error("unexpected atom: " + atom); + if (!obj) throw_invalid_atom(atom); int numsurf = 0; stream >> numsurf; @@ -224,119 +200,19 @@ void mesh::import(std::istream& stream) for (int i = 0; i < numsurf; ++i) { stream >> atom; - if (atom != "SURF") throw std::runtime_error("uh oh"); - - read_hex(stream); - - int material = 0; - stream >> atom; - if (atom == "mat") stream >> material >> atom; - - if (atom != "refs") - { - throw std::runtime_error("blaaaaaaaahhh!!"); - } - - int numrefs = 0; - stream >> numrefs; - ASSERT(numrefs >= 3); - - if ((int)obj->faces.size() <= material) - { - obj->faces.resize(material + 1); - } - material_group& face = obj->faces[material]; - - unsigned vert; - stream >> vert; - vector2 uv = read_pair(stream); - if (vert < face.triangles_uv.size()) - { - if (uv != face.triangles_uv[vert]) - { - obj->verts.push_back(obj->verts[vert]); - face.triangles_uv.resize(obj->verts.size()); - vert = obj->verts.size() - 1; - } - } - else face.triangles_uv.resize(vert + 1); - face.triangles_uv[vert] = uv; - face.triangles.push_back(vert); - - unsigned first = vert; - - stream >> vert; - uv = read_pair(stream); - if (vert < face.triangles_uv.size()) - { - if (uv != face.triangles_uv[vert]) - { - obj->verts.push_back(obj->verts[vert]); - face.triangles_uv.resize(obj->verts.size()); - vert = obj->verts.size() - 1; - } - } - else face.triangles_uv.resize(vert + 1); - face.triangles_uv[vert] = uv; - face.triangles.push_back(vert); - - stream >> vert; - uv = read_pair(stream); - if (vert < face.triangles_uv.size()) - { - if (uv != face.triangles_uv[vert]) - { - obj->verts.push_back(obj->verts[vert]); - face.triangles_uv.resize(obj->verts.size()); - vert = obj->verts.size() - 1; - } - } - else face.triangles_uv.resize(vert + 1); - face.triangles_uv[vert] = uv; - face.triangles.push_back(vert); - - unsigned last = vert; - - for (int j = 3; j < numrefs; ++j) - { - face.triangles.push_back(first); - face.triangles.push_back(last); - - stream >> vert; - uv = read_pair(stream); - if (vert < face.triangles_uv.size()) - { - if (uv != face.triangles_uv[vert]) - { - obj->verts.push_back(obj->verts[vert]); - face.triangles_uv.resize(obj->verts.size()); - vert = obj->verts.size() - 1; - } - } - else face.triangles_uv.resize(vert + 1); - face.triangles_uv[vert] = uv; - face.triangles.push_back(vert); - - last = face.triangles.back(); - } + if (atom != "SURF") throw_invalid_atom(atom); + load_surface(stream, obj); } + } else if (atom == "kids") { - //while (0 < kids.size()) - //{ - //if (--kids.top() <= 0) - //{ - //ASSERT(obj && "should be an object"); - //obj = obj->parent; - //kids.pop(); - //} - //else break; - //} - int numkids = 0; stream >> numkids; - if (0 < numkids) kids.push(numkids); + if (0 < numkids) + { + kids.push(numkids); + } else { if (0 < kids.size() && 0 < --kids.top()) kids.pop(); @@ -347,29 +223,188 @@ void mesh::import(std::istream& stream) while (stream); } -//unsigned mesh::read_vertex_line(std::istream& stream) -//{ - //unsigned vert; - //stream >> vert; - //vector2 uv = read_pair(stream); - //if (vert < face.triangles_uv.size()) - //{ - //if (uv != face.triangles_uv[vert]) - //{ - //obj->verts.push_back(obj->verts[vert]); - //face.triangles_uv.resize(obj->verts.size()); - //vert = obj->verts.size() - 1; - //} - //} - //else face.triangles_uv.resize(vert + 1); - //face.triangles_uv[vert] = uv; - //face.triangles.push_back(vert); -//} + +void mesh::load_material(std::istream& stream) +{ + materials_.push_back(material(read_string(stream))); + + std::string atom; + stream >> atom; + materials_.back().diffuse = read_color(stream); + stream >> atom; + materials_.back().ambient = read_color(stream); + stream >> atom; + materials_.back().emissive = read_color(stream); + stream >> atom; + materials_.back().specular = read_color(stream); + + stream >> atom >> materials_.back().shininess; + stream >> atom >> materials_.back().diffuse[3]; + materials_.back().diffuse[3] = SCALAR(1.0) - materials_.back().diffuse[3]; +} + +mesh::object_ptr mesh::load_object(std::istream& stream, object_ptr parent) +{ + std::string atom; + stream >> atom; + if (atom != "world" && atom != "group" && atom != "poly") + { + throw_invalid_atom(atom); + } + + object_ptr obj = object::alloc(*this); + + if (parent) + { + parent->kids.push_back(obj); + obj->parent = parent; + } + else + { + objects_.push_back(obj); + } + + return obj; +} + +void mesh::load_surface(std::istream& stream, object_ptr obj) +{ + std::string atom; + read_hex(stream); + + int material = 0; + stream >> atom; + if (atom == "mat") stream >> material >> atom; + if (atom != "refs") throw_invalid_atom(atom); + + int numrefs = 0; + stream >> numrefs; + ASSERT(numrefs >= 3); + + if ((int)obj->faces.size() <= material) obj->faces.resize(material + 1); + material_group& face = obj->faces[material]; + + std::vector verts(numrefs); + std::vector uv(numrefs); + + for (int i = 0; i < numrefs; ++i) + { + stream >> verts[i]; + uv[i] = read_pair(stream); + } + + // translate texture coordinates + if (obj->texture) obj->texture->fix_uv(uv); + // TODO why isn't texture always defined at this point? + + for (int i = 0; i < numrefs; ++i) + { + scalar vert = verts[i]; + vector2 texcoord = uv[i]; + if (vert < face.triangles_uv.size()) + { + if (texcoord != face.triangles_uv[vert]) + { + obj->verts.push_back(obj->verts[vert]); + face.triangles_uv.resize(obj->verts.size()); + vert = obj->verts.size() - 1; + } + } + else face.triangles_uv.resize(vert + 1); + face.triangles_uv[vert] = texcoord; + verts[i] = vert; + } + + face.triangles.push_back(verts[0]); + face.triangles.push_back(verts[1]); + face.triangles.push_back(verts[2]); + for (int i = 3; i < numrefs; ++i) + { + face.triangles.push_back(verts[0]); + face.triangles.push_back(verts[i-1]); + face.triangles.push_back(verts[i]); + } + +#if 0 + unsigned vert; + stream >> vert; + vector2 uv = read_pair(stream); + if (vert < face.triangles_uv.size()) + { + if (uv != face.triangles_uv[vert]) + { + obj->verts.push_back(obj->verts[vert]); + face.triangles_uv.resize(obj->verts.size()); + vert = obj->verts.size() - 1; + } + } + else face.triangles_uv.resize(vert + 1); + face.triangles_uv[vert] = uv; + face.triangles.push_back(vert); + + unsigned first = vert; + + stream >> vert; + uv = read_pair(stream); + if (vert < face.triangles_uv.size()) + { + if (uv != face.triangles_uv[vert]) + { + obj->verts.push_back(obj->verts[vert]); + face.triangles_uv.resize(obj->verts.size()); + vert = obj->verts.size() - 1; + } + } + else face.triangles_uv.resize(vert + 1); + face.triangles_uv[vert] = uv; + face.triangles.push_back(vert); + + stream >> vert; + uv = read_pair(stream); + if (vert < face.triangles_uv.size()) + { + if (uv != face.triangles_uv[vert]) + { + obj->verts.push_back(obj->verts[vert]); + face.triangles_uv.resize(obj->verts.size()); + vert = obj->verts.size() - 1; + } + } + else face.triangles_uv.resize(vert + 1); + face.triangles_uv[vert] = uv; + face.triangles.push_back(vert); + + unsigned last = vert; + + for (int j = 3; j < numrefs; ++j) + { + face.triangles.push_back(first); + face.triangles.push_back(last); + + stream >> vert; + uv = read_pair(stream); + if (vert < face.triangles_uv.size()) + { + if (uv != face.triangles_uv[vert]) + { + obj->verts.push_back(obj->verts[vert]); + face.triangles_uv.resize(obj->verts.size()); + vert = obj->verts.size() - 1; + } + } + else face.triangles_uv.resize(vert + 1); + face.triangles_uv[vert] = uv; + face.triangles.push_back(vert); + + last = face.triangles.back(); + } +#endif +} + mesh::mesh(const std::string& path) { - std::ifstream file(path.c_str(), std::ifstream::in | - std::ifstream::binary); + std::ifstream file(path.c_str(), std::ios::binary); if (!file) throw std::runtime_error("cannot find mesh file"); // if we can read the header, the file isn't compressed @@ -379,61 +414,15 @@ mesh::mesh(const std::string& path) { log_info("text mesh detected"); file.seekg(std::ios::beg); - import(file); + load(file); } else { - log_info("compressed mesh detected"); + log_info("decompressing mesh..."); file.seekg(std::ios::beg); - std::stringstream stream; - char in[ZLIB_BUF_SIZE]; - char out[ZLIB_BUF_SIZE]; - - z_stream zstream; - - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.opaque = Z_NULL; - zstream.avail_in = 0; - zstream.next_in = Z_NULL; - - int result = inflateInit2(&zstream, 32+MAX_WBITS); - if (result != Z_OK) - throw std::runtime_error("zlib init error"); - - do { - file.read(in, sizeof(in)); - zstream.next_in = (Bytef*)in; - zstream.avail_in = file.gcount(); - - if (zstream.avail_in == 0) break; - - do { - zstream.next_out = (Bytef*)out; - zstream.avail_out = sizeof(out); - - result = inflate(&zstream, Z_NO_FLUSH); - switch (result) - { - case Z_NEED_DICT: - case Z_DATA_ERROR: - case Z_MEM_ERROR: - inflateEnd(&zstream); - throw std::runtime_error("zlib inflate error"); - case Z_STREAM_ERROR: - throw std::runtime_error("zlib stream error"); - } - - int inflated = sizeof(out) - zstream.avail_out; - stream.write(out, inflated); - } - while (zstream.avail_out == 0); - } - while(result != Z_STREAM_END); - - inflateEnd(&zstream); - import(stream); + inflate(file, stream); + load(stream); } } @@ -465,6 +454,7 @@ void mesh::set_material(const material& material) const glMaterial(GL_FRONT, GL_SHININESS, material.shininess); } + void mesh::object::draw(scalar alpha, bool recurse) const { glVertexPointer(verts); @@ -499,23 +489,6 @@ void mesh::object::draw(scalar alpha, bool recurse) const } } -//class mesh_resource_loader -//{ -//public: - - //mesh_resource_loader() - //{ - //resource::register_type("ac", "models"); - //} - - //~mesh_resource_loader() - //{ - //resource::unregister_type("ac"); - //} -//}; - -//static mesh_resource_loader loader; - } // namespace moof