OSDN Git Service

first commit.
authorousttrue <ousttrue@gmail.com>
Thu, 29 Apr 2010 23:45:51 +0000 (08:45 +0900)
committerousttrue <ousttrue@gmail.com>
Thu, 29 Apr 2010 23:47:28 +0000 (08:47 +0900)
18 files changed:
README [new file with mode: 0644]
bin/premake4.exe [new file with mode: 0755]
include/binary.h [new file with mode: 0644]
include/color.h [new file with mode: 0644]
include/la.h [new file with mode: 0644]
include/meshio.h [new file with mode: 0644]
include/mqo.h [new file with mode: 0644]
include/pmd.h [new file with mode: 0644]
include/text.h [new file with mode: 0644]
include/vmd.h [new file with mode: 0644]
premake4.lua [new file with mode: 0644]
src/binary.cpp [new file with mode: 0644]
src/mqo.cpp [new file with mode: 0644]
src/pmd.cpp [new file with mode: 0644]
src/vmd.cpp [new file with mode: 0644]
test/cube.mqo [new file with mode: 0644]
test/main.cpp [new file with mode: 0644]
test/premake4.lua [new file with mode: 0644]

diff --git a/README b/README
new file mode 100644 (file)
index 0000000..d8d6a65
--- /dev/null
+++ b/README
@@ -0,0 +1,37 @@
+MeshIO\83\89\83C\83u\83\89\83\8a
+
+\82±\82ê\82Í\81Amqo, pmd, vmd\82Ì\93Ç\82Ý\8d\9e\82Ý\82ð\96Ú\93I\82Æ\82µ\82½\83\89\83C\83u\83\89\83\8a\82Å\82·\81B
+\91Î\8fÛ\82Ì\83t\83@\83C\83\8b\82ð\83p\81[\83X\82µ\82Ä\93Ç\82Ý\8d\9e\82Þ\82Æ\82±\82ë\82Ü\82Å\82ð\8eÀ\8ds\82µ\82Ü\82·\81B
+
+*\83\89\83C\83Z\83\93\83X
+zlib\83\89\83C\83Z\83\93\83X
+
+*VC2008\82Å\82Ì\83r\83\8b\83h\95û\96@
+**\83\\83\8a\83\85\81[\83V\83\87\83\93\82Ì\90\90¬
+\83v\83\8d\83W\83F\83N\83g\82Ì\8aÇ\97\9d\82Épremake4(http://industriousone.com/premake)\82ð\97\98\97p\82µ\82Ä\82¢\82Ü\82·\81B Windows\8cü\82¯\82Ì\8eÀ\8ds\83t\83@\83C\83\8b\82ð\93¯\8d«\82µ\82Ä\82¢\82é\82Ì\82Å\88È\89º\82Ì\83R\83}\83\93\83h\82ðDOS\83v\83\8d\83\93\83v\83g\82Å\8eÀ\8ds\82µ\82Ä\82­\82¾\82³\82¢\81B
+
+> cd MeshIO
+> bin\premake4.exe vs2008
+
+meshio.sln\82ª\90\90¬\82³\82ê\82é\82Ì\82Å\82±\82ê\82ðVC\82Å\8aJ\82¢\82Ä\83r\83\8b\83h\82µ\82Ä\82­\82¾\82³\82¢\81B
+
+\88È\89º\82Ìstatic\83\89\83C\83u\83\89\83\8a\82ª\90\90¬\82³\82ê\82Ü\82·\81B
+debug/meshio.lib
+release/meshio.lib
+
+*\8eg\82¢\95û
+\82Æ\82è\82 \82¦\82¸test/main.cpp\82Æinclude/{mqo,pmd,vmd}.h\82ð\8c©\82Ä\82­\82¾\82³\82¢\81B
+
+*\97\\92è
+-vpd, DirextX9\82Ìx\8c`\8e®, bvh\82Ö\82Ì\91Î\89\9e
+-\8f\91\82«\8d\9e\82Ý\8b@\94\
+-python\83o\83C\83\93\83f\83B\83\93\83O
+-blender\8cü\82¯\82Ìmqo, pmd, vmd\83C\83\93\83|\81[\83^\81E\83G\83N\83X\83|\81[\83^
+-gcc\91Î\89\9e
+
+*\97\9a\97ð
+2010/04/30 SourceForge\82É\8fê\8f\8a\8am\95Û\81Bmqo, pmd, vmd\82Ì\93Ç\82Ý\8d\9e\82Ý\82ð\8eÀ\91\95\81B
+
+*URL
+https://sourceforge.jp/projects/meshio
+
diff --git a/bin/premake4.exe b/bin/premake4.exe
new file mode 100755 (executable)
index 0000000..28e45a3
Binary files /dev/null and b/bin/premake4.exe differ
diff --git a/include/binary.h b/include/binary.h
new file mode 100644 (file)
index 0000000..d685ed4
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef MESH_IO_BINARY_H_INCLUDED
+#define MESH_IO_BINARY_H_INCLUDED
+
+#include <fstream>
+#include <vector>
+#include <assert.h>
+
+namespace meshio {
+namespace binary {
+
+/**
+ * \83f\81[\83^\93Ç\82Ý\8d\9e\82Ý\83C\83\93\83^\81[\83t\83F\81[\83X
+ */
+class IReader
+{
+public:
+       virtual ~IReader(){}
+       virtual unsigned int read(char *buf, unsigned int size)=0;
+       virtual unsigned int getPos()const=0;
+       virtual bool isEnd()const=0;
+
+       template<typename T>
+               bool get(T &t)
+               {
+                       if(read(reinterpret_cast<char*>(&t), sizeof(t))){
+                               return true;
+                       }
+                       else{
+                               return false;
+                       }
+               }
+       char getChar()
+       {
+               char byte;
+               return get(byte) ? byte : 0;
+       }
+       std::string getString(unsigned int length, bool isTrim=false)
+       {
+               std::vector<char> buf(length);
+               read(&buf[0], buf.size());
+
+               std::vector<char>::iterator it;
+               if(isTrim){
+                       it=buf.begin();
+                       for(; it!=buf.end(); ++it){
+                               if(*it=='\0'){
+                                       break;
+                               }
+                       }
+               }
+               else{
+                       it=buf.end();
+               }
+               return std::string(buf.begin(), it);
+       }
+       unsigned char getUchar()
+       {
+               unsigned char value;
+               return get(value) ? value : 0;
+       }
+       unsigned short getUshort()
+       {
+               unsigned short value;
+               return get(value) ? value : 0;
+       }
+       unsigned int getUint()
+       {
+               unsigned int value;
+               return get(value) ? value : 0;
+       }
+};
+
+/**
+ * \83t\83@\83C\83\8b\82©\82ç\82Ì\93Ç\82Ý\8d\9e\82Ý
+ */
+class FileReader : public IReader
+{
+       std::ifstream io_;
+       unsigned int pos_;
+       bool eof_;
+
+public:
+       FileReader(const char *path);
+       virtual ~FileReader();
+       virtual unsigned int read(char *buf, unsigned int size);
+       virtual unsigned int getPos()const;
+       virtual bool isEnd()const;
+};
+
+/**
+ * \83\81\83\82\83\8a\82©\82ç\82Ì\93Ç\82Ý\8d\9e\82Ý
+ */
+class MemoryReader : public IReader
+{
+       const char *buf_;
+       unsigned int size_;
+       unsigned int pos_;
+
+public:
+       MemoryReader(const char *buf, unsigned int size);
+       virtual ~MemoryReader();
+       virtual unsigned int read(char *buf, unsigned int size);
+       virtual unsigned int getPos()const;
+       virtual bool isEnd()const;
+};
+
+ void readAll(const char *path, std::vector<char> &all);
+
+} // namespace binary
+} // namespace meshio
+
+#endif // MESH_IO_BINARY_H_INCLUDED
diff --git a/include/color.h b/include/color.h
new file mode 100644 (file)
index 0000000..443aa09
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef MESH_IO_COLOR_H_INCLUDED
+#define MESH_IO_COLOR_H_INCLUDED
+
+namespace meshio {
+namespace color {
+
+//! Byte\95Û\8e\9d\82ÌGBA
+struct bRGBA
+{
+       char r;
+       char g;
+       char b;
+       char a;
+
+       bRGBA()
+       {}
+
+       bRGBA(int _r, int _g, int _b, int _a)
+               : r(_r), g(_g), b(_b), a(_a)
+       {}
+
+       static bRGBA createFromUInt(unsigned int uint)
+       {
+               return bRGBA(
+                       uint & 0x000000FF,
+                       uint & 0x0000FF00 >> 8,
+                       uint & 0x00FF0000 >> 16,
+                       uint & 0xFF000000 >> 24
+                       );
+       }
+};
+inline std::ostream &operator<<(std::ostream &os, const bRGBA &rhs)
+{
+       return os
+               << '[' << rhs.r << ',' << rhs.g << ',' << rhs.b << ',' << rhs.a << ']';
+}
+
+//! Float\95Û\8e\9d\82ÌRGBA
+struct fRGBA
+{
+       float r;
+       float g;
+       float b;
+       float a;
+};
+inline std::ostream &operator<<(std::ostream &os, const fRGBA &rhs)
+{
+       return os
+               << '[' << rhs.r << ',' << rhs.g << ',' << rhs.b << ',' << rhs.a << ']';
+}
+
+
+//! Float\95Û\8e\9d\82ÌRGB
+struct fRGB
+{
+       float r;
+       float g;
+       float b;
+};
+inline std::ostream &operator<<(std::ostream &os, const fRGB &rhs)
+{
+       return os
+               << '[' << rhs.r << ',' << rhs.g << ',' << rhs.b << ',' << ']';
+}
+
+
+} // namespace color
+} // namespace meshio
+
+#endif // MESH_IO_COLOR_H_INCLUDED
diff --git a/include/la.h b/include/la.h
new file mode 100644 (file)
index 0000000..e0fe84d
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef MESH_IO_LA_H_INCLUDED
+#define MESH_IO_LA_H_INCLUDED
+
+#include <ostream>
+
+namespace meshio {
+namespace la {
+/**
+ * \e$B@~7ABe?t\e(B(Linear Algebra)
+ */
+
+struct Vector2
+{
+       float x;
+       float y;
+
+       Vector2()
+       {}
+
+       Vector2(float _x, float _y)
+               : x(_x), y(_y)
+               {}
+};
+inline std::ostream &operator<<(std::ostream &os, const Vector2 &rhs)
+{
+       return os
+               << '[' << rhs.x << ',' << rhs.y << ']';
+}
+
+
+struct Vector3
+{
+       float x;
+       float y;
+       float z;
+
+       Vector3()
+       {}
+
+       Vector3(float _x, float _y, float _z)
+               : x(_x), y(_y), z(_z)
+               {}
+
+       bool operator==(const Vector3 &rhs)const
+       {
+               return x==rhs.x && y==rhs.y && z==rhs.z;
+       }
+};
+inline std::ostream &operator<<(std::ostream &os, const Vector3 &rhs)
+{
+       return os
+               << '[' << rhs.x << ',' << rhs.y << ',' << rhs.z << ']';
+}
+
+
+struct Vector4
+{
+       float x;
+       float y;
+       float z;
+       float w;
+
+       Vector4()
+       {}
+
+       Vector4(float _x, float _y, float _z, float _w)
+               : x(_x), y(_y), z(_z), w(_w)
+               {}
+};
+inline std::ostream &operator<<(std::ostream &os, const Vector4 &rhs)
+{
+       return os
+               << '[' << rhs.x << ',' << rhs.y << ',' << rhs.z << ',' << rhs.w << ']';
+}
+
+
+struct Quaternion
+{
+       float x;
+       float y;
+       float z;
+       float w;
+
+       Quaternion()
+       {}
+
+       Quaternion(float _x, float _y, float _z, float _w)
+               : x(_x), y(_y), z(_z), w(_w)
+               {}
+};
+inline std::ostream &operator<<(std::ostream &os, const Quaternion &rhs)
+{
+       return os
+               << '[' << rhs.x << ',' << rhs.y << ',' << rhs.z << ',' << rhs.w << ']';
+}
+
+
+}
+}
+
+#endif // MESH_IO_LA_H_INCLUDED
diff --git a/include/meshio.h b/include/meshio.h
new file mode 100644 (file)
index 0000000..481b1f7
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef MESH_IO_H_INCLUCDED
+#define MESH_IO_H_INCLUCDED
+
+#include "binary.h"
+#include "text.h"
+#include "mqo.h"
+#include "pmd.h"
+#include "vmd.h"
+
+#endif // MESH_IO_H_INCLUCDED
diff --git a/include/mqo.h b/include/mqo.h
new file mode 100644 (file)
index 0000000..f8da2f6
--- /dev/null
@@ -0,0 +1,242 @@
+/**
+ * MQO\8c`\8e®
+ * \83\81\83^\83Z\83R\83C\83A\82Ì\83\82\83f\83\8b\83f\81[\83^\81B\83e\83L\83X\83g\8c`\8e®\81B
+ * \83}\83e\83\8a\83A\83\8b\8fî\95ñ\82Æ\8c`\8fó\83f\81[\83^\82ð\95Û\8e\9d\82·\82é\81B
+ * \83\82\83f\83\8a\83\93\83O\8cü\82¯\82É\88Ù\82È\82é\92¸\93_\91®\90«\82ð\8e\9d\82Â\92¸\93_\82ð\82Ð\82Æ\82Â\82Ì\92¸\93_\82Æ\82µ\82Ä\88µ\82Á\82Ä\82¢\82é\82Ì\82Å\81A
+ * \83v\83\8d\83O\83\89\83\80\82Å\92¸\93_\94z\97ñ\82ð\8dì\82é\8fê\8d\87\82Í\83}\83e\83\8a\83A\83\8b\81AUV\82È\82Ç\82ª\88Ù\82È\82é\92l\82ð\8e\9d\82Â\92¸\93_\82ð
+ * \95Ê\82Ì\92¸\93_\82Æ\82µ\82Ä\95ª\97£\82·\82é\8dì\8bÆ\82ª\95K\97v\82É\82È\82é\81B
+ * \96@\90ü\82Í\8cv\8eZ\82µ\82Ä\8eZ\8fo\82·\82é\95K\97v\82ª\82 \82é\81B
+ *
+ * \8dÀ\95W\8cn
+ * \89E\8eè Y-UP
+ *
+ * \96Ê\82Ì\95\
+ * clock wise ?
+ *
+ * UV\8c´\93_
+ * left top ?
+ *
+ * \96@\90ü
+ * \83I\83u\83W\83F\83N\83g\82Ì\95Û\8e\9d\82·\82é\83X\83\80\81[\83W\83\93\83O\92l\82ð\8eQ\8fÆ\82µ\82Ä\96Ê\96@\90ü\82©\82ç\8cv\8eZ\82·\82é\81B
+ *
+ * \97 \96Ê\82Ì\88µ\82¢
+ * \83I\83\8a\83W\83i\83\8b\82Å\82Í\83o\83b\83N\83J\83\8a\83\93\83O\97L\8cø\81B
+ *
+ * MIKOTO\95û\8e®\82Ì\83{\81[\83\93
+ * MQO\82Í\95W\8f\80\82Å\83X\83L\83j\83\93\83O\8fî\95ñ\82ð\8e\9d\82½\82È\82¢\82ª\81A\93Á\92è\82Ì\83\8b\81[\83\8b\82Å\83}\83e\83\8a\83A\83\8b\82Æ\83I\83u\83W\83F\83N\83g
+ * \82ð\8dì\90¬\82·\82é\82±\82Æ\82Å\82±\82ê\82ð\8dì\90¬\82·\82é\81B
+ *
+ * \8eQ\8dl\83T\83C\83g
+ * http://www.metaseq.net/metaseq/format.html
+ */
+
+#ifndef MESH_IO_MQO_H_INCLUDED
+#define MESH_IO_MQO_H_INCLUDED 
+
+#include <iosfwd>
+#include <vector>
+#include "la.h"
+#include "color.h"
+#include "text.h"
+
+namespace meshio {
+namespace mqo {
+
+typedef la::Vector2 Vector2;
+typedef la::Vector3 Vector3;
+typedef la::Vector4 Vector4;
+typedef color::bRGBA RGBA;
+
+//! Scene\83`\83\83\83\93\83N
+struct Scene
+{
+       Vector3 pos;
+       Vector3 lookat;
+       float head;
+       float pitch;
+       int ortho;
+       float zoom2;
+       Vector3 ambient;
+       Scene()
+               : head(0), pitch(0), ortho(false), zoom2(2)
+               {}
+};
+inline std::ostream &operator<<(std::ostream &os, const Scene &rhs)
+{
+       os
+               << "<Scene"
+               << " pos: " << rhs.pos
+               << ", lookat: " << rhs.lookat
+               << ", head: " << rhs.head
+               << ", pitch: " << rhs.pitch
+               << ", ortho: " << rhs.ortho
+               << ", zoom2: " << rhs.zoom2
+               << ", ambient: " << rhs.ambient
+               << ">"
+               ;
+       return os;
+}
+
+//! Material\83`\83\83\83\93\83N
+struct Material
+{
+       std::string name;
+       int shader;
+       RGBA color;
+       float diffuse;
+       float ambient;
+       float emmit;
+       float specular;
+       float power;
+       std::string texture;
+       std::string alphamap;
+       std::string bumpmap;
+       int vcol;
+
+       Material()
+               : shader(0), diffuse(1), ambient(0), emmit(0), specular(0), power(0),
+               vcol(0)
+               {}
+};
+inline std::ostream &operator<<(std::ostream &os, const Material &rhs)
+{
+       os
+               << "<Material "
+               << '"' << rhs.name << '"'
+               << " shader:" << rhs.shader
+               << ", color:" << rhs.color
+               << ", diffuse:" << rhs.diffuse
+               << ", ambient:" << rhs.ambient
+               << ", emmit:" << rhs.emmit
+               << ", specular:" << rhs.specular
+               << ", power:" << rhs.power
+               << ", texture:\"" << rhs.texture << '"'
+               << ", alphamap:\"" << rhs.alphamap << '"'
+               << ", bumpmap:\"" << rhs.bumpmap << '"'
+               << ">"
+               ;
+       return os;
+}
+
+//! face\83`\83\83\83\93\83N
+struct Face
+{
+       unsigned int index_count;
+       unsigned int indices[4];
+       unsigned int material_index;
+       Vector2 uv[4];
+       RGBA color[4];
+       Face()
+               : index_count(0), material_index(0)
+               {
+                       indices[0]=0;
+                       indices[1]=0;
+                       indices[2]=0;
+                       indices[3]=0;
+                       uv[0]=Vector2();
+                       uv[1]=Vector2();
+                       uv[2]=Vector2();
+                       uv[3]=Vector2();
+               }
+};
+inline std::ostream &operator<<(std::ostream &os, const Face &rhs)
+{
+       switch(rhs.index_count)
+       {
+       case 2:
+               os
+                       << "<Edge "
+                       << "indices:{" << rhs.indices[0] << ',' << rhs.indices[1] << "}"
+                       << ", material_index: " << rhs.material_index
+                       << ", uv:{" << rhs.uv[0] << ',' << rhs.uv[1] << "}"
+                       << ", color:{" << rhs.color[0] << ',' << rhs.color[1] << "}"
+                       << ">"
+                       ;
+               break;
+
+       case 3:
+               os
+                       << "<Triangle "
+                       << "indices:{" << rhs.indices[0] 
+                       << ',' << rhs.indices[1] 
+                       << ',' << rhs.indices[2] << "}"
+                       << ", material_index: " << rhs.material_index
+                       << ", uv:{" << rhs.uv[0] << ',' << rhs.uv[1] << ',' << rhs.uv[2] << "}"
+                       << ", color:{" 
+                       << rhs.color[0] << ',' << rhs.color[1] << ',' <<  rhs.color[2] << "}"
+                       << ">"
+                       ;
+               break;
+
+       case 4:
+               os
+                       << "<Rectangle "
+                       << "indices:{" << rhs.indices[0] 
+                       << ',' << rhs.indices[1] 
+                       << ',' << rhs.indices[2] 
+                       << ',' << rhs.indices[3] << "}"
+                       << ", material_index: " << rhs.material_index
+                       << ", uv:{" << rhs.uv[0] << ',' << rhs.uv[1] 
+                       << ',' <<  rhs.uv[2] << ',' << rhs.uv[3] << "}"
+                       << ", color:{" << rhs.color[0] 
+                       << ',' << rhs.color[1] 
+                       << ',' <<  rhs.color[2] 
+                       << ',' <<  rhs.color[3] << "}"
+                       << ">"
+                       ;
+               break;
+       default:
+               assert(false);
+       }
+
+       return os;
+}
+
+//! Object\83`\83\83\83\93\83N
+struct Object
+{
+       std::string name;
+       int depth;
+       int folding;
+       Vector3 scale;
+       Vector3 rotation;
+       Vector3 translation;
+       int visible;
+       int locking;
+       int shading;
+       float smoothing;
+       Vector3 color;
+       int color_type;
+
+       std::vector<Vector3> vertices;
+       std::vector<Face> faces;
+};
+inline std::ostream &operator<<(std::ostream &os, const Object &rhs)
+{
+       os
+               << "<Object "
+               << '"' << rhs.name << '"'
+               << " vertices:" << rhs.vertices.size()
+               << ", faces:" << rhs.faces.size()
+               << ">"
+               ;
+       return os;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// IO
+///////////////////////////////////////////////////////////////////////////////
+struct IO
+{
+       Scene scene;
+       std::vector<Material> materials;
+       std::vector<Object> objects;
+
+       bool read(binary::IReader &reader);
+       bool write(std::ostream &os);
+};
+
+} // namespace mqo
+} // namespace meshio
+
+#endif // MESH_IO_MQO_H_INCLUDED
diff --git a/include/pmd.h b/include/pmd.h
new file mode 100644 (file)
index 0000000..f2c9912
--- /dev/null
@@ -0,0 +1,386 @@
+/**
+ * PMD\8c`\8e®
+ * MMD\82Ì\83\82\83f\83\8b\83f\81[\83^\81B\83o\83C\83i\83\8a\8c`\8e®\82Å\82Ð\82Æ\82Â\82Ì\92¸\93_\82ª\8dÅ\91å\82Q\82Â\82Ü\82Å\82Ì\83{\81[\83\93\82Ì
+ * \83E\83F\83C\83g\82ð\95Û\8e\9d\82·\82é\92P\88ê\82Ì\92¸\93_\94z\97ñ\82Æ\92¸\93_\83C\83\93\83f\83b\83N\83X\94z\97ñ\82ð\82à\82Â\81B\96Ê\82Í
+ * \8eO\8ap\8c`\82Ì\82Ý\81B
+ * \82Ü\82½\95\\8fî\83\82\81[\83t\83B\83\93\83O\8fî\95ñ\81A\95¨\97\9d\89\89\8eZ\8cü\82¯\82Ì\8d\84\91Ì\8fî\95ñ\82Æ\8dS\91©\8fî\95ñ\82È\82Ç\82ð\82à\82Â\81B
+ *
+ * \8dÀ\95W\8cn
+ * \8d\8eè Y-UP
+ *
+ * \95\
+ * clock wise ?
+ *
+ * UV\8c´\93_
+ * left top ?
+ *
+ * \96@\90ü
+ * \92¸\93_\96@\90ü\82ª\8ai\94[\8dÏ\82Ý\81B
+ *
+ * \83\81\83b\83V\83\85
+ * \8dÅ\91å\92¸\93_\90\94
+ * \8dÅ\91å\8eO\8ap\8c`\90\94
+ *
+ * \97 \96Ê\82Ì\88µ\82¢
+ * \83I\83\8a\83W\83i\83\8b\82Å\82Í\83o\83b\83N\83J\83\8a\83\93\83O\82ð\82µ\82Ä\82¢\82È\82¢\82Ì\82Å\82â\82é\8fê\8d\87\82Í\83\82\83f\83\8b\8cÂ\95Ê\82É
+ * \91Î\89\9e\82ª\95K\97v\81B
+ *
+ * \8eQ\8dl\83T\83C\83g
+ * http://blog.goo.ne.jp/torisu_tetosuki/e/209ad341d3ece2b1b4df24abf619d6e4
+ */
+
+#ifndef MESH_IO_PMD_H_INCLUDED
+#define MESH_IO_PMD_H_INCLUDED 
+
+#include <ostream>
+#include <vector>
+#include "la.h"
+#include "text.h"
+
+namespace meshio {
+namespace pmd {
+
+typedef la::Vector2 Vector2;
+typedef la::Vector3 Vector3;
+typedef la::Vector4 Vector4;
+typedef color::fRGBA fRGBA;
+typedef color::fRGB fRGB;
+
+////////////////////////////////////////////////////////////
+//! \92¸\93_
+////////////////////////////////////////////////////////////
+struct Vertex
+{
+       //! \8dÀ\95W
+       Vector3 pos;
+       //! \96@\90ü\83x\83N\83g\83\8b
+       Vector3 normal;
+       //! \83e\83N\83X\83`\83\83UV
+       Vector2 uv;
+       //! \83u\83\8c\83\93\83f\83B\83\93\83O\83{\81[\83\931
+       unsigned short bone0;
+       //! \83u\83\8c\83\93\83f\83B\83\93\83O\83{\81[\83\932
+       unsigned short bone1;
+       //! \83E\83F\83C\83g[0 - 100]
+       unsigned char weight0;
+       //! \94ñ\83G\83b\83W
+       unsigned char edge_flag;
+};
+inline std::ostream &operator<<(std::ostream &os, const Vertex &rhs)
+{
+       os
+               << "[Vertex"
+               << " pos:" << rhs.pos
+               << " normal:" << rhs.normal
+               << " uv:" << rhs.uv
+               << " bone0:" << rhs.bone0
+               << " bone1:" << rhs.bone1
+               << " weight0:" << (int)rhs.weight0
+               << " edge_flag:" << (int)rhs.edge_flag
+               << "]"
+               ;
+       return os;
+}
+
+////////////////////////////////////////////////////////////
+//! \8dÞ\8e¿
+////////////////////////////////////////////////////////////
+struct Material
+{
+       //! Diffuse
+       fRGBA diffuse;
+       //! Shinness
+       float shinness;
+       //! Specular
+       fRGB specular;
+       //! Ambient
+       fRGB ambient;
+       //! \83g\83D\81[\83\93\83e\83N\83X\83`\83\83
+       unsigned char toon_index;
+       //! \97Ö\8as/\89e
+       unsigned char flag;
+       //! \96Ê\92¸\93_\90\94
+       unsigned int vertex_count;
+       //! \83e\83N\83X\83`\83\83
+       char texture[20];
+};
+inline std::ostream &operator<<(std::ostream &os,
+               const Material &rhs)
+{
+       os
+               << "[Material"
+               << " diffuse:" << rhs.diffuse
+               << " toon_index:" << (int)rhs.toon_index
+               << " flag:" << (int)rhs.flag
+               << " vertex_count:" << rhs.vertex_count
+               << " texture:" << rhs.texture
+               << "]"
+               ;
+       return os;
+}
+
+////////////////////////////////////////////////////////////
+//! \83{\81[\83\93 
+////////////////////////////////////////////////////////////
+//! \83{\81[\83\93\82Ì\8eí\97Þ
+enum BONE_TYPE
+{
+       // \89ñ\93]
+       BONE_ROTATE=0,
+       // \89ñ\93]\82Æ\88Ú\93®
+       BONE_ROTATE_MOVE,
+       // IK
+       BONE_IK,
+       // \95s\96¾
+       BONE_UNKNOWN,
+       // IK\89e\8b¿\89º
+       BONE_IK_INFLUENCED,
+       // \89ñ\93]\89e\8b¿\89º
+       BONE_ROTATE_INFLUENCED,
+       // IK\90Ú\91±\90æ
+       BONE_IK_CONNECT,
+       // \94ñ\95\\8e¦
+       BONE_INVISIBLE,
+       // \94P\82è
+       BONE_TWIST,
+       // \89ñ\93]\98A\93®
+       BONE_REVOLVE,
+};
+struct Bone
+{
+       //! \96¼\91O
+       char name[20];
+       //! \90e\83{\81[\83\93
+       unsigned short parent_index;
+       //! \8eq\83{\81[\83\93
+       unsigned short tail_index;
+       //! \83{\81[\83\93\8eí\97Þ
+       BONE_TYPE type;
+       //! \89e\8b¿IK\83{\81[\83\93
+       unsigned short ik_index;
+       // \83{\81[\83\93\8dÀ\95W
+       Vector3 pos;
+};
+inline std::ostream &operator<<(std::ostream &os,
+               const Bone &rhs)
+{
+       os
+               << "[Bone "
+               << '"' << rhs.name << '"'
+               << "]"
+               ;
+       return os;
+}
+
+////////////////////////////////////////////////////////////
+//! IK
+////////////////////////////////////////////////////////////
+struct IK
+{
+       //! IK(IK\83^\81[\83Q\83b\83g)
+       unsigned short index;
+       //! Target(\83G\83t\83F\83N\83^\81[)
+       unsigned short target;
+       //! \83G\83t\83F\83N\83^\82É\98A\93®\82·\82é\83{\81[\83\93\90\94
+       unsigned char length;
+       //! IK\92l1\81BCCD-IK\8e\8e\8ds\89ñ\90\94
+       unsigned short iterations;
+       //! IK\92l2\81BCCD-IK\8e\8e\8ds\88ê\89ñ\95Ó\82è\82Ì\89e\8b¿\93x
+       float weight;
+       //! \83G\83t\83F\83N\83^\82É\98A\93®\82·\82é\83{\81[\83\93(\8aî\96{\93I\82É\90e\83{\81[\83\93\82É\91k\82é)
+       std::vector<unsigned short> children;
+};
+inline std::ostream &operator<<(std::ostream &os, const IK &rhs)
+{
+       os
+               << "[IK "
+               << "]"
+               ;
+       return os;
+}
+
+////////////////////////////////////////////////////////////
+//! \95\\8fî
+////////////////////////////////////////////////////////////
+//! \95\\8fî\82Ì\8eí\97Þ
+enum MORPH_TYPE
+{
+       //! \83x\81[\83X\95\\8fî
+       MORPH_BASE=0,
+       //! \82Ü\82ä
+       MORPH_MAYU,
+       //! \96Ú
+       MORPH_ME,
+       //! \83\8a\83b\83v
+       MORPH_LIP,
+       //! \82»\82Ì\91¼
+       MORPH_OTHER,
+};
+struct Morph
+{
+       //! \95\\8fî\96¼
+       char name[20];
+       //! \8eg\97p\82·\82é\92¸\93_\90\94
+       unsigned int vertex_count;
+       //! \95ª\97Þ
+       unsigned char type;
+       //! \92¸\93_Index
+       std::vector<unsigned int> indices;
+       //! \88Ú\93®\97Ê
+       std::vector<Vector3> pos_list;
+};
+inline std::ostream &operator<<(std::ostream &os, const Morph &rhs)
+{
+       os
+               << "[Morph "
+               << '"' << rhs.name << '"'
+               << "]"
+               ;
+       return os;
+}
+
+////////////////////////////////////////////////////////////
+//! \8d\84\91Ì
+////////////////////////////////////////////////////////////
+//! \8c`\8fó
+enum SHAPE_TYPE
+{
+       //! \8b\85
+       SHAPE_SPHERE=0,
+       //! \94 
+       SHAPE_BOX,
+       //! \83J\83v\83Z\83\8b
+       SHAPE_CAPSULE,
+};
+//! \8d\84\91Ì\83^\83C\83v
+enum PROCESS_TYPE
+{
+       //! \83{\81[\83\93\82Æ\93¯\82\93®\82«
+       RIGIDBODY_KINEMATICS=0,
+       //! \95¨\97\9d\89\89\8eZ
+       RIGIDBODY_PHYSICS,
+       //! \95¨\97\9d\89\89\8eZ\8c\8b\89Ê\82ð\83{\81[\83\93\82É\94½\89f\82·\82é
+       RIGIDBODY_PHYSICS_WITH_BONE,
+};
+
+struct RigidBody
+{
+       //! \8d\84\91Ì\96¼
+       char name[20];
+       //! \8aÖ\98A\83{\81[\83\93(\83{\81[\83\93\92Ç\8f]\82Æ\83{\81[\83\93\88Ê\92u\8d\87\82í\82¹\82Å\95K\97v)
+       unsigned short boneIndex;
+       //! \83O\83\8b\81[\83v
+       unsigned char group;
+       //! \94ñ\8fÕ\93Ë\83O\83\8b\81[\83v
+       unsigned short target;
+       //! \8c`\8fó
+       SHAPE_TYPE shapeType;
+       //! \83T\83C\83Y
+       float w;
+       float h;
+       float d;
+       //! \8ep\90¨
+       Vector3 position;
+       Vector3 rotation;
+       //! \8e¿\97Ê
+       float weight;
+       //! \95¨\97\9d\89\89\8eZ\83p\83\89\83\81\81[\83^(bullet)
+       float linearDamping;
+       float angularDamping;
+       float restitution;
+       float friction;
+       //! \8d\84\91Ì\83^\83C\83v
+       PROCESS_TYPE processType;
+};
+
+//! Joint(\95¨\97\9d\89\89\8eZ\82Å\82ÌJoint\82ÆConstraint\82Í\93¯\82\88Ó\96¡)
+struct Constraint
+{
+       //! Joint\96¼
+       char name[20];
+       //! \90Ú\91±\8d\84\91ÌA
+       unsigned int rigidA;
+       //! \90Ú\91±\8d\84\91ÌB
+       unsigned int rigidB;
+       //! \88Ê\92u
+       Vector3 pos;
+       //! \89ñ\93]
+       Vector3 rot;
+       //! \88Ú\93®\90§\8cÀ
+       Vector3 constraintPosMin;
+       Vector3 constraintPosMax;
+       //! \89ñ\93]\90§\8cÀ
+       Vector3 constraintRotMin;
+       Vector3 constraintRotMax;
+       //! \82Î\82Ë
+       Vector3 springPos;
+       Vector3 springRot;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// IO
+///////////////////////////////////////////////////////////////////////////////
+struct IO
+{
+       float version;
+       char name[20];
+       char comment[256];
+       std::vector<Vertex> vertices;
+       std::vector<unsigned short> indices;
+       std::vector<Material> materials;
+       std::vector<Bone> bones;
+       std::vector<IK> ik_list;
+       std::vector<Morph> morph_list;
+       std::vector<std::pair<unsigned short, unsigned char> > bone_list;
+       std::vector<std::string> bone_name_list;
+       std::vector<RigidBody> rigidbodies;
+       std::vector<Constraint> constraints;
+
+       IO();
+       bool read(binary::IReader &reader);
+       bool write(std::ostream &os);
+};
+inline std::ostream &operator<<(std::ostream &os, const IO &rhs)
+{
+       os
+               << "<PMD " << rhs.name << std::endl
+               << rhs.comment << std::endl
+               << "[vertices] " << rhs.vertices.size() << std::endl
+               << "[indices] " << rhs.indices.size() << std::endl
+               << "[materials] " << rhs.materials.size() << std::endl
+               ;
+       /*
+       std::copy(rhs.materials.begin(), rhs.materials.end(), 
+                       std::ostream_iterator<Material>(os, ""));
+
+       os
+               << "[bones] " << rhs.bones.size() << std::endl
+               ;
+       std::copy(rhs.bones.begin(), rhs.bones.end(), 
+                       std::ostream_iterator<Bone>(os, ""));
+
+       os
+               << "[ik] " << rhs.ik_list.size() << std::endl
+               ;
+       std::copy(rhs.ik_list.begin(), rhs.ik_list.end(), 
+                       std::ostream_iterator<IK>(os, ""));
+
+       os
+               << "[morph] " << rhs.morph_list.size() << std::endl
+               ;
+       std::copy(rhs.morph_list.begin(), rhs.morph_list.end(), 
+                       std::ostream_iterator<Morph>(os, ""));
+                       */
+
+       os
+               << ">" << std::endl
+               ;
+       return os;
+}
+
+
+} // namespace pmd
+} // namespace meshio
+
+#endif // MESH_IO_PMD_H_INCLUDED
diff --git a/include/text.h b/include/text.h
new file mode 100644 (file)
index 0000000..2096a7e
--- /dev/null
@@ -0,0 +1,362 @@
+#ifndef MESH_IO_TEXT_H_INCLUDED
+#define MESH_IO_TEXT_H_INCLUDED
+
+#include "binary.h"
+#include "la.h"
+#include "color.h"
+#include <string>
+#include <stdlib.h>
+
+namespace meshio {
+namespace text {
+
+/**
+ * \8eQ\8fÆ\83I\83\93\83\8a\81[\82Ì\8aÈ\88Õ\95\8e\9a\97ñ\83N\83\89\83X
+ */
+class cstr
+{
+       const char *begin_;
+       const char *end_;
+
+public:
+       cstr()
+               : begin_(0), end_(0)
+               {}
+
+       cstr(const char *begin, const char *end)
+               : begin_(begin), end_(end)
+               { }
+
+       bool operator==(const char *rhs)const
+       {
+               const char *l=begin_;
+               for(const char *r=rhs; *r; ++r, ++l){
+                       if(l==end_){
+                               return false;
+                       }
+                       if(*l!=*r){
+                               return false;
+                       }
+               }
+               return l==end_;
+       }
+
+       bool operator!=(const char *rhs)const
+       {
+               return !(*this==rhs);
+       }
+
+       bool include(char c)const
+       {
+               for(const char *l=begin_; l!=end_; ++l){
+                       if(*l==c){
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       bool startswith(const char *rhs)
+       {
+               const char *r=rhs;
+               for(const char *l=begin_; l!=end_ && *r!='\0'; ++l, ++r){
+                       if(*l!=*r){
+                               return false;
+                       }
+               }
+               return true;
+       }
+
+       bool empty()const
+       {
+               return begin_==end_;
+       }
+
+       std::string str()const{ return std::string(begin_, end_); }
+       const char* begin()const{ return begin_; }
+       const char* end()const{ return end_; }
+       std::pair<const char*, const char*> range()const{ 
+               return std::make_pair(begin_, end_); 
+       }
+
+       template<typename IsTrim>
+               cstr &trim(IsTrim isTrim){
+                       while(begin_!=end_ && isTrim(*begin_)){
+                               begin_++;
+                       }
+                       while(end_!=begin_ && isTrim(end_[-1])){
+                               end_--;
+                       }
+                       return *this;
+               }
+};
+inline std::ostream &operator<<(std::ostream &os, const cstr &rhs)
+{
+       return os << rhs.str();
+}
+
+struct IsCRLF
+{
+       bool operator()(char byte)const
+       {
+               switch(byte)
+               {
+               case '\n':
+               case '\r': // fall through
+                       return true;
+
+               default:
+                       return false;
+               }
+       }
+};
+
+struct IsWhiteSpace
+{
+       bool operator()(char byte)const
+       {
+               switch(byte)
+               {
+               case ' ':
+               case '\t': // fall through
+                       return true;
+
+               default:
+                       return false;
+               }
+       }
+};
+
+struct IsEmpty
+{
+       bool operator()(cstr line)const
+       {
+               return line.empty();
+       }
+};
+
+template<class DELIMITER=IsCRLF, 
+       class TRIM=IsSpace,
+       class LINESKIP=IsEmptyLine>
+       class LineReader
+{
+       binary::IReader &reader_;
+       unsigned int lineCount_;
+       std::vector<char> buf_;
+       bool isEnd_;
+
+public:
+       LineReader(binary::IReader &reader)
+               : reader_(reader), lineCount_(0), isEnd_(false)
+               {
+               }
+
+       cstr getLine()
+       {
+               while(!isEnd_){
+                       fill_();
+                       cstr line;
+                       if(!buf_.empty()){
+                               line=trim_();
+                       }
+                       if(LINESKIP()(line)){
+                               continue;
+                       }
+                       ++lineCount_;
+                       return line;
+               }
+               return cstr();
+       }
+
+       unsigned int getLineCount()const
+       {
+               return lineCount_;
+       }
+
+       bool isEnd()const
+       {
+               return isEnd_;
+       }
+
+private:
+       void fill_()
+       {
+               buf_.clear();
+               // skip delimeter
+               while(char byte=reader_.getChar()){
+                       if(DELIMITER()(byte)){
+                               continue;
+                       }
+                       buf_.push_back(byte);
+                       break;
+               }
+               while(char byte=reader_.getChar()){
+                       if(DELIMITER()(byte)){
+                               break;
+                       }
+                       buf_.push_back(byte);
+               }
+               if(buf_.empty()){
+                       isEnd_=true;
+                       return;
+               }
+       }
+       
+       cstr trim_()
+       {
+               if(buf_.empty()){
+                       return cstr();
+               }
+
+               size_t front=0;
+               while(true){
+                       if(front>=buf_.size()){
+                               return cstr();
+                       }
+                       if(!TRIM()(buf_[front])){
+                               break;
+                       }
+                       ++front;
+               }
+
+               size_t back=buf_.size()-1;
+               for(; back>=0; --back){
+                       if(!TRIM()(buf_[back])){
+                               break;
+                       }
+               }
+               assert(front<=back);
+               return cstr(&buf_[0]+front, &buf_[0]+back+1);
+       }
+};
+
+template<class DELIMITER=IsSpace>
+class LineSplitter
+{
+       cstr line_;
+       std::vector<const char*> heads_;
+       std::vector<const char*> tails_;
+       size_t index_;
+
+public:
+       LineSplitter(cstr line)
+               : line_(line), index_(0)
+               {
+                       const char *current=line.begin();
+                       for(; current!=line_.end();){
+                               for(; current!=line_.end(); ++current){
+                                       if(!DELIMITER()(*current)){
+                                               break;
+                                       }
+                               }
+                               if(current==line_.end()){
+                                       break;
+                               }
+                               heads_.push_back(current);
+                               for(; current!=line_.end(); ++current){
+                                       if(DELIMITER()(*current)){
+                                               break;
+                                       }
+                               }
+                               tails_.push_back(current);
+                       }
+               }
+
+       cstr get()
+       {
+               if(index_>=heads_.size()){
+                       return cstr();
+               }
+               const char* head=heads_[index_];
+               const char* tail=tails_[index_];
+               ++index_;
+               return cstr(head, tail);
+       }
+
+       int getInt()
+       {
+               return atoi(get().begin());
+       }
+
+       float getFloat()
+       {
+               return static_cast<float>(atof(get().begin()));
+       }
+
+       la::Vector2 getVector2()
+       {
+               float x=getFloat();
+               float y=getFloat();
+               return la::Vector2(x, y);
+       }
+
+       la::Vector3 getVector3()
+       {
+               float x=getFloat();
+               float y=getFloat();
+               float z=getFloat();
+               return la::Vector3(x, y, z);
+       }
+
+       la::Vector4 getVector4()
+       {
+               float x=getFloat();
+               float y=getFloat();
+               float z=getFloat();
+               float w=getFloat();
+               return la::Vector4(x, y, z, w);
+       }
+
+       color::bRGBA getByteRGBA()
+       {
+               int r=getInt();
+               int g=getInt();
+               int b=getInt();
+               int a=getInt();
+               return color::bRGBA(r, g, b, a);
+       }
+
+       cstr getQuated()
+       {
+               const char *begin=line_.begin();
+               for(; begin!=line_.end(); ++begin){
+                       if(*begin=='"'){
+                               break;
+                       }
+               }
+               begin++;
+               assert(begin<=line_.end());
+
+               const char *c=begin+1;
+               for(; c!=line_.end(); ++c){
+                       if(*c=='"'){
+                               break;
+                       }
+               }
+
+               cstr token=cstr(begin, c);
+               begin=c+1;
+               return token;
+       }
+
+};
+
+inline void copyStringAndFillZero(char *dst, const std::string &src)
+{
+       size_t i=0;
+       for(; i<src.size(); ++i)
+       {
+               dst[i]=src[i];
+               if(src[i]=='\0'){
+                       break;
+               }
+       }
+       for(; i<src.size(); ++i)
+       {
+               dst[i]='\0';
+       }
+}
+
+} // namespace text
+} // namespace meshio
+#endif // MESH_IO_TEXT_H_INCLUDED
diff --git a/include/vmd.h b/include/vmd.h
new file mode 100644 (file)
index 0000000..b8aa069
--- /dev/null
@@ -0,0 +1,184 @@
+/**
+ * VMD\8c`\8e®
+ * MMD\82Ì\83\82\81[\83V\83\87\83\93\83f\81[\83^\81B
+ * \83o\83C\83i\83\8a\8c`\8e®\82Å\83{\81[\83\93\83\82\81[\83V\83\87\83\93\81A\95\\8fî\83\82\81[\83t\83B\83\93\83O\81A\8cõ\8c¹\81A\89e\82Ì\83L\81[\83t\83\8c\81[\83\80\82ª
+ * \8bL\98^\82³\82ê\82é\81B
+ *
+ * \8eQ\8dl\83T\83C\83g
+ * http://blog.goo.ne.jp/torisu_tetosuki/e/bc9f1c4d597341b394bd02b64597499d
+ * http://atupdate.web.fc2.com/vmd_format.htm
+ */
+
+#ifndef MESH_IO_VMD_H_INCLUDED
+#define MESH_IO_VMD_H_INCLUDED 
+
+#include <ostream>
+#include <vector>
+#include <map>
+#include "la.h"
+#include "color.h"
+#include "binary.h"
+
+namespace meshio {
+namespace vmd {
+
+typedef la::Vector2 Vector2;
+typedef la::Vector3 Vector3;
+typedef la::Quaternion Quaternion;
+typedef color::fRGB fRGB;
+
+////////////////////////////////////////////////////////////
+//! \83\82\81[\83V\83\87\83\93
+////////////////////////////////////////////////////////////
+struct BoneKey
+{
+       Vector3 pos;
+       Quaternion q;
+       char interpolationX[16];
+       char interpolationY[16];
+       char interpolationZ[16];
+       char interpolationRot[16];
+};
+inline std::ostream& operator<<(std::ostream &os, const BoneKey &rhs)
+{
+       return os
+               << "<BoneKey: " << rhs.pos << rhs.q << ">" 
+               ;
+}
+
+////////////////////////////////////////////////////////////
+//! \95\\8fî
+////////////////////////////////////////////////////////////
+struct MorphKey
+{
+       float weight;
+};
+inline std::ostream& operator<<(std::ostream &os, const MorphKey &rhs)
+{
+       return os
+               << "<MorphKey: " << rhs.weight << ">" 
+               ;
+}
+
+
+////////////////////////////////////////////////////////////
+//! \83J\83\81\83\89
+////////////////////////////////////////////////////////////
+struct CameraKey
+{
+       //! \89½\82Ì\8b\97\97£\81H
+       float length;
+       //! \88Ê\92u
+       Vector3 pos;
+       //! \83I\83C\83\89\81[\8ap
+       Vector3 euler;
+       //! \95â\8aÔ
+       char interpolation[24];
+       //! \8e\8b\96ì\8ap
+       unsigned short viewAngle;
+       //! \89\93\8bß\8a´ 0\82ªon
+       unsigned char perspective;
+};
+inline std::ostream& operator<<(std::ostream &os, const CameraKey &rhs)
+{
+       return os
+               << "<CameraKey: " << rhs.length 
+               << rhs.pos << rhs.euler << ">" 
+               ;
+}
+
+
+////////////////////////////////////////////////////////////
+//! \8cõ\8c¹
+////////////////////////////////////////////////////////////
+struct LightKey
+{
+       fRGB color;
+       Vector3 pos;
+};
+inline std::ostream& operator<<(std::ostream &os, const LightKey &rhs)
+{
+       return os
+               << "<LightKey: " << rhs.color << rhs.pos << ">" 
+               ;
+}
+
+
+////////////////////////////////////////////////////////////
+//! \83Z\83\8b\83t\83V\83\83\83h\83E
+////////////////////////////////////////////////////////////
+struct SelfShadowKey
+{
+};
+
+////////////////////////////////////////////////////////////
+//! 1\83`\83\83\83\93\83l\83\8b\95ª\82Ì\83L\81[\83t\83\8c\81[\83\80\82Ì\83\8a\83X\83g\81B
+//! \93Ç\82Ý\8d\9e\82ñ\82¾\8cã\82Å\83t\83\8c\81[\83\80\94Ô\8d\86\82Å\83\\81[\83g\82·\82é\81B
+////////////////////////////////////////////////////////////
+template<typename T>
+struct KeyFrameList
+{
+       struct KeyFrame
+       {
+               //! \83t\83\8c\81[\83\80\94Ô\8d\86
+               unsigned int frame;
+               //! \83L\81[
+               T key;
+
+               //! \83t\83\8c\81[\83\80\94Ô\8d\86\82Å\83L\81[\82ð\83\\81[\83g\82·\82é
+               bool operator<(const KeyFrame &rhs)const{ return frame<rhs.frame; }
+       };
+       std::vector<KeyFrame> list;
+       void sort(){ std::sort(list.begin(), list.end()); }
+       KeyFrame& push(unsigned int frame)
+       {
+               list.push_back(KeyFrame());
+               KeyFrame &keyFrame=list.back();
+               keyFrame.frame=frame;
+               return keyFrame;
+       }
+};
+
+////////////////////////////////////////////////////////////
+//! IO
+////////////////////////////////////////////////////////////
+struct IO
+{
+       std::string version;
+       char name[20];
+
+       //! \83\82\81[\83V\83\87\83\93
+       typedef std::map<std::string, KeyFrameList<BoneKey> > BoneMap;
+       BoneMap boneMap;
+       //! \95\\8fî
+       typedef std::map<std::string, KeyFrameList<MorphKey> > MorphMap;
+       MorphMap morphMap;
+       //! \83J\83\81\83\89\83\82\81[\83V\83\87\83\93
+       typedef std::map<std::string, KeyFrameList<CameraKey> > CameraMap;
+       CameraMap cameraKey;
+       //! \8fÆ\96¾
+       typedef std::map<std::string, KeyFrameList<LightKey> > LightMap;
+       LightMap lightMap;
+       //! \83Z\83\8b\83t\83V\83\83\83h\81[
+       typedef std::map<std::string, KeyFrameList<SelfShadowKey> > SelfShadowMap;
+       SelfShadowMap selfShadowMap;
+
+       IO();
+       bool read(binary::IReader &reader);
+       bool write(std::ostream &os);
+};
+inline std::ostream& operator<<(std::ostream &os, const IO &rhs)
+{
+       os
+               << "<VMD " << rhs.name << std::endl
+               << "[bones] " << rhs.boneMap.size() << std::endl
+               << "[morphs] " << rhs.morphMap.size() << std::endl
+               << ">"
+               ;
+       return os;
+}
+
+} // namespace vmd
+} // namespace meshio
+
+#endif // MESH_IO_VMD_H_INCLUDED
diff --git a/premake4.lua b/premake4.lua
new file mode 100644 (file)
index 0000000..081bad2
--- /dev/null
@@ -0,0 +1,42 @@
+-- A solution contains projects, and defines the available configurations
+solution "meshio"
+configurations { "Debug", "Release" }
+
+-- A project defines one build target
+project "meshio"
+--kind "WindowedApp"
+--kind "ConsoleApp"
+--kind "SharedLib"
+kind "StaticLib"
+language "C++"
+files { "include/*.h", "src/**.h", "src/**.cpp" }
+flags {
+       --"Unicode", 
+       "StaticRuntime",
+}
+buildoptions {
+       "/wd4996",
+}
+includedirs {
+       "include", "boost",
+}
+defines {}
+linkoptions {}
+libdirs {}
+links {}
+
+configuration "Debug"
+do
+  defines { "DEBUG" }
+  flags { "Symbols" }
+  targetdir "debug"
+end
+
+configuration "Release"
+do
+  defines { "NDEBUG" }
+  flags { "Optimize" }
+  targetdir "release"
+end
+
+
diff --git a/src/binary.cpp b/src/binary.cpp
new file mode 100644 (file)
index 0000000..7e6ec6c
--- /dev/null
@@ -0,0 +1,92 @@
+#include "binary.h"
+
+namespace meshio {
+namespace binary {
+
+///////////////////////////////////////////////////////////////////////////////
+// FileReader
+///////////////////////////////////////////////////////////////////////////////
+FileReader::FileReader(const char *path)
+: io_(path, std::ios::binary), pos_(0), eof_(false)
+{
+}
+
+FileReader::~FileReader()
+{
+}
+
+unsigned int FileReader::read(char *buf, unsigned int size)
+{
+       if(size==0){
+               return 0;
+       }
+       io_.read(buf, size);
+       size=io_.gcount();
+       if(size==0){
+               eof_=true;
+       }
+       pos_+=size;
+       return size;
+}
+
+unsigned int FileReader::getPos()const
+{
+       return pos_;
+}
+
+bool FileReader::isEnd()const
+{
+       return eof_;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// MemoryReader
+///////////////////////////////////////////////////////////////////////////////
+MemoryReader::MemoryReader(const char *buf, unsigned int size)
+: buf_(buf), size_(size), pos_(0)
+{
+}
+
+MemoryReader::~MemoryReader()
+{
+}
+
+unsigned int MemoryReader::read(char *buf, unsigned int size)
+{
+       if(pos_+size>=size_){
+               size=size_-pos_;
+       }
+       std::copy(&buf_[pos_], &buf_[pos_+size], buf);
+       pos_+=size;
+       return size;
+}
+
+unsigned int MemoryReader::getPos()const
+{
+       return pos_;
+}
+
+bool MemoryReader::isEnd()const
+{
+       return pos_>=size_;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void readAll(const char *path, std::vector<char> &buf)
+{
+       std::ifstream io(path, std::ios::binary);
+       if(!io){
+               return;
+       }
+       io.seekg(0, std::fstream::end);
+       unsigned int eofPos = io.tellg();
+       io.clear();
+       io.seekg(0, std::fstream::beg);
+       unsigned int begPos = io.tellg();
+       unsigned int size = eofPos - begPos;
+       buf.resize(size);
+       io.read(&buf[0], buf.size());
+}
+
+} // namespace binary
+} // namespace meshio
diff --git a/src/mqo.cpp b/src/mqo.cpp
new file mode 100644 (file)
index 0000000..982d47d
--- /dev/null
@@ -0,0 +1,399 @@
+#include "mqo.h"
+#include <iostream>
+#include <fstream>
+#include <vector>
+
+namespace meshio {
+namespace mqo {
+
+//! Tokenizer
+struct DELIMITER
+{
+       bool operator()(char c)
+       {
+               switch(c)
+               {
+               case ' ':
+               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{
+                                       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::bRGBA::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.getByteRGBA();
+                               }
+                               else if(key=="dif"){
+                                       material.diffuse=splitter.getFloat();
+                               }
+                               else if(key=="amb"){
+                                       material.ambient=splitter.getFloat();
+                               }
+                               else if(key=="emi"){
+                                       material.emmit=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::write(std::ostream &os)
+{
+       return false;
+}
+
+
+}
+}
diff --git a/src/pmd.cpp b/src/pmd.cpp
new file mode 100644 (file)
index 0000000..d5e523f
--- /dev/null
@@ -0,0 +1,438 @@
+#include "pmd.h"
+#include <iostream>
+
+namespace meshio {
+namespace pmd {
+
+// 38bytes
+template<class READER>
+       void
+       read(READER &reader, Vertex &v)
+       {
+               unsigned int pos=reader.getPos();
+               reader.get(v.pos);
+               reader.get(v.normal);
+               reader.get(v.uv);
+               reader.get(v.bone0);
+               reader.get(v.bone1);
+               reader.get(v.weight0);
+               reader.get(v.edge_flag);
+               assert(reader.getPos()-pos==38);
+       }
+
+
+// 70bytes
+template<class READER>
+       void
+       read(READER &reader, Material &m)
+       {
+               unsigned int pos=reader.getPos();
+               reader.get(m.diffuse);
+               reader.get(m.shinness);
+               reader.get(m.specular);
+               reader.get(m.ambient);
+               reader.get(m.toon_index);
+               reader.get(m.flag);
+               reader.get(m.vertex_count);
+               text::copyStringAndFillZero(m.texture, reader.getString(20));
+               assert(reader.getPos()-pos==70);
+       }
+
+// 39bytes
+template<class READER>
+       void
+       read(READER &reader, Bone &b)
+       {
+               unsigned int pos=reader.getPos();
+               text::copyStringAndFillZero(b.name, reader.getString(20));
+               reader.get(b.parent_index);
+               reader.get(b.tail_index);
+               b.type=static_cast<BONE_TYPE>(reader.getUchar());
+               reader.get(b.ik_index);
+               reader.get(b.pos);
+               assert(reader.getPos()-pos==39);
+       }
+
+// 11+2xIK_COUNT bytes
+template<class READER>
+       void
+       read(READER &reader, IK &ik)
+       {
+               // 11bytes
+               reader.get(ik.index);
+               reader.get(ik.target);
+               reader.get(ik.length);
+               reader.get(ik.iterations);
+               reader.get(ik.weight);
+               // 2 x length bytes
+               for(unsigned short j=0; j<ik.length; ++j){
+                       ik.children.push_back(reader.getUshort());
+               }
+       }
+
+// 25+12xMORPH_COUNT bytes
+template<class READER>
+       void
+       read(READER &reader, Morph &m)
+       {
+               // 25bytes
+               text::copyStringAndFillZero(m.name, reader.getString(20));
+               reader.get(m.vertex_count);
+               m.type=static_cast<MORPH_TYPE>(reader.getUchar());
+               // 12 x vertex_count bytes
+               for(unsigned short i=0; i<m.vertex_count; ++i){
+                       m.indices.push_back(reader.getUint());
+                       m.pos_list.push_back(Vector3());
+                       reader.get(m.pos_list.back());
+               }
+       }
+
+// 83bytes
+template<class READER>
+       void
+       read(READER &reader, RigidBody &r)
+       {
+               unsigned int pos=reader.getPos();
+               text::copyStringAndFillZero(r.name, reader.getString(20));
+               reader.get(r.boneIndex);
+               reader.get(r.group);
+               reader.get(r.target);
+               r.shapeType=static_cast<SHAPE_TYPE>(reader.getUchar());
+               reader.get(r.w);
+               reader.get(r.h);
+               reader.get(r.d);
+               reader.get(r.position);
+               reader.get(r.rotation);
+               reader.get(r.weight);
+               reader.get(r.linearDamping);
+               reader.get(r.angularDamping);
+               reader.get(r.restitution);
+               reader.get<float>(r.friction);
+               r.processType=static_cast<PROCESS_TYPE>(reader.getUchar());
+               assert(reader.getPos()-pos==83);
+       }
+
+// 124bytes
+template<class READER>
+       void
+       read(READER &reader, Constraint &c)
+       {
+               unsigned int base_pos=reader.getPos();
+               text::copyStringAndFillZero(c.name, reader.getString(20));
+               reader.get(c.rigidA);
+               reader.get(c.rigidB);
+               reader.get(c.pos);
+               reader.get(c.rot);
+               reader.get(c.constraintPosMin);
+               reader.get(c.constraintPosMax);
+               reader.get(c.constraintRotMin);
+               reader.get(c.constraintRotMax);
+               reader.get(c.springPos);
+               reader.get(c.springRot);
+               assert(reader.getPos()-base_pos==124);
+       }
+
+class Impl
+{
+       IO &io_;
+       binary::IReader &reader_;
+
+public:
+       Impl(IO &io, binary::IReader &reader)
+               : io_(io), reader_(reader)
+               {}
+
+       bool parse()
+       {
+               if(!parseHeader()){
+                       return false;
+               }
+               if(!parseVertices()){
+                       return false;
+               }
+               if(!parseIndices()){
+                       return false;
+               }
+               if(!parseMaterials()){
+                       return false;
+               }
+               if(!parseBones()){
+                       return false;
+               }
+               if(!parseIK()){
+                       return false;
+               }
+               if(!parseMorph()){
+                       return false;
+               }
+               if(!parseFaceList()){
+                       return false;
+               }
+               if(!parseBoneNameList()){
+                       return false;
+               }
+               if(!parseBoneList()){
+                       return false;
+               }
+               if(reader_.isEnd()){
+                       return true;
+               }
+
+               ////////////////////////////////////////////////////////////
+               // extended data
+               ////////////////////////////////////////////////////////////
+               // english
+               ////////////////////////////////////////////////////////////
+               if(reader_.getChar()){
+                       if(!parseEnglishName()){
+                               return false;
+                       }
+                       if(!parseEnglishBone()){
+                               return false;
+                       }
+                       if(!parseEnglishMorph()){
+                               return false;
+                       }
+                       if(!parseEnglishBoneList()){
+                               return false;
+                       }
+               }
+               if(reader_.isEnd()){
+                       return true;
+               }
+
+               // toone texture
+               ////////////////////////////////////////////////////////////
+               if(!parseToonTextures()){
+                       return false;
+               }
+               if(reader_.isEnd()){
+                       return true;
+               }
+
+               // physics
+               ////////////////////////////////////////////////////////////
+               if(!parseRigid()){
+                       return false;
+               }
+               if(!parseConstraint()){
+                       return false;
+               }
+
+               // end
+               assert(reader_.isEnd());
+
+               return true;
+       }
+
+private:
+       bool parseConstraint()
+       {
+               unsigned int count=reader_.getUint();
+               for(unsigned int i=0; i<count; ++i){
+                       io_.constraints.push_back(Constraint());
+                       read(reader_, io_.constraints.back());
+               }
+               return true;
+       }
+
+       bool parseRigid()
+       {
+               unsigned int count=reader_.getUint();
+               for(unsigned int i=0; i<count; ++i){
+                       io_.rigidbodies.push_back(RigidBody());
+                       read(reader_, io_.rigidbodies.back());
+               }
+               return true;
+       }
+
+       bool parseToonTextures()
+       {
+               for(size_t i=0; i<10; ++i){
+                       reader_.getString(100);
+               }
+               return true;
+       }
+
+       bool parseEnglishBoneList()
+       {
+               for(size_t i=0; i<io_.bone_name_list.size(); ++i){
+                       std::string english=reader_.getString(50);
+               }
+               return true;
+       }
+
+       bool parseEnglishMorph()
+       {
+               int count=io_.morph_list.size()-1;
+               for(int i=0; i<count; ++i){
+                       std::string english_morph_name=reader_.getString(20);
+               }
+               return true;
+       }
+
+       bool parseEnglishBone()
+       {
+               for(size_t i=0; i<io_.bones.size(); ++i){
+                       std::string english_bone_name=reader_.getString(20);
+               }
+               return true;
+       }
+
+       bool parseEnglishName()
+       {
+               std::string english_mdoel_name=reader_.getString(20);
+               std::string english_comment=reader_.getString(256);
+               return true;
+       }
+
+       bool parseBoneList()
+       {
+               unsigned int count=reader_.getUint();
+               for(unsigned int i=0; i<count; ++i){
+                       unsigned short bone=reader_.getUshort();
+                       unsigned char disp=reader_.getUchar();
+                       io_.bone_list.push_back(std::make_pair(bone, disp));
+               }
+               return true;
+       }
+
+       bool parseBoneNameList()
+       {
+               unsigned int count=reader_.getUchar();
+               for(unsigned int i=0; i<count; ++i){
+                       io_.bone_name_list.push_back(reader_.getString(50));
+               }
+               return true;
+       }
+
+       bool parseFaceList()
+       {
+               unsigned int count=reader_.getUchar();
+               for(unsigned int i=0; i<count; ++i){
+                       reader_.getUshort();
+               }
+               return true;
+       }
+
+       bool parseMorph()
+       {
+               unsigned int count=reader_.getUshort();
+               for(unsigned int i=0; i<count; ++i){
+                       io_.morph_list.push_back(Morph());
+                       read(reader_, io_.morph_list.back());
+               }
+               return true;
+       }
+
+       bool parseIK()
+       {
+               unsigned int count=reader_.getUshort();
+               for(unsigned int i=0; i<count; ++i){
+                       io_.ik_list.push_back(IK());
+                       read(reader_, io_.ik_list.back());
+               }
+               return true;
+       }
+
+       bool parseBones()
+       {
+               unsigned int count=reader_.getUshort();
+               for(unsigned int i=0; i<count; ++i){
+                       io_.bones.push_back(Bone());
+                       read(reader_, io_.bones.back());
+               }
+               return true;
+       }
+
+       bool parseMaterials()
+       {
+               unsigned int count=reader_.getUint();
+               for(unsigned int i=0; i<count; ++i){
+                       io_.materials.push_back(Material());
+                       read(reader_, io_.materials.back());
+               }
+               return true;
+       }
+
+       bool parseIndices()
+       {
+               unsigned int count=reader_.getUint();
+               for(unsigned int i=0; i<count; ++i){
+                       io_.indices.push_back(reader_.getUshort());
+               }
+               return true;
+       }
+
+       bool parseVertices()
+       {
+               unsigned int count=reader_.getUint();
+               for(unsigned int i=0; i<count; ++i){
+                       io_.vertices.push_back(Vertex());
+                       read(reader_, io_.vertices.back());
+               }
+               return true;
+       }
+
+       bool parseHeader()
+       {
+               if(reader_.getString(3)!="Pmd"){
+                       //std::cout << "invalid pmd" << std::endl;
+                       return false;
+               }
+               reader_.get(io_.version);
+               if(io_.version!=1.0){
+                       std::cout << "invalid vesion: " << io_.version <<std::endl;
+                       return false;
+               }
+               text::copyStringAndFillZero(io_.name, reader_.getString(20));
+               text::copyStringAndFillZero(io_.comment, reader_.getString(256));
+
+               return true;
+       }
+
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// IO
+///////////////////////////////////////////////////////////////////////////////
+IO::IO()
+: version(0)
+{}
+
+bool IO::read(binary::IReader &input)
+{
+       Impl impl(*this, input);
+       if(!impl.parse()){
+               return false;
+       }
+
+       ////////////////////////////////////////////////////////////
+       // validation
+       ////////////////////////////////////////////////////////////
+       if(!morph_list.empty()){
+               // validate morph
+               assert(morph_list[0].type==MORPH_BASE);
+               // check base
+               Morph &base=morph_list[0];
+               for(size_t i=0; i<base.vertex_count; ++i){
+                       assert(vertices[base.indices[i]].pos==base.pos_list[i]);
+               }
+               // check each face
+               for(size_t i=1; i<morph_list.size(); ++i){
+                       Morph &m=morph_list[i];
+                       assert(m.type!=MORPH_BASE);
+               }
+       }
+
+       return true;
+}
+
+bool IO::write(std::ostream &os)
+{
+       return false;
+}
+
+} // namespace
+} // namespace
+
diff --git a/src/vmd.cpp b/src/vmd.cpp
new file mode 100644 (file)
index 0000000..1d494ba
--- /dev/null
@@ -0,0 +1,160 @@
+#include "vmd.h"
+#include "text.h"
+#include <algorithm>
+#include <string>
+
+namespace meshio {
+namespace vmd {
+
+template<typename T>
+struct SortKeyFrameList
+{
+       typedef T MAP;
+       void operator()(typename MAP::value_type &channel)
+       {
+               channel.second.sort();
+       }
+};
+
+template<class READER>
+       void
+       read(READER &reader, IO::BoneMap &channels)
+       {
+               std::string name=reader.getString(15);
+               unsigned int frame=reader.getUint();
+               IO::BoneMap::iterator found=channels.find(name);
+               if(found==channels.end()){
+                       // not found
+                       found=channels.insert(
+                                               std::make_pair(name, KeyFrameList<BoneKey>())).first;
+               }
+               BoneKey &key=found->second.push(frame).key;
+
+               reader.get(key.pos);
+               reader.get(key.q);
+               reader.get(key.interpolationX);
+               reader.get(key.interpolationY);
+               reader.get(key.interpolationZ);
+               reader.get(key.interpolationRot);
+       }
+
+template<class READER>
+       void
+       read(READER &reader, IO::MorphMap &channels)
+       {
+               std::string name=reader.getString(15);
+               unsigned int frame=reader.getUint();
+               IO::MorphMap::iterator found=channels.find(name);
+               if(found==channels.end()){
+                       // not found
+                       found=channels.insert(
+                                       std::make_pair(name, KeyFrameList<MorphKey>())).first;
+               }
+               MorphKey &key=found->second.push(frame).key;
+
+               reader.get(key.weight);
+       }
+
+class Implementation
+{
+       IO &io_;
+       binary::IReader &reader_;
+
+public:
+       Implementation(IO &io, binary::IReader &reader)
+               : io_(io), reader_(reader)
+               {}
+
+       bool parse()
+       {
+               // check header
+               std::string line=reader_.getString(30, true);
+               if(line=="Vocaloid Motion Data file"){
+                       io_.version="1";
+                       text::copyStringAndFillZero(io_.name, reader_.getString(10));
+                       return parseBody();
+               }
+               else if(line=="Vocaloid Motion Data 0002"){
+                       io_.version="2";
+                       text::copyStringAndFillZero(io_.name, reader_.getString(20));
+                       return parseBody();
+               }
+               else{
+                       //std::cout << "unknown header:" << line << std::endl;
+                       return false;
+               }
+       }
+
+
+private:
+       bool parseBody()
+       {
+               if(!parseFrame()){
+                       return false;
+               }
+               if(!parseMorph()){
+                       return false;
+               }
+               if(!parseCamera()){
+                       return false;
+               }
+               if(!parseLight()){
+                       return false;
+               }
+               // sort
+               std::for_each(io_.boneMap.begin(), io_.boneMap.end(), 
+                               SortKeyFrameList<IO::BoneMap>());
+               std::for_each(io_.morphMap.begin(), io_.morphMap.end(), 
+                               SortKeyFrameList<IO::MorphMap>());
+               return true;
+       }
+
+       bool parseMorph()
+       {
+               unsigned int count=reader_.getUint();
+               for(unsigned int i=0; i<count; ++i){
+                       read(reader_, io_.morphMap);
+               }
+               return true;
+       }
+
+       bool parseFrame()
+       {
+               unsigned int count=reader_.getUint();
+               for(unsigned int i=0; i<count; ++i){
+                       read(reader_, io_.boneMap);
+               }
+               return true;
+       }
+
+       bool parseCamera()
+       {
+               return true;
+       }
+
+       bool parseLight()
+       {
+               return true;
+       }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+//! IO
+///////////////////////////////////////////////////////////////////////////////
+IO::IO()
+{
+}
+
+bool IO::read(binary::IReader &reader)
+{
+       return Implementation(*this, reader).parse();
+}
+
+bool IO::write(std::ostream &os)
+{
+       return false;
+}
+
+} // namespace vmd
+} // namespace meshio
diff --git a/test/cube.mqo b/test/cube.mqo
new file mode 100644 (file)
index 0000000..7affc0c
--- /dev/null
@@ -0,0 +1,44 @@
+Metasequoia Document\r
+Format Text Ver 1.0\r
+\r
+Scene {\r
+       pos 0.0000 0.0000 1500.0000\r
+       lookat 0.0000 0.0000 0.0000\r
+       head -0.5236\r
+       pich 0.5236\r
+       ortho 0\r
+       zoom2 5.0000\r
+       amb 0.250 0.250 0.250\r
+}\r
+Object "obj1" {\r
+       depth 0\r
+       folding 0\r
+       scale 1.000000 1.000000 1.000000\r
+       rotation 0.000000 0.000000 0.000000\r
+       translation 0.000000 0.000000 0.000000\r
+       visible 15\r
+       locking 0\r
+       shading 1\r
+       facet 59.5\r
+       color 0.898 0.400 0.137\r
+       color_type 0\r
+       vertex 8 {\r
+               -100.0000 100.0000 100.0000\r
+               -100.0000 -100.0000 100.0000\r
+               100.0000 100.0000 100.0000\r
+               100.0000 -100.0000 100.0000\r
+               100.0000 100.0000 -100.0000\r
+               100.0000 -100.0000 -100.0000\r
+               -100.0000 100.0000 -100.0000\r
+               -100.0000 -100.0000 -100.0000\r
+       }\r
+       face 6 {\r
+               4 V(0 2 3 1) UV(0.00000 0.00000 1.00000 0.00000 1.00000 1.00000 0.00000 1.00000)\r
+               4 V(2 4 5 3) UV(0.00000 0.00000 1.00000 0.00000 1.00000 1.00000 0.00000 1.00000)\r
+               4 V(4 6 7 5) UV(0.00000 0.00000 1.00000 0.00000 1.00000 1.00000 0.00000 1.00000)\r
+               4 V(6 0 1 7) UV(0.00000 0.00000 1.00000 0.00000 1.00000 1.00000 0.00000 1.00000)\r
+               4 V(6 4 2 0) UV(0.00000 0.00000 1.00000 0.00000 1.00000 1.00000 0.00000 1.00000)\r
+               4 V(1 3 5 7) UV(0.00000 0.00000 1.00000 0.00000 1.00000 1.00000 0.00000 1.00000)\r
+       }\r
+}\r
+Eof\r
diff --git a/test/main.cpp b/test/main.cpp
new file mode 100644 (file)
index 0000000..b4e6fef
--- /dev/null
@@ -0,0 +1,116 @@
+#include <gtest/gtest.h> 
+#include <fstream>
+#include <sstream>
+
+#include <meshio.h>
+using namespace meshio;
+
+TEST(binary, FileReader)
+{
+       binary::FileReader reader("cube.mqo");
+
+       char buf[1024];
+       while(reader.read(buf, 1024)){
+       }
+       EXPECT_EQ(1235, reader.getPos());
+}
+
+TEST(binary, MemoryReader)
+{
+       std::vector<char> all;
+       binary::readAll("cube.mqo", all);
+       binary::MemoryReader reader(&all[0], all.size());
+       char buf[1024];
+       while(reader.read(buf, 1024)){
+       }
+       EXPECT_EQ(1235, reader.getPos());
+}
+
+TEST(text, LineReader)
+{
+       binary::FileReader reader("cube.mqo");
+       text::LineReader<
+               text::IsCRLF, 
+               text::IsWhiteSpace, 
+               text::IsEmpty> l(reader);
+       EXPECT_EQ("Metasequoia Document", l.getLine().str());
+       EXPECT_EQ("Format Text Ver 1.0", l.getLine().str());
+
+       {
+               text::cstr line=l.getLine();
+               text::LineSplitter<text::IsWhiteSpace> splitter(line);
+               EXPECT_EQ("Scene", splitter.get().str());
+       }
+
+       {
+               text::cstr line=l.getLine();
+               text::LineSplitter<text::IsWhiteSpace> splitter(line);
+               EXPECT_EQ("pos", splitter.get().str());
+               EXPECT_EQ(0.0000f, splitter.getFloat());
+               EXPECT_EQ(0.0000f, splitter.getFloat());
+               EXPECT_EQ(1500.0000f, splitter.getFloat());
+       }
+  
+       while(true)
+       {
+               text::cstr line=l.getLine();
+               if(l.isEnd()){
+                       break;
+               }
+               //std::cout << l.getLineCount() << ',' << line << std::endl;
+       }
+       EXPECT_EQ(43, l.getLineCount());
+}
+
+TEST(mqo, read) 
+{ 
+       //binary::FileReader reader("cube.mqo");
+       std::vector<char> all;
+       binary::readAll("cube.mqo", all);
+       binary::MemoryReader reader(&all[0], all.size());
+
+       mqo::IO io;
+       EXPECT_TRUE(io.read(reader));
+       EXPECT_EQ(1, io.objects.size());
+       EXPECT_EQ(8, io.objects[0].vertices.size());
+       EXPECT_EQ(6, io.objects[0].faces.size());
+}
+
+TEST(pmd, read) 
+{ 
+       std::locale::global(std::locale("japanese"));
+       std::vector<char> all;
+       binary::readAll("\8f\89\89¹\83~\83NVer2.pmd", all);
+       binary::MemoryReader reader(&all[0], all.size());
+
+       pmd::IO io;
+       EXPECT_TRUE(io.read(reader));
+       //std::cout << io << std::endl;
+       EXPECT_STREQ("\8f\89\89¹\83~\83N", io.name);
+       EXPECT_EQ(17, io.materials.size());
+       EXPECT_EQ(12354, io.vertices.size());
+       EXPECT_EQ(68883, io.indices.size());
+       EXPECT_EQ(45, io.rigidbodies.size());
+       EXPECT_EQ(27, io.constraints.size());
+}
+
+TEST(vmd, read)
+{
+       std::locale::global(std::locale("japanese"));
+       std::vector<char> all;
+       binary::readAll("mikumiku.vmd", all);
+       binary::MemoryReader reader(&all[0], all.size());
+
+       vmd::IO io;
+       EXPECT_TRUE(io.read(reader));
+       //std::cout << io << std::endl;
+       EXPECT_EQ(122, io.boneMap.size());
+       EXPECT_EQ(16, io.morphMap.size());
+}
+
+int main(int argc, char **argv)
+{
+       testing::InitGoogleTest(&argc, argv); 
+       RUN_ALL_TESTS();
+}
+
diff --git a/test/premake4.lua b/test/premake4.lua
new file mode 100644 (file)
index 0000000..a7644cf
--- /dev/null
@@ -0,0 +1,62 @@
+-- A solution contains projects, and defines the available configurations
+solution "meshio_test"
+configurations { "Debug", "Release" }
+
+-- A project defines one build target
+project "meshio_test"
+--kind "WindowedApp"
+kind "ConsoleApp"
+--kind "SharedLib"
+--kind "StaticLib"
+language "C++"
+files { "**.h", "**.cpp" }
+flags {
+       --"Unicode", 
+       "StaticRuntime",
+}
+buildoptions {
+       "/wd4996",
+}
+includedirs {
+       "../include",
+       "T:/vc/gtest-1.5.0/include",
+}
+defines {}
+linkoptions {}
+libdirs {}
+links {
+       "meshio",
+}
+
+configuration "Debug"
+do
+       defines { "DEBUG" }
+       flags { "Symbols" }
+       targetdir "debug"
+       linkoptions {
+               --"/NODEFAULTLIB:msvcprtd.lib",
+               --"/NODEFAULTLIB:libcmtd.lib",
+       }
+       libdirs {
+               "../Debug",
+               "T:/vc/gtest-1.5.0/msvc/gtest/Debug",
+       }
+       links {
+               "gtestd",
+       }
+end
+
+configuration "Release"
+do
+       defines { "NDEBUG" }
+       flags { "Optimize" }
+       targetdir "release"
+       libdirs {
+               "../Release",
+               "T:/vc/gtest-1.5.0/msvc/gtest/Release",
+       }
+       links {
+               "gtest",
+       }
+end
+