OSDN Git Service

merge local update
[meshio/meshio.git] / src / mqo.cpp
index 8c27c03..ca6834d 100644 (file)
 #include "mqo.h"
+#include "linereader.h"
 #include <iostream>
 #include <fstream>
 #include <sstream>
 #include <iomanip>
 #include <vector>
 
-#include "text.h"
-
 namespace meshio {
-namespace mqo {
-
-std::wstring 
-       Material::getName()const
-       {
-               return text::trim(text::cp932_to_unicode(name));
-       }
-
-std::wstring 
-       Material::getTexture()const
-       {
-               return text::trim(text::cp932_to_unicode(texture));
-       }
-
-std::wstring 
-       Object::getName()const
-       {
-               return text::trim(text::cp932_to_unicode(name));
-       }
-
-//! Tokenizer
-struct DELIMITER
-{
-       bool operator()(char c)
-       {
-               switch(c)
-               {
-               case ' ':
-               case '\t':
-               case '(':
-               case ')':
-                       return true;
-               default:
-                       return false;
-               }
-       }
-};
-typedef text::LineSplitter<DELIMITER> SPLITTER;
-
-
-//! \8eÀ\91\95
-class Implementation
-{
-       Scene &scene;
-       std::vector<Material> &materials;
-       std::vector<Object> &objects;
-
-public:
-       Implementation(Scene &_scene, std::vector<Material> &_materials,
-                       std::vector<Object> &_objects)
-               : scene(_scene), materials(_materials), objects(_objects)
-               {}
-
-       template<class READER> bool 
-               parse(READER reader)
-               {
-                       while(!reader.isEnd()){
-                               text::cstr line=reader.getLine();
-                               SPLITTER splitter(line);
-                               text::cstr key=splitter.get();
-                               if(key=="Scene"){
-                                       if(!readSceneChunk(reader)){
-                                               return false;
-                                       }
-                               }
-                               else if(key=="Material"){
-                                       if(!readMaterialChunk(reader, splitter.getInt())){
-                                               return false;
-                                       }
-                               }
-                               else if(key=="Object"){
-                                       if(!readObjectChunk(reader, splitter.getQuated())){
-                                               return false;
-                                       }
-                               }
-                               else if(key=="Eof"){
-                                       if(materials.empty()){
-                                               // fallback
-                                               //materials.push_back(Material());
-                                       }
-                                       return true;
-                               }
-                       }
-                       std::cout << "not found 'EOF'" << std::endl;
-                       return true;
-               }
-
-
-private:
-       template<class READER> bool 
-               readObjectChunk(READER &reader, text::cstr name)
-               {
-                       objects.push_back(Object());
-                       Object &object=objects.back();
-                       object.name=name.str();
-                       while(!reader.isEnd()){
-                               text::cstr line=reader.getLine();
-                               if(line=="}"){
-                                       return true;
-                               }
-                               SPLITTER splitter(line);
-                               text::cstr key=splitter.get();
-                               if(key=="depth"){
-                                       object.depth=splitter.getInt();
-                               }
-                               else if(key=="folding"){
-                                       object.folding=splitter.getInt();
-                               }
-                               else if(key=="scale"){
-                                       object.scale=splitter.getVector3();
-                               }
-                               else if(key=="rotation"){
-                                       object.rotation=splitter.getVector3();
-                               }
-                               else if(key=="translation"){
-                                       object.translation=splitter.getVector3();
-                               }
-                               else if(key=="visible"){
-                                       object.visible=splitter.getInt();
-                               }
-                               else if(key=="locking"){
-                                       object.locking=splitter.getInt();
-                               }
-                               else if(key=="shading"){
-                                       object.shading=splitter.getInt();
-                               }
-                               else if(key=="facet"){
-                                       object.smoothing=splitter.getFloat();
-                               }
-                               else if(key=="color"){
-                                       object.color=splitter.getVector3();
-                               }
-                               else if(key=="color_type"){
-                                       object.color_type=splitter.getInt();
-                               }
-                               else if(key=="vertex"){
-                                       if(!readObjectVertexChunk(reader, object, splitter.getInt())){
-                                               return false;
-                                       }
-                               }
-                               else if(key=="face"){
-                                       if(!readObjectFaceChunk(reader, object, splitter.getInt())){
-                                               return false;
-                                       }
-                               }
-                               else if(key=="segment"){
-                                       // ToDo
-                                       continue;
-                               }
-                               else if(key=="patch"){
-                                       // ToDo
-                                       continue;
-                               }
-                               else if(key=="mirror"){
-                                       object.mirror=splitter.getInt();
-                               }
-                               else{
-                                       std::cout << "unknown object key: " << key << std::endl;
-                               }
-                       }
-                       std::cout << "fail to readObjectChunk" << std::endl;
-                       return false;
-               }
-       template<class READER> bool 
-               readObjectVertexChunk(READER &reader, 
-                               Object &object, size_t vertex_count)
-               {
-                       while(!reader.isEnd()){
-                               text::cstr line=reader.getLine();
-                               if(line=="}"){
-                                       if(object.vertices.size()!=vertex_count){
-                                               std::cout << "invalid vertex count." 
-                                                       << " expected " << vertex_count
-                                                       << ", but " << object.vertices.size()
-                                                       << std::endl;
-                                               return false;
-                                       }
-                                       return true;
-                               }
-                               object.vertices.push_back(SPLITTER(line).getVector3());
-                       }
-                       std::cout << "fail to readObjectVertexChunk" << std::endl;
-                       return false;
-               }
-
-       template<class READER> bool 
-               readObjectFaceChunk(READER &reader,
-                               Object &object, size_t face_count)
-               {
-                       while(!reader.isEnd()){
-                               text::cstr line=reader.getLine();
-                               if(line=="}"){
-                                       if(object.faces.size()!=face_count){
-                                               std::cout << "invalid face count."
-                                                       << " expected " << face_count
-                                                       << ", but " << object.faces.size()
-                                                       << std::endl;
-                                               return false;
-                                       }
-                                       return true;
-                               }
-                               if(!readObjectFaceLine(object, line)){
-                                       return false;
-                               }
-                       }
-                       std::cout << "fail to readFaceChunk" << std::endl;
-                       return false;
-               }
-
-       bool 
-               readObjectFaceLine(Object &object, text::cstr line)
-               {
-                       object.faces.push_back(Face());
-                       Face &face=object.faces.back();
-                       SPLITTER splitter(line);
-                       face.index_count=splitter.getInt();
-                       while(true){
-                               text::cstr key=splitter.get();
-                               if(key==""){
-                                       break;
-                               }
-
-                               if(key=="V"){
-                                       for(size_t i=0; i<face.index_count; ++i){
-                                               face.indices[i]=splitter.getInt();
-                                       }
-                               }
-                               else if(key=="M"){
-                                       face.material_index=splitter.getInt();
-                               }
-                               else if(key=="UV"){
-                                       for(size_t i=0; i<face.index_count; ++i){
-                                               face.uv[i]=splitter.getVector2();
-                                       }
-                               }
-                               else if(key=="COL"){
-                                       for(size_t i=0; i<face.index_count; ++i){
-                                               face.color[i]=
-                                                       color::fRGBA::createFromUInt(splitter.getInt());
-                                       }
-                               }
-                               else{
-                                       std::cout << "unknown face key: " 
-                                               << '"' << key << '"'  << std::endl
-                                               ;
-                                       //return false;
-                                       break;
-                               }
-                       }
-                       return true;
-               }
-
-       template<class READER> bool 
-               readMaterialChunk(READER &reader, size_t material_count)
-               {
-                       while(!reader.isEnd()){
-                               text::cstr line=reader.getLine();
-                               if(line=="}"){
-                                       if(materials.size()!=material_count){
-                                               std::cout << "invalid material count." 
-                                                       << " expected " << material_count
-                                                       << ", but " << materials.size()
-                                                       << std::endl;
-                                               return false;
-                                       }
-                                       return true;
-                               }
-                               readMaterialLine(line);
-                       }
-                       std::cout << "fail to readMaterialChunk" << std::endl;
-                       return false;
-               }
-
-       void 
-               readMaterialLine(text::cstr line)
-               {
-                       materials.push_back(Material());
-                       Material &material=materials.back();
-
-                       SPLITTER splitter(line);
-                       material.name=splitter.getQuated().str();
-                       while(true){
-                               text::cstr key=splitter.get();
-                               if(key==""){
-                                       break;
-                               }
-                               else if(key=="shader"){
-                                       material.shader=splitter.getInt();
-                               }
-                               else if(key=="col"){
-                                       material.color=splitter.getFloatRGBA();
-                               }
-                               else if(key=="dif"){
-                                       material.diffuse=splitter.getFloat();
-                               }
-                               else if(key=="amb"){
-                                       material.ambient=splitter.getFloat();
-                               }
-                               else if(key=="emi"){
-                                       material.emit=splitter.getFloat();
-                               }
-                               else if(key=="spc"){
-                                       material.specular=splitter.getFloat();
-                               }
-                               else if(key=="power"){
-                                       material.power=splitter.getFloat();
-                               }
-                               else if(key=="tex"){
-                                       material.texture=splitter.getQuated().str();
-                               }
-                               else if(key=="aplane"){
-                                       material.alphamap=splitter.getQuated().str();
-                               }
-                               else if(key=="bump"){
-                                       material.bumpmap=splitter.getQuated().str();
-                               }
-                               else if(key=="vcol"){
-                                       material.vcol=splitter.getInt();
-                               }
-                               else{
-                                       std::cout << "unknown material key: \"" << key << '"' << std::endl;
-                                       //assert(false);
-                                       return;
-                               }
-                       }
-               }
-
-       template<class READER> bool 
-               readSceneChunk(READER &reader)
-               {
-                       while(!reader.isEnd()){
-                               text::cstr line=reader.getLine();
-                               if(line=="}"){
-                                       return true;
-                               }
-                               SPLITTER splitter(line);
-                               text::cstr key=splitter.get();
-                               if(key=="pos"){
-                                       scene.pos=splitter.getVector3();
-                               }
-                               else if(key=="lookat"){
-                                       scene.lookat=splitter.getVector3();
-                               }
-                               else if(key=="head"){
-                                       scene.head=splitter.getFloat();
-                               }
-                               else if(key=="pich") {
-                                       scene.pitch=splitter.getFloat();
-                               }
-                               else if(key=="ortho"){
-                                       scene.ortho=splitter.getInt();
-                               }
-                               else if(key=="zoom2"){
-                                       scene.zoom2=splitter.getFloat();
-                               }
-                               else if(key=="amb"){
-                                       scene.ambient=splitter.getVector3();
-                               }
-                               else{
-                                       std::cout << "unknown scene key: " << key << std::endl;
-                               }
-                       }
-                       std::cout << "fail to readSceneChunk" << std::endl;
-                       return false;
-               }
-
-       template<class READER> bool 
-               readChunk(READER &reader)
-               {
-                       int level=1;
-                       while(!reader.isEnd()){
-                               text::cstr line=reader.getLine();
-                               if(line=="}"){
-                                       level--;
-                                       if(level==0){
-                                               return true;
-                                       }
-                               }
-                               else if(line.include('{')){
-                                       level+=1;
-                               }
-                       }
-                       return false;
-               }
-
-};
-
-
-///////////////////////////////////////////////////////////////////////////////
-// IO
-///////////////////////////////////////////////////////////////////////////////
-bool IO::read(binary::IReader &input)
-{
-       text::LineReader<text::IsCRLF, text::IsWhiteSpace, text::IsEmpty> 
-               reader(input);
-       text::cstr line=reader.getLine();
-       if(line!="Metasequoia Document"){
-               return false;
-       }
-       line=reader.getLine();
-       if(line!="Format Text Ver 1.0"){
-               return false;
-       }
-
-       return Implementation(scene, materials, objects).parse(reader);
-}
-
-bool IO::read(const char *path)
-{
-       std::vector<char> all;
-       binary::readAll(path, all);
-       if(all.empty()){
-               return false;
-       }
-       binary::MemoryReader reader(&all[0], all.size());
-       return read(reader);
-}
-
-#ifdef _WIN32
-bool IO::read(const wchar_t *path)
-{
-       std::vector<char> all;
-       binary::readAll(path, all);
-       if(all.empty()){
-               return false;
-       }
-       binary::MemoryReader reader(&all[0], all.size());
-       return read(reader);
-}
-#endif
-
-bool IO::write(binary::IWriter &writer)
-{
-       // header
-       writer.printLn("Metasequoia Document");
-       writer.printLn("Format Text Ver 1.0");
-       writer.printLn("");
-
-       // scene
-       writer.printLn("Scene {");
-       writer.printLn("\tpos 0.0000 0.0000 1500.0000");
-       writer.printLn("\tlookat 0.0000 0.0000 0.0000");
-       writer.printLn("\thead -0.5236");
-       writer.printLn("\tpich 0.5236");
-       writer.printLn("\tortho 0");
-       writer.printLn("\tzoom2 5.0000");
-       writer.printLn("\tamb 0.250 0.250 0.250");
-       writer.printLn("}");
-
-       // materials
-       if(materials.size()>0){
-               writer.printLn("Material %d {", materials.size());
-               for(size_t i=0; i<materials.size(); ++i){
-                       Material &m=materials[i];
-               }
-               writer.printLn("}");
-       }
-
-       // objects
-       for(size_t i=0; i<objects.size(); ++i){
-               Object &o=objects[i];
-               writer.printLn("Object \"%s\" {", o.name.c_str());
-               writer.printLn("\tdepth 0");
-               writer.printLn("\tfolding 0");
-               writer.printLn("\tscale 1.000000 1.000000 1.000000");
-               writer.printLn("\trotation 0.000000 0.000000 0.000000");
-               writer.printLn("\ttranslation 0.000000 0.000000 0.000000");
-               writer.printLn("\tvisible 15");
-               writer.printLn("\tlocking 0");
-               writer.printLn("\tshading 1");
-               writer.printLn("\tfacet 59.5");
-               writer.printLn("\tcolor 0.898 0.400 0.137");
-               writer.printLn("\tcolor_type 0");
-               // vertex
-               writer.printLn("\tvertex %d {", o.vertices.size());
-               for(size_t j=0; j<o.vertices.size(); ++j){
-                       Vector3 &v=o.vertices[j];
-                       writer.printLn("\t\t%.4f %.4f %.4f", v.x, v.y, v.z);
-               }
-               writer.printLn("\t}");
-               // face
-               writer.printLn("\tface %d {", o.faces.size());
-               for(size_t j=0; j<o.faces.size(); ++j){
-                       Face &f=o.faces[j];
-
-                       std::stringstream ss;
-                       ss.setf(std::ios_base::fixed, std::ios_base::floatfield);
-                       ss 
-                               << "\t\t"
-                               << f.index_count
-                               ;
-                       ss << " V(";
-                       for(size_t k=0; k<f.index_count; ++k){
-                               if(k){
-                                       ss << ' ';
-                               }
-                               ss << f.indices[k];
-                       }
-                       ss << ") UV(";
-                       for(size_t k=0; k<f.index_count; ++k){
-                               if(k){
-                                       ss << ' ';
-                               }
-                               Vector2 &uv=f.uv[k];
-                               ss 
-                                       << std::setprecision(5) << uv.x 
-                                       << ' ' << std::setprecision(5) << uv.y;
-                       }
-                       ss << ")";
-
-                       writer.printLn(ss.str().c_str());
-               }
-               writer.printLn("\t}");
-               // close
-               writer.printLn("}");
-       }
-       // Eof
-       writer.printLn("Eof");
-
-       return true;
-}
-
-bool IO::write(const char *path)
-{
-       binary::FileWriter writer(path);
-       return write(writer);
-}
-
-}
+  namespace mqo {
+
+    //! Tokenizer
+    struct DELIMITER
+    {
+      bool operator()(char c)
+      {
+        switch(c)
+        {
+          case ' ':
+          case '\t':
+          case '(':
+          case ')':
+            return true;
+          default:
+            return false;
+        }
+      }
+    };
+    typedef LineSplitter<DELIMITER> SPLITTER;
+
+
+    //! \8eÀ\91\95
+    class Implementation
+    {
+      Scene &scene;
+      std::vector<Material> &materials;
+      std::vector<Object> &objects;
+
+    public:
+      Implementation(Scene &_scene, std::vector<Material> &_materials,
+          std::vector<Object> &_objects)
+        : scene(_scene), materials(_materials), objects(_objects)
+      {}
+
+      template<class READER> bool 
+        parse(READER reader)
+        {
+          while(!reader.isEnd()){
+            cstr line=reader.getLine();
+            SPLITTER splitter(line);
+            cstr key=splitter.get();
+            if(key=="Scene"){
+              if(!readSceneChunk(reader)){
+                return false;
+              }
+            }
+            else if(key=="Material"){
+              if(!readMaterialChunk(reader, splitter.getInt())){
+                return false;
+              }
+            }
+            else if(key=="Object"){
+              if(!readObjectChunk(reader, splitter.getQuated())){
+                return false;
+              }
+            }
+            else if(key=="Eof"){
+              if(materials.empty()){
+                // fallback
+                //materials.push_back(Material());
+              }
+              return true;
+            }
+          }
+          std::cout << "not found 'EOF'" << std::endl;
+          return true;
+        }
+
+
+    private:
+      template<class READER> bool 
+        readObjectChunk(READER &reader, cstr name)
+        {
+          objects.push_back(Object());
+          Object &object=objects.back();
+          object.name=name.str();
+          while(!reader.isEnd()){
+            cstr line=reader.getLine();
+            if(line=="}"){
+              return true;
+            }
+            SPLITTER splitter(line);
+            cstr key=splitter.get();
+            if(key=="depth"){
+              object.depth=splitter.getInt();
+            }
+            else if(key=="folding"){
+              object.folding=splitter.getInt();
+            }
+            else if(key=="scale"){
+              object.scale=splitter.getVector3();
+            }
+            else if(key=="rotation"){
+              object.rotation=splitter.getVector3();
+            }
+            else if(key=="translation"){
+              object.translation=splitter.getVector3();
+            }
+            else if(key=="visible"){
+              object.visible=splitter.getInt();
+            }
+            else if(key=="locking"){
+              object.locking=splitter.getInt();
+            }
+            else if(key=="shading"){
+              object.shading=splitter.getInt();
+            }
+            else if(key=="facet"){
+              object.smoothing=splitter.getFloat();
+            }
+            else if(key=="color"){
+              object.color=splitter.getVector3();
+            }
+            else if(key=="color_type"){
+              object.color_type=splitter.getInt();
+            }
+            else if(key=="vertex"){
+              if(!readObjectVertexChunk(reader, object, splitter.getInt())){
+                return false;
+              }
+            }
+            else if(key=="face"){
+              if(!readObjectFaceChunk(reader, object, splitter.getInt())){
+                return false;
+              }
+            }
+            else if(key=="segment"){
+              // ToDo
+              continue;
+            }
+            else if(key=="patch"){
+              // ToDo
+              continue;
+            }
+            else if(key=="mirror"){
+              object.mirror=splitter.getInt();
+            }
+            else{
+              std::cout << "unknown object key: " << key << std::endl;
+            }
+          }
+          std::cout << "fail to readObjectChunk" << std::endl;
+          return false;
+        }
+      template<class READER> bool 
+        readObjectVertexChunk(READER &reader, 
+            Object &object, size_t vertex_count)
+        {
+          while(!reader.isEnd()){
+            cstr line=reader.getLine();
+            if(line=="}"){
+              if(object.vertices.size()!=vertex_count){
+                std::cout << "invalid vertex count." 
+                  << " expected " << vertex_count
+                  << ", but " << object.vertices.size()
+                  << std::endl;
+                return false;
+              }
+              return true;
+            }
+            object.vertices.push_back(SPLITTER(line).getVector3());
+          }
+          std::cout << "fail to readObjectVertexChunk" << std::endl;
+          return false;
+        }
+
+      template<class READER> bool 
+        readObjectFaceChunk(READER &reader,
+            Object &object, size_t face_count)
+        {
+          while(!reader.isEnd()){
+            cstr line=reader.getLine();
+            if(line=="}"){
+              if(object.faces.size()!=face_count){
+                std::cout << "invalid face count."
+                  << " expected " << face_count
+                  << ", but " << object.faces.size()
+                  << std::endl;
+                return false;
+              }
+              return true;
+            }
+            if(!readObjectFaceLine(object, line)){
+              return false;
+            }
+          }
+          std::cout << "fail to readFaceChunk" << std::endl;
+          return false;
+        }
+
+      bool 
+        readObjectFaceLine(Object &object, cstr line)
+        {
+          object.faces.push_back(Face());
+          Face &face=object.faces.back();
+          SPLITTER splitter(line);
+          face.index_count=splitter.getInt();
+          while(true){
+            cstr key=splitter.get();
+            if(key==""){
+              break;
+            }
+
+            if(key=="V"){
+              for(size_t i=0; i<face.index_count; ++i){
+                face.indices[i]=splitter.getInt();
+              }
+            }
+            else if(key=="M"){
+              face.material_index=splitter.getInt();
+            }
+            else if(key=="UV"){
+              for(size_t i=0; i<face.index_count; ++i){
+                face.uv[i]=splitter.getVector2();
+              }
+            }
+            else if(key=="COL"){
+              for(size_t i=0; i<face.index_count; ++i){
+                face.color[i]=
+                  fRGBA::createFromUInt(splitter.getInt());
+              }
+            }
+            else{
+              std::cout << "unknown face key: " 
+                << '"' << key << '"'  << std::endl
+                ;
+              //return false;
+              break;
+            }
+          }
+          return true;
+        }
+
+      template<class READER> bool 
+        readMaterialChunk(READER &reader, size_t material_count)
+        {
+          while(!reader.isEnd()){
+            cstr line=reader.getLine();
+            if(line=="}"){
+              if(materials.size()!=material_count){
+                std::cout << "invalid material count." 
+                  << " expected " << material_count
+                  << ", but " << materials.size()
+                  << std::endl;
+                return false;
+              }
+              return true;
+            }
+            readMaterialLine(line);
+          }
+          std::cout << "fail to readMaterialChunk" << std::endl;
+          return false;
+        }
+
+      void 
+        readMaterialLine(cstr line)
+        {
+          materials.push_back(Material());
+          Material &material=materials.back();
+
+          SPLITTER splitter(line);
+          material.name=splitter.getQuated().str();
+          while(true){
+            cstr key=splitter.get();
+            if(key==""){
+              break;
+            }
+            else if(key=="shader"){
+              material.shader=splitter.getInt();
+            }
+            else if(key=="col"){
+              material.color=splitter.getFloatRGBA();
+            }
+            else if(key=="dif"){
+              material.diffuse=splitter.getFloat();
+            }
+            else if(key=="amb"){
+              material.ambient=splitter.getFloat();
+            }
+            else if(key=="emi"){
+              material.emit=splitter.getFloat();
+            }
+            else if(key=="spc"){
+              material.specular=splitter.getFloat();
+            }
+            else if(key=="power"){
+              material.power=splitter.getFloat();
+            }
+            else if(key=="tex"){
+              material.texture=splitter.getQuated().str();
+            }
+            else if(key=="aplane"){
+              material.alphamap=splitter.getQuated().str();
+            }
+            else if(key=="bump"){
+              material.bumpmap=splitter.getQuated().str();
+            }
+            else if(key=="vcol"){
+              material.vcol=splitter.getInt();
+            }
+            else{
+              std::cout << "unknown material key: \"" << key << '"' << std::endl;
+              //assert(false);
+              return;
+            }
+          }
+        }
+
+      template<class READER> bool 
+        readSceneChunk(READER &reader)
+        {
+          while(!reader.isEnd()){
+            cstr line=reader.getLine();
+            if(line=="}"){
+              return true;
+            }
+            SPLITTER splitter(line);
+            cstr key=splitter.get();
+            if(key=="pos"){
+              scene.pos=splitter.getVector3();
+            }
+            else if(key=="lookat"){
+              scene.lookat=splitter.getVector3();
+            }
+            else if(key=="head"){
+              scene.head=splitter.getFloat();
+            }
+            else if(key=="pich") {
+              scene.pitch=splitter.getFloat();
+            }
+            else if(key=="ortho"){
+              scene.ortho=splitter.getInt();
+            }
+            else if(key=="zoom2"){
+              scene.zoom2=splitter.getFloat();
+            }
+            else if(key=="amb"){
+              scene.ambient=splitter.getVector3();
+            }
+            else{
+              std::cout << "unknown scene key: " << key << std::endl;
+            }
+          }
+          std::cout << "fail to readSceneChunk" << std::endl;
+          return false;
+        }
+
+      template<class READER> bool 
+        readChunk(READER &reader)
+        {
+          int level=1;
+          while(!reader.isEnd()){
+            cstr line=reader.getLine();
+            if(line=="}"){
+              level--;
+              if(level==0){
+                return true;
+              }
+            }
+            else if(line.include('{')){
+              level+=1;
+            }
+          }
+          return false;
+        }
+
+    };
+
+
+    // IO
+    bool IO::read(binary::IReader &input)
+    {
+      LineReader<IsCRLF, IsWhiteSpace, IsEmpty> 
+        reader(input);
+      cstr line=reader.getLine();
+      if(line!="Metasequoia Document"){
+        return false;
+      }
+      line=reader.getLine();
+      if(line!="Format Text Ver 1.0"){
+        return false;
+      }
+
+      return Implementation(scene, materials, objects).parse(reader);
+    }
+
+    bool IO::read(const char *path)
+    {
+      std::vector<char> all;
+      binary::readAll(path, all);
+      if(all.empty()){
+        return false;
+      }
+      binary::MemoryReader reader(&all[0], all.size());
+      return read(reader);
+    }
+
+    bool IO::write(binary::IWriter &writer)
+    {
+      // header
+      writer.printLn("Metasequoia Document");
+      writer.printLn("Format Text Ver 1.0");
+      writer.printLn("");
+
+      // scene
+      writer.printLn("Scene {");
+      writer.printLn("\tpos 0.0000 0.0000 1500.0000");
+      writer.printLn("\tlookat 0.0000 0.0000 0.0000");
+      writer.printLn("\thead -0.5236");
+      writer.printLn("\tpich 0.5236");
+      writer.printLn("\tortho 0");
+      writer.printLn("\tzoom2 5.0000");
+      writer.printLn("\tamb 0.250 0.250 0.250");
+      writer.printLn("}");
+
+      // materials
+      if(materials.size()>0){
+        writer.printLn("Material %d {", materials.size());
+        /*
+        for(size_t i=0; i<materials.size(); ++i){
+          Material &m=materials[i];
+        }
+        */
+        writer.printLn("}");
+      }
+
+      // objects
+      for(size_t i=0; i<objects.size(); ++i){
+        Object &o=objects[i];
+        writer.printLn("Object \"%s\" {", o.name.c_str());
+        writer.printLn("\tdepth 0");
+        writer.printLn("\tfolding 0");
+        writer.printLn("\tscale 1.000000 1.000000 1.000000");
+        writer.printLn("\trotation 0.000000 0.000000 0.000000");
+        writer.printLn("\ttranslation 0.000000 0.000000 0.000000");
+        writer.printLn("\tvisible 15");
+        writer.printLn("\tlocking 0");
+        writer.printLn("\tshading 1");
+        writer.printLn("\tfacet 59.5");
+        writer.printLn("\tcolor 0.898 0.400 0.137");
+        writer.printLn("\tcolor_type 0");
+        // vertex
+        writer.printLn("\tvertex %d {", o.vertices.size());
+        for(size_t j=0; j<o.vertices.size(); ++j){
+          Vector3 &v=o.vertices[j];
+          writer.printLn("\t\t%.4f %.4f %.4f", v.x, v.y, v.z);
+        }
+        writer.printLn("\t}");
+        // face
+        writer.printLn("\tface %d {", o.faces.size());
+        for(size_t j=0; j<o.faces.size(); ++j){
+          Face &f=o.faces[j];
+
+          std::stringstream ss;
+          ss.setf(std::ios_base::fixed, std::ios_base::floatfield);
+          ss 
+            << "\t\t"
+            << f.index_count
+            ;
+          ss << " V(";
+          for(size_t k=0; k<f.index_count; ++k){
+            if(k){
+              ss << ' ';
+            }
+            ss << f.indices[k];
+          }
+          ss << ") UV(";
+          for(size_t k=0; k<f.index_count; ++k){
+            if(k){
+              ss << ' ';
+            }
+            Vector2 &uv=f.uv[k];
+            ss 
+              << std::setprecision(5) << uv.x 
+              << ' ' << std::setprecision(5) << uv.y;
+          }
+          ss << ")";
+
+          writer.printLn(ss.str().c_str());
+        }
+        writer.printLn("\t}");
+        // close
+        writer.printLn("}");
+      }
+      // Eof
+      writer.printLn("Eof");
+
+      return true;
+    }
+
+    bool IO::write(const char *path)
+    {
+      binary::FileWriter writer(path);
+      return write(writer);
+    }
+
+  }
 }