]> Dogcows Code - chaz/yoink/blobdiff - src/moof/mesh.cc
initial mesh testing
[chaz/yoink] / src / moof / mesh.cc
diff --git a/src/moof/mesh.cc b/src/moof/mesh.cc
new file mode 100644 (file)
index 0000000..ee4d4b6
--- /dev/null
@@ -0,0 +1,518 @@
+
+/*]  Copyright (c) 2009-2010, Charles McGarvey  [**************************
+**]  All rights reserved.
+*
+* vi:ts=4 sw=4 tw=75
+*
+* Distributable under the terms and conditions of the 2-clause BSD license;
+* see the file COPYING for a complete text of the license.
+*
+**************************************************************************/
+
+#include <cstring>
+#include <fstream>
+#include <sstream>
+#include <stack>
+#include <stdexcept>
+
+#include <boost/algorithm/string/trim.hpp>
+#include <zlib.h>
+
+#include <stlplus/strings/string_utilities.hpp>
+
+#include "debug.hh"
+#include "log.hh"
+#include "mesh.hh"
+#include "opengl.hh"
+
+
+#define AC3D_FORMAT_VERSION            (0x0b)
+#define ZLIB_BUF_SIZE                  (262114)
+
+
+namespace moof {
+
+
+static std::string read_string(std::istream& stream)
+{
+       std::string     str;
+       char            atom;
+
+       do      // skip to the next non-space character
+       {
+               stream.get(atom);
+       }
+       while (stream && std::isspace(atom));
+
+       if (atom == '"')
+       {
+               do
+               {
+                       stream.get(atom);
+                       if (atom == '"') break;
+                       str += atom;
+               }
+               while (stream);
+       }
+       else
+       {
+               do
+               {
+                       stream.get(atom);
+                       if (std::isspace(atom)) break;
+                       str += atom;
+               }
+               while (stream);
+       }
+
+       return str;
+}
+
+inline int read_hex(std::istream& stream)
+{
+       int hex;
+       std::ios::fmtflags flags = stream.flags();
+       stream.setf(std::ios::hex, std::ios::basefield);
+       stream >> hex;
+       stream.flags(flags);
+       return hex;
+}
+
+inline vector2 read_pair(std::istream& stream)
+{
+       vector2 triplet;
+       stream >> triplet[0] >> triplet[1];
+       return triplet;
+}
+
+
+template <int D>
+inline vector< scalar, fixed<D> > read_triplet(std::istream& stream)
+{
+       vector< scalar, fixed<D> > triplet;
+       stream >> triplet[0] >> triplet[1] >> triplet[2];
+       return triplet;
+}
+
+
+void mesh::import(std::istream& stream)
+{
+       std::string             atom;
+
+       object_ptr              obj;
+       std::stack<int> kids;
+
+       // read and verify the AC3D header
+       {
+               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");
+               }
+
+               version = read_hex(stream);
+               if (version > AC3D_FORMAT_VERSION)
+               {
+                       throw std::runtime_error("wrong mesh file format version");
+               }
+       }
+
+       while (stream)
+       {
+               stream >> atom;
+               if (!stream) break;
+
+               if (atom == "MATERIAL")
+               {
+                       materials_.push_back(material(read_string(stream)));
+
+                       stream >> atom;
+                       materials_.back().diffuse = read_triplet<4>(stream);
+                       stream >> atom;
+                       materials_.back().ambient = read_triplet<3>(stream);
+                       stream >> atom;
+                       materials_.back().emissive = read_triplet<3>(stream);
+                       stream >> atom;
+                       materials_.back().specular = read_triplet<3>(stream);
+
+                       stream >> atom >> materials_.back().shininess;
+                       stream >> atom >> materials_.back().diffuse[3]; // transparency
+                       materials_.back().diffuse[3] = 1.0;
+
+                       log_info("read material", materials_.back().name,
+                                                                         materials_.back().diffuse);
+               }
+               else if (atom == "OBJECT")
+               {
+                       stream >> atom;
+                       if (atom != "world" && atom != "group" && atom != "poly")
+                       {
+                               throw std::runtime_error("unexpected object type " + atom);
+                       }
+
+                       object_ptr newObj = object::alloc();
+
+                       if (obj)
+                       {
+                               obj->kids.push_back(newObj);
+                               newObj->parent = obj;
+                       }
+                       else
+                       {
+                               objects_.push_back(newObj);
+                       }
+
+                       obj = newObj;
+               }
+               else if (atom == "name")
+               {
+                       if (obj) obj->name = read_string(stream);
+                       else throw std::runtime_error("unexpected atom: " + atom);
+               }
+               else if (atom == "data")
+               {
+                       std::getline(stream, atom);
+                       std::getline(stream, obj ? obj->data : atom);
+               }
+               else if (atom == "texture")
+               {
+                       if (obj) obj->texture = resource::load(read_string(stream));
+               }
+               else if (atom == "texrep")
+               {
+                       if (obj) obj->texrep = read_pair(stream);
+                       else throw std::runtime_error("unexpected atom: " + atom);
+               }
+               else if (atom == "rot")
+               {
+                       // TODO
+                       std::getline(stream, atom);
+               }
+               else if (atom == "loc")
+               {
+                       // TODO
+                       std::getline(stream, atom);
+               }
+               else if (atom == "url")
+               {
+                       if (obj) std::getline(stream, obj->url);
+                       else throw std::runtime_error("unexpected atom: " + atom);
+               }
+               else if (atom == "numvert")
+               {
+                       if (!obj) throw std::runtime_error("unexpected atom: " + atom);
+
+                       int numvert = 0;
+                       stream >> numvert;
+
+                       log_warning("adding verts", numvert);
+
+                       for (int i = 0; i < numvert; ++i)
+                       {
+                               obj->verts.push_back(read_triplet<3>(stream));
+                               log_error("vert", obj->verts.back());
+                       }
+               }
+               else if (atom == "numsurf")
+               {
+                       if (!obj) throw std::runtime_error("unexpected atom: " + atom);
+
+                       int numsurf = 0;
+                       stream >> numsurf;
+
+                       for (int i = 0; i < numsurf; ++i)
+                       {
+                               stream >> atom;
+                               if (atom != "SURF") throw std::runtime_error("uh oh");
+
+                               int             flags = read_hex(stream);
+                               log_info(flags);
+
+                               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 || numrefs == 4);
+
+                               if ((int)obj->faces.size() <= material)
+                               {
+                                       log_info("inserting face...");
+                                       //obj->faces.insert(obj->faces.begin() + material,
+                                                                         //material_group());
+                                       obj->faces.resize(material + 1);
+                                       log_info("inserted face", material, obj->faces.size());
+                               }
+
+                               material_group& face = obj->faces[material];
+                               for (int j = 0; j < numrefs; ++j)
+                               {
+                                       int             vert;
+                                       stream >> vert;
+
+                                       vector2 uv = read_pair(stream);
+
+                                       if (numrefs == 3)
+                                       {
+                                               face.triangles.push_back(vert);
+                                               face.triangles_uv.push_back(uv);
+                                       }
+                                       else
+                                       {
+                                               face.quads.push_back(vert);
+                                               face.quads_uv.push_back(uv);
+                                       }
+                               }
+                       }
+               }
+               else if (atom == "kids")
+               {
+                       for (int i = kids.size(); i > 0; --i)
+                       {
+                               if (--kids.top() <= 0)
+                               {
+                                       ASSERT(obj && "should be an object");
+                                       obj = obj->parent;
+                                       kids.pop();
+                               }
+                               else break;
+                       }
+
+                       int numkids = 0;
+                       stream >> numkids;
+                       if (numkids > 0) kids.push(numkids);
+
+                       if (kids.size() > 0)
+                       {
+                               log_info("KIDS", kids.top(), "|", kids.size());
+                       }
+               }
+               else
+               {
+                       log_warning("UNKNOWN ATOM:", atom);
+               }
+       }
+       while (stream);
+}
+
+
+mesh::mesh(const std::string& path)
+{
+       std::ifstream file(path.c_str(), std::ifstream::in |
+                                                                        std::ifstream::binary);
+       if (!file) throw std::runtime_error("cannot find mesh file");
+
+       // if we can read the header, the file isn't compressed
+       char magic[5];
+       file.get(magic, sizeof(magic));
+       if (strncmp(magic, "AC3D", 4) == 0)
+       {
+               log_info("text mesh detected");
+               file.seekg(std::ios::beg);
+
+               import(file);
+       }
+       else
+       {
+               log_info("compressed mesh detected");
+               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);
+       }
+}
+
+
+void mesh::draw(scalar alpha) const
+{
+       //glEnableClientState(GL_VERTEX_ARRAY);
+       //glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+       
+       glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+
+       std::vector<object_ptr>::const_iterator it;
+       for (it = objects_.begin(); it != objects_.end(); ++it)
+       {
+               (*it)->draw(*this, alpha);
+       }
+}
+
+
+void mesh::set_material(int index) const
+{
+       set_material(materials_[index]);
+}
+
+void mesh::set_material(const material& material) const
+{
+       //glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material.diffuse.data());
+       //glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, material.ambient.data());
+       //glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material.specular.data());
+       //glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, material.emissive.data());
+       //glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material.shininess);
+       glColor(material.diffuse);
+}
+
+
+void mesh::object::draw(const mesh& mesh, scalar alpha) const
+{
+       //log_info("cool", verts.size());
+       //{
+               //image::reset_binding();
+               //std::vector<vector3>::const_iterator it;
+               //glBegin(GL_LINE_STRIP);
+               //for (it = verts.begin(); it != verts.end(); ++it)
+               //{
+                       //glVertex(*it);
+               //}
+               //glEnd();
+       //}
+       
+       glPolygonMode(GL_BACK, GL_LINE);
+       //glVertexPointer(3, GL_SCALAR, 0, verts[0].data());
+       if (texture) texture->bind();
+       else image::reset_binding();
+
+       for (int i = 0; i < faces.size(); ++i)
+       {
+               const material_group& face = faces[i];
+               mesh.set_material(i);
+               //it->draw(alpha);
+               //std::vector<unsigned>::const_iterator jt;
+               int count = face.triangles.size();
+               for (int j = 0; j < count; j += 3)
+               {
+                       glBegin(GL_TRIANGLES);
+                               glTexCoord(face.triangles_uv[j]);
+                               glVertex(verts[face.triangles[j]]);
+                               glTexCoord(face.triangles_uv[j+1]);
+                               glVertex(verts[face.triangles[j+1]]);
+                               glTexCoord(face.triangles_uv[j+2]);
+                               glVertex(verts[face.triangles[j+2]]);
+                       glEnd();
+               }
+
+               count = face.quads.size();
+               for (int j = 0; j < count; j += 4)
+               {
+                       glBegin(GL_QUADS);
+                               glTexCoord(face.quads_uv[j]);
+                               glVertex(verts[face.quads[j]]);
+                               glTexCoord(face.quads_uv[j+1]);
+                               glVertex(verts[face.quads[j+1]]);
+                               glTexCoord(face.quads_uv[j+2]);
+                               glVertex(verts[face.quads[j+2]]);
+                               glTexCoord(face.quads_uv[j+3]);
+                               glVertex(verts[face.quads[j+3]]);
+                       glEnd();
+               }
+       }
+
+       std::vector<object_ptr>::const_iterator jt;
+       for (jt = kids.begin(); jt != kids.end(); ++jt)
+       {
+               (*jt)->draw(mesh, alpha);
+       }
+}
+
+void mesh::material_group::draw(scalar alpha) const
+{
+       // TODO: setup material
+       
+       /*
+       if (triangles.size() > 0)
+       {
+               //log_info("drawing triangles:", triangles.size()/3);
+               glTexCoordPointer(2, GL_SCALAR, 0, triangles_uv[0].data());
+               glDrawElements(GL_TRIANGLES,
+                                          triangles.size(), GL_UNSIGNED_INT,
+                                          &triangles[0]);
+       }
+
+       if (quads.size() > 0)
+       {
+               //log_info("drawing quads:", quads.size()/4);
+               glTexCoordPointer(2, GL_SCALAR, 0, quads_uv[0].data());
+               glDrawElements(GL_QUADS, quads.size(), GL_UNSIGNED_INT, &quads[0]);
+       }
+       */
+}
+
+
+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.027665 seconds and 4 git commands to generate.