]> Dogcows Code - chaz/yoink/blobdiff - src/moof/mesh.cc
compression functions; fixed texture seams
[chaz/yoink] / src / moof / mesh.cc
index 32550f7fcfb3361aff55ea7e2748c0c2c62531df..eac6ef9151a74fb25767613d6f6ce847f1fa3c4b 100644 (file)
 #include <boost/algorithm/string/trim.hpp>
 #include <zlib.h>
 
+#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<int> 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<int> 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<unsigned>   verts(numrefs);
+       std::vector<vector2>    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<mesh>("ac", "models");
-       //}
-
-       //~mesh_resource_loader()
-       //{
-               //resource::unregister_type("ac");
-       //}
-//};
-
-//static mesh_resource_loader loader;
-
 
 } // namespace moof
 
This page took 0.03319 seconds and 4 git commands to generate.