OSDN Git Service

add setup.py
authorousttrue <ousttrue@gmail.com>
Tue, 17 May 2011 21:08:55 +0000 (06:08 +0900)
committerousttrue <ousttrue@gmail.com>
Tue, 17 May 2011 21:08:55 +0000 (06:08 +0900)
22 files changed:
.gitignore [new file with mode: 0644]
README.txt
blender25-meshio/__init__.py [moved from meshio/__init__.py with 100% similarity, mode: 0644]
blender25-meshio/__init__.pyc [new file with mode: 0755]
blender25-meshio/bl25.py [moved from meshio/bl25.py with 100% similarity, mode: 0644]
blender25-meshio/export_mqo.py [moved from meshio/export_mqo.py with 100% similarity, mode: 0644]
blender25-meshio/export_pmd.py [moved from meshio/export_pmd.py with 100% similarity, mode: 0644]
blender25-meshio/import_mqo.py [moved from meshio/import_mqo.py with 100% similarity, mode: 0644]
blender25-meshio/import_pmd.py [moved from meshio/import_pmd.py with 100% similarity, mode: 0644]
blender25-meshio/pymeshio/__init__.py [moved from meshio/pymeshio/__init__.py with 100% similarity, mode: 0644]
blender25-meshio/pymeshio/englishmap.py [moved from meshio/pymeshio/englishmap.py with 100% similarity, mode: 0644]
blender25-meshio/pymeshio/mmd.py [new file with mode: 0644]
blender25-meshio/pymeshio/mqo.py [moved from meshio/pymeshio/mqo.py with 95% similarity, mode: 0644]
blender25-meshio/pymeshio/pmd.py [moved from meshio/pymeshio/mmd.py with 57% similarity, mode: 0644]
blender25-meshio/pymeshio/vmd.py [new file with mode: 0644]
blender25-meshio/pymeshio/vpd.py [new file with mode: 0644]
setup.cfg [new file with mode: 0644]
setup.py [new file with mode: 0644]
test/mqo_test.py [new file with mode: 0644]
test/mqo_test.pyc [new file with mode: 0755]
test/pmd_test.py [new file with mode: 0644]
test/pmd_test.pyc [new file with mode: 0755]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..cfe6115
--- /dev/null
@@ -0,0 +1,4 @@
+Makefile
+build
+dist
+pymeshio.egg-info
index afded69..3e5b8c2 100644 (file)
@@ -19,9 +19,10 @@ Import-Exportの中から"meshio. (.pmd)(.mqo)"を探して右のチェックボ
 更新履歴
 ========
 
-20101229 1.05
+20110518 1.10
 -------------
-blender2.55向け修正。
+setup.pyとtest導入。
+python2と3両用に改造。
 
 20110429 1.06
 -------------
@@ -29,3 +30,7 @@ MeshIOからリポジトリを分離。
 blender2.57b向け修正。
 blender2.49サポートを終了。
 
+20101229 1.05
+-------------
+blender2.55向け修正。
+
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from meshio/__init__.py
rename to blender25-meshio/__init__.py
diff --git a/blender25-meshio/__init__.pyc b/blender25-meshio/__init__.pyc
new file mode 100755 (executable)
index 0000000..24c4690
Binary files /dev/null and b/blender25-meshio/__init__.pyc differ
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from meshio/bl25.py
rename to blender25-meshio/bl25.py
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from meshio/export_mqo.py
rename to blender25-meshio/export_mqo.py
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from meshio/export_pmd.py
rename to blender25-meshio/export_pmd.py
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from meshio/import_mqo.py
rename to blender25-meshio/import_mqo.py
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from meshio/import_pmd.py
rename to blender25-meshio/import_pmd.py
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from meshio/pymeshio/__init__.py
rename to blender25-meshio/pymeshio/__init__.py
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from meshio/pymeshio/englishmap.py
rename to blender25-meshio/pymeshio/englishmap.py
diff --git a/blender25-meshio/pymeshio/mmd.py b/blender25-meshio/pymeshio/mmd.py
new file mode 100644 (file)
index 0000000..5a1614a
--- /dev/null
@@ -0,0 +1,333 @@
+#!/usr/bin/python
+# coding: utf-8
+"""
+20091202: VPD読み込みを追加
+20100318: PMD書き込みを追加
+20100731: meshioと互換になるように改造
+
+VMDの読み込み
+http://yumin3123.at.webry.info/200810/article_4.html
+http://atupdate.web.fc2.com/vmd_format.htm
+
+PMDの読み込み
+http://blog.goo.ne.jp/torisu_tetosuki/e/209ad341d3ece2b1b4df24abf619d6e4
+
+VPDの読み込み
+
+ToDo:
+    rigdid bodies
+    constraints
+"""
+import sys
+import codecs
+import os.path
+import struct
+import math
+import re
+#import numpy
+from decimal import *
+
+ENCODING='cp932'
+
+if sys.version_info[0]>=3:
+    xrange=range
+
+###############################################################################
+# utility
+###############################################################################
+def truncate_zero(src):
+    """
+    0x00以降を捨てる
+    """
+    pos = src.find(b"\x00")
+    assert(type(src)==bytes)
+    if pos >= 0:
+        return src[:pos]
+    else:
+        return src
+
+def radian_to_degree(x):
+    return x/math.pi * 180.0
+
+
+###############################################################################
+# geometry
+###############################################################################
+class Vector2(object):
+    __slots__=['x', 'y']
+    def __init__(self, x=0, y=0):
+        self.x=x
+        self.y=y
+
+    def __str__(self):
+        return "<%f %f>" % (self.x, self.y)
+
+    def __getitem__(self, key):
+        if key==0:
+            return self.x
+        elif key==1:
+            return self.y
+        else:
+            assert(False)
+
+    def to_tuple(self):
+        return (self.x, self.y)
+
+
+class Vector3(object):
+    __slots__=['x', 'y', 'z']
+    def __init__(self, x=0, y=0, z=0):
+        self.x=x
+        self.y=y
+        self.z=z
+
+    def __str__(self):
+        return "<%f %f %f>" % (self.x, self.y, self.z)
+
+    def __getitem__(self, key):
+        if key==0:
+            return self.x
+        elif key==1:
+            return self.y
+        elif key==2:
+            return self.z
+        else:
+            assert(False)
+
+    def to_tuple(self):
+        return (self.x, self.y, self.z)
+
+class Quaternion(object):
+    __slots__=['x', 'y', 'z', 'w']
+    def __init__(self, x=0, y=0, z=0, w=1):
+        self.x=x
+        self.y=y
+        self.z=z
+        self.w=w
+
+    def __str__(self):
+        return "<%f %f %f %f>" % (self.x, self.y, self.z, self.w)
+
+    def __mul__(self, rhs):
+        u=numpy.array([self.x, self.y, self.z], 'f')
+        v=numpy.array([rhs.x, rhs.y, rhs.z], 'f')
+        xyz=self.w*v+rhs.w*u+numpy.cross(u, v)
+        q=Quaternion(xyz[0], xyz[1], xyz[2], self.w*rhs.w-numpy.dot(u, v))
+        return q
+
+    def dot(self, rhs):
+        return self.x*rhs.x+self.y*rhs.y+self.z*rhs.z+self.w*rhs.w
+
+    def getMatrix(self):
+        sqX=self.x*self.x
+        sqY=self.y*self.y
+        sqZ=self.z*self.z
+        xy=self.x*self.y
+        xz=self.x*self.z
+        yz=self.y*self.z
+        wx=self.w*self.x
+        wy=self.w*self.y
+        wz=self.w*self.z
+        return numpy.array([
+                # 1
+                [1-2*sqY-2*sqZ, 2*xy+2*wz, 2*xz-2*wy, 0],
+                # 2
+                [2*xy-2*wz, 1-2*sqX-2*sqZ, 2*yz+2*wx, 0],
+                # 3
+                [2*xz+2*wy, 2*yz-2*wx, 1-2*sqX-2*sqY, 0],
+                # 4
+                [0, 0, 0, 1]],
+                'f')
+
+    def getRHMatrix(self):
+        x=-self.x
+        y=-self.y
+        z=self.z
+        w=self.w
+        sqX=x*x
+        sqY=y*y
+        sqZ=z*z
+        xy=x*y
+        xz=x*z
+        yz=y*z
+        wx=w*x
+        wy=w*y
+        wz=w*z
+        return numpy.array([
+                # 1
+                [1-2*sqY-2*sqZ, 2*xy+2*wz, 2*xz-2*wy, 0],
+                # 2
+                [2*xy-2*wz, 1-2*sqX-2*sqZ, 2*yz+2*wx, 0],
+                # 3
+                [2*xz+2*wy, 2*yz-2*wx, 1-2*sqX-2*sqY, 0],
+                # 4
+                [0, 0, 0, 1]],
+                'f')
+
+    def getRollPitchYaw(self):
+        m=self.getMatrix()
+
+        roll = math.atan2(m[0, 1], m[1, 1])
+        pitch = math.asin(-m[2, 1])
+        yaw = math.atan2(m[2, 0], m[2, 2])
+
+        if math.fabs(math.cos(pitch)) < 1.0e-6:
+            roll += m[0, 1] > math.pi if 0.0 else -math.pi
+            yaw += m[2, 0] > math.pi if 0.0 else -math.pi
+
+        return roll, pitch, yaw
+
+    def getSqNorm(self):
+        return self.x*self.x+self.y*self.y+self.z*self.z+self.w*self.w
+
+    def getNormalized(self):
+        f=1.0/self.getSqNorm()
+        q=Quaternion(self.x*f, self.y*f, self.z*f, self.w*f)
+        return q
+
+    def getRightHanded(self):
+        "swap y and z axis"
+        return Quaternion(-self.x, -self.z, -self.y, self.w)
+
+    @staticmethod
+    def createFromAxisAngle(axis, rad):
+        q=Quaternion()
+        half_rad=rad/2.0
+        c=math.cos(half_rad)
+        s=math.sin(half_rad)
+        return Quaternion(axis[0]*s, axis[1]*s, axis[2]*s, c)
+
+
+class RGBA(object):
+    __slots__=['r', 'g', 'b', 'a']
+    def __init__(self, r=0, g=0, b=0, a=1):
+        self.r=r
+        self.g=g
+        self.b=b
+        self.a=a
+
+    def __getitem__(self, key):
+        if key==0:
+            return self.r
+        elif key==1:
+            return self.g
+        elif key==2:
+            return self.b
+        elif key==3:
+            return self.a
+        else:
+            assert(False)
+
+
+
+
+###############################################################################
+# interface
+###############################################################################
+def load_pmd(path):
+    size=os.path.getsize(path)
+    f=open(path, "rb")
+    l=PMDLoader()
+    if l.load(path, f, size):
+        return l
+
+def load_vmd(path):
+    size=os.path.getsize(path)
+    f=open(path, "rb")
+    l=VMDLoader()
+    if l.load(path, f, size):
+        return l
+
+def load_vpd(path):
+    f=open(path, 'rb')
+    if not f:
+        return;
+    size=os.path.getsize(path)
+    l=VPDLoader()
+    if l.load(path, f, size):
+        return l
+
+
+###############################################################################
+# debug
+###############################################################################
+def debug_pmd(path):
+    l=load_pmd(path)
+    if not l:
+        print("fail to load")
+        sys.exit()
+
+    print(unicode(l).encode(ENCODING))
+    print(l.comment.encode(ENCODING))
+    print("<ボーン>".decode('utf-8').encode(ENCODING))
+    for bone in l.no_parent_bones:
+        print(bone.name.encode(ENCODING))
+        bone.display()
+    #for bone in l.bones:
+    #    uni="%s:%s" % (bone.english_name, bone.name)
+    #    print uni.encode(ENCODING)
+    #for skin in l.morph_list:
+    #    uni="%s:%s" % (skin.english_name, skin.name)
+    #    print uni.encode(ENCODING)
+    #for i, v in enumerate(l.vertices):
+    #    print i, v
+    #for i, f in enumerate(l.indices):
+    #    print i, f
+    for m in l.materials:
+        print(m)
+
+def debug_pmd_write(path, out):
+    l=load_pmd(path)
+    if not l:
+        print("fail to load")
+        sys.exit()
+
+    if not l.write(out):
+        print("fail to write")
+        sys.exit()
+
+def debug_vmd(path):
+    l=load_vmd(path)
+    if not l:
+        print("fail to load")
+        sys.exit()
+    print(unicode(l).encode(ENCODING))
+
+    #for m in l.motions[u'センター']:
+    #    print m.frame, m.pos
+    for n, m in l.shapes.items():
+        print(unicode(n).encode(ENCODING), getEnglishSkinName(n))
+
+def debug_vpd(path):
+    l=load_vpd(path)
+    if not l:
+        print("fail to load")
+        sys.exit()
+    for bone in l.pose:
+        print(unicode(bone).encode(ENCODING))
+
+if __name__=="__main__":
+    if len(sys.argv)<2:
+        print("usage: %s {pmd file}" % sys.argv[0])
+        print("usage: %s {vmd file}" % sys.argv[0])
+        print("usage: %s {vpd file}" % sys.argv[0])
+        print("usage: %s {pmd file} {export pmdfile}" % sys.argv[0])
+        sys.exit()
+
+    path=sys.argv[1]
+    if not os.path.exists(path):
+        print("no such file: %s" % path)
+
+    if path.lower().endswith('.pmd'):
+        if len(sys.argv)==2:
+            debug_pmd(path)
+        else:
+            debug_pmd_write(path, sys.argv[2])
+    elif path.lower().endswith('.vmd'):
+        debug_vmd(path)
+    elif path.lower().endswith('.vpd'):
+        debug_vpd(path)
+    else:
+        print("unknown file type: %s" % path)
+        sys.exit()
+
old mode 100755 (executable)
new mode 100644 (file)
similarity index 95%
rename from meshio/pymeshio/mqo.py
rename to blender25-meshio/pymeshio/mqo.py
index e9eee56..f8b825c
@@ -258,7 +258,11 @@ class Face(object):
 \r
 def withio(method):\r
     def new(self, path):\r
-        self.io=open(path, encoding='cp932')\r
+        print sys.version_info[0]\r
+        if sys.version_info[0]<3:\r
+            self.io=open(path)\r
+        else:\r
+            self.io=open(path, encoding='cp932')\r
         result=method(self)\r
         self.io=None\r
         return result\r
old mode 100755 (executable)
new mode 100644 (file)
similarity index 57%
rename from meshio/pymeshio/mmd.py
rename to blender25-meshio/pymeshio/pmd.py
index 00d9ecf..caf4639
@@ -1,447 +1,7 @@
-#!/usr/bin/python
 # coding: utf-8
-"""
-20091202: VPD読み込みを追加
-20100318: PMD書き込みを追加
-20100731: meshioと互換になるように改造
-
-VMDの読み込み
-http://yumin3123.at.webry.info/200810/article_4.html
-http://atupdate.web.fc2.com/vmd_format.htm
-
-PMDの読み込み
-http://blog.goo.ne.jp/torisu_tetosuki/e/209ad341d3ece2b1b4df24abf619d6e4
-
-VPDの読み込み
-
-ToDo:
-    rigdid bodies
-    constraints
-"""
-import sys
-import codecs
-import os.path
+import os
 import struct
-import math
-import re
-#import numpy
-from decimal import *
-
-ENCODING='cp932'
-
-if sys.version_info[0]>=3:
-    xrange=range
-
-###############################################################################
-# utility
-###############################################################################
-def truncate_zero(src):
-    """
-    0x00以降を捨てる
-    """
-    pos = src.find(b"\x00")
-    assert(type(src)==bytes)
-    if pos >= 0:
-        return src[:pos]
-    else:
-        return src
-
-def radian_to_degree(x):
-    return x/math.pi * 180.0
-
-
-###############################################################################
-# geometry
-###############################################################################
-class Vector2(object):
-    __slots__=['x', 'y']
-    def __init__(self, x=0, y=0):
-        self.x=x
-        self.y=y
-
-    def __str__(self):
-        return "<%f %f>" % (self.x, self.y)
-
-    def __getitem__(self, key):
-        if key==0:
-            return self.x
-        elif key==1:
-            return self.y
-        else:
-            assert(False)
-
-    def to_tuple(self):
-        return (self.x, self.y)
-
-
-class Vector3(object):
-    __slots__=['x', 'y', 'z']
-    def __init__(self, x=0, y=0, z=0):
-        self.x=x
-        self.y=y
-        self.z=z
-
-    def __str__(self):
-        return "<%f %f %f>" % (self.x, self.y, self.z)
-
-    def __getitem__(self, key):
-        if key==0:
-            return self.x
-        elif key==1:
-            return self.y
-        elif key==2:
-            return self.z
-        else:
-            assert(False)
-
-    def to_tuple(self):
-        return (self.x, self.y, self.z)
-
-class Quaternion(object):
-    __slots__=['x', 'y', 'z', 'w']
-    def __init__(self, x=0, y=0, z=0, w=1):
-        self.x=x
-        self.y=y
-        self.z=z
-        self.w=w
-
-    def __str__(self):
-        return "<%f %f %f %f>" % (self.x, self.y, self.z, self.w)
-
-    def __mul__(self, rhs):
-        u=numpy.array([self.x, self.y, self.z], 'f')
-        v=numpy.array([rhs.x, rhs.y, rhs.z], 'f')
-        xyz=self.w*v+rhs.w*u+numpy.cross(u, v)
-        q=Quaternion(xyz[0], xyz[1], xyz[2], self.w*rhs.w-numpy.dot(u, v))
-        return q
-
-    def dot(self, rhs):
-        return self.x*rhs.x+self.y*rhs.y+self.z*rhs.z+self.w*rhs.w
-
-    def getMatrix(self):
-        sqX=self.x*self.x
-        sqY=self.y*self.y
-        sqZ=self.z*self.z
-        xy=self.x*self.y
-        xz=self.x*self.z
-        yz=self.y*self.z
-        wx=self.w*self.x
-        wy=self.w*self.y
-        wz=self.w*self.z
-        return numpy.array([
-                # 1
-                [1-2*sqY-2*sqZ, 2*xy+2*wz, 2*xz-2*wy, 0],
-                # 2
-                [2*xy-2*wz, 1-2*sqX-2*sqZ, 2*yz+2*wx, 0],
-                # 3
-                [2*xz+2*wy, 2*yz-2*wx, 1-2*sqX-2*sqY, 0],
-                # 4
-                [0, 0, 0, 1]],
-                'f')
-
-    def getRHMatrix(self):
-        x=-self.x
-        y=-self.y
-        z=self.z
-        w=self.w
-        sqX=x*x
-        sqY=y*y
-        sqZ=z*z
-        xy=x*y
-        xz=x*z
-        yz=y*z
-        wx=w*x
-        wy=w*y
-        wz=w*z
-        return numpy.array([
-                # 1
-                [1-2*sqY-2*sqZ, 2*xy+2*wz, 2*xz-2*wy, 0],
-                # 2
-                [2*xy-2*wz, 1-2*sqX-2*sqZ, 2*yz+2*wx, 0],
-                # 3
-                [2*xz+2*wy, 2*yz-2*wx, 1-2*sqX-2*sqY, 0],
-                # 4
-                [0, 0, 0, 1]],
-                'f')
-
-    def getRollPitchYaw(self):
-        m=self.getMatrix()
-
-        roll = math.atan2(m[0, 1], m[1, 1])
-        pitch = math.asin(-m[2, 1])
-        yaw = math.atan2(m[2, 0], m[2, 2])
-
-        if math.fabs(math.cos(pitch)) < 1.0e-6:
-            roll += m[0, 1] > math.pi if 0.0 else -math.pi
-            yaw += m[2, 0] > math.pi if 0.0 else -math.pi
-
-        return roll, pitch, yaw
-
-    def getSqNorm(self):
-        return self.x*self.x+self.y*self.y+self.z*self.z+self.w*self.w
-
-    def getNormalized(self):
-        f=1.0/self.getSqNorm()
-        q=Quaternion(self.x*f, self.y*f, self.z*f, self.w*f)
-        return q
-
-    def getRightHanded(self):
-        "swap y and z axis"
-        return Quaternion(-self.x, -self.z, -self.y, self.w)
-
-    @staticmethod
-    def createFromAxisAngle(axis, rad):
-        q=Quaternion()
-        half_rad=rad/2.0
-        c=math.cos(half_rad)
-        s=math.sin(half_rad)
-        return Quaternion(axis[0]*s, axis[1]*s, axis[2]*s, c)
-
-
-class RGBA(object):
-    __slots__=['r', 'g', 'b', 'a']
-    def __init__(self, r=0, g=0, b=0, a=1):
-        self.r=r
-        self.g=g
-        self.b=b
-        self.a=a
-
-    def __getitem__(self, key):
-        if key==0:
-            return self.r
-        elif key==1:
-            return self.g
-        elif key==2:
-            return self.b
-        elif key==3:
-            return self.a
-        else:
-            assert(False)
-
-
-###############################################################################
-# VMD
-###############################################################################
-class ShapeData(object):
-    __slots__=['name', 'frame', 'ratio']
-    def __init__(self, name):
-        self.name=name
-        self.frame=-1
-        self.ratio=0
-
-    def __cmp__(self, other):
-        return cmp(self.frame, other.frame)
-
-class MotionData(object):
-    __slots__=['name', 'frame', 'pos', 'q', 'complement']
-    def __init__(self, name):
-        self.name=name
-        self.frame=-1
-        self.pos=Vector3()
-        self.q=Quaternion()
-
-    def __cmp__(self, other):
-        return cmp(self.frame, other.frame)
-
-    def __str__(self):
-        return '<MotionData "%s" %d %s%s>' % (self.name, self.frame, self.pos, self.q)
-
-class VMDLoader(object):
-    __slots__=['io', 'end', 'signature',
-            'model_name', 'last_frame',
-            'motions', 'shapes', 'cameras', 'lights',
-            ]
-    def __init__(self):
-        self.model_name=''
-        self.motions=[]
-        self.shapes=[]
-        self.cameras=[]
-        self.lights=[]
-        self.last_frame=0
-
-    def __str__(self):
-        return '<VMDLoader model: "%s", motion: %d, shape: %d, camera: %d, light: %d>' % (
-            self.model_name, len(self.motions), len(self.shapes),
-            len(self.cameras), len(self.lights))
-
-    def load(self, path, io, end):
-        self.io=io
-        self.end=end
-
-        # signature
-        self.signature=truncate_zero(self.io.read(30))
-        version=self.validate_signature(self.signature)
-        if not version:
-            print("invalid signature", self.signature)
-            return False
-
-        if version==1:
-            if not self.load_verstion_1():
-                return False
-        elif version==2:
-            if not  self.load_verstion_2():
-                return False 
-        else:
-            raise Exception("unknown version") 
-
-        # post process
-        motions=self.motions
-        self.motions={}
-        for m in motions:
-            if not m.name in self.motions:
-                self.motions[m.name]=[]
-            self.motions[m.name].append(m)
-        for name in self.motions.keys():
-            self.motions[name].sort()
-
-        shapes=self.shapes
-        self.shapes={}
-        for s in shapes:
-            if not s.name in self.shapes:
-                self.shapes[s.name]=[]
-            self.shapes[s.name].append(s)
-        for name in self.shapes.keys():
-            self.shapes[name].sort()
-
-        return True
-
-    def getMotionCount(self):
-        count=0
-        for v in self.motions.values():
-            count+=len(v)
-        return count
-
-    def getShapeCount(self):
-        count=0
-        for v in self.shapes.values():
-            count+=len(v)
-        return count
-
-    def load_verstion_1(self):
-        # model name
-        self.model_name=truncate_zero(self.io.read(10))
-        if not self.loadMotion_1():
-            return False
-        return True
-
-    def loadMotion_1(self):
-        count=struct.unpack('H', self.io.read(2))[0]
-        self.io.read(2)
-        for i in xrange(0, count):
-            self.loadFrameData()
-        return True
-
-    ############################################################
-    def load_verstion_2(self):
-        # model name
-        self.model_name=truncate_zero(self.io.read(20))
-
-        if not self.loadMotion():
-            return False
-        if not self.loadShape():
-            return False
-        if not self.loadCamera():
-            return False
-        if not self.loadLight():
-            return False
-        #assert(self.io.tell()==self.end)
-        #self.motions.sort(lambda l, r: l.name<r.name)
-
-        return True
-
-    def validate_signature(self, signature):
-        if self.signature == "Vocaloid Motion Data 0002":
-            return 2
-        if self.signature == "Vocaloid Motion Data file":
-            return 1
-        else:
-            return None
-
-    def loadMotion(self):
-        count=struct.unpack('I', self.io.read(4))[0]
-        for i in xrange(0, count):
-            self.loadFrameData()
-        return True
-
-    def loadShape(self):
-        count=struct.unpack('I', self.io.read(4))[0]
-        for i in xrange(0, count):
-            self.loadShapeData()
-        return True
-
-    def loadCamera(self):
-        count=struct.unpack('I', self.io.read(4))[0]
-        for i in xrange(0, count):
-            # not implemented
-            assert(False)
-            pass
-        return True
-
-    def loadLight(self):
-        count=struct.unpack('I', self.io.read(4))[0]
-        for i in xrange(0, count):
-            # not implemented
-            assert(False)
-            pass
-        return True
-
-    def loadFrameData(self):
-        """
-        フレームひとつ分を読み込む
-        """
-        data=MotionData(truncate_zero(self.io.read(15)))
-        (data.frame, data.pos.x, data.pos.y, data.pos.z,
-        data.q.x, data.q.y, data.q.z, data.q.w) = struct.unpack(
-                'I7f', self.io.read(32))
-        # complement data
-        data.complement=''.join(
-                ['%x' % x for x in struct.unpack('64B', self.io.read(64))])
-        self.motions.append(data)
-        if data.frame>self.last_frame:
-            self.last_frame=data.frame
-
-    def loadShapeData(self):
-        """
-        モーフデータひとつ分を読み込む
-        """
-        data=ShapeData(truncate_zero(self.io.read(15)))
-        (data.frame, data.ratio)=struct.unpack('If', self.io.read(8))
-        self.shapes.append(data)
-        if data.frame>self.last_frame:
-            self.last_frame=data.frame
-
-    # vmd -> csv
-    ############################################################
-    def create_csv_line(m):
-        # quaternion -> euler angle
-        (roll, pitch, yaw)=m.q.getRollPitchYaw()
-        return '%s,%d,%g,%g,%g,%g,%g,%g,0x%s\n' % (
-                m.name, m.frame, m.pos.x, m.pos.y, m.pos.z,
-                to_degree(pitch), to_degree(yaw), to_degree(roll), m.complement
-                )
-
-    def write_csv(l, path):
-        sys.setdefaultencoding('cp932')
-        csv=open(path, "w")
-        csv.write('%s,0\n' % l.signature)
-        csv.write('%s\n' % l.model_name)
-        # motion
-        csv.write('%d\n' % len(l.motions))
-        for m in l.motions:
-            csv.write(create_csv_line(m))
-        # shape
-        csv.write('%d\n' % len(l.shapes))
-        for s in l.shapes:
-            csv.write('%s,%d,%f\n' % ( s.name, s.frame, s.ratio))
-        # camera
-        csv.write('%d\n' % len(l.cameras))
-        for camera in l.cameras:
-            assert(False)
-        # light
-        csv.write('%d\n' % len(l.lights))
-        for light in l.lights:
-            assert(False)
-
+from mmd import *
 
 ###############################################################################
 # PMD
@@ -705,7 +265,7 @@ class BoneGroup(object):
     def getEnglishName(self): return self.english_name.decode('cp932')
     def setEnglishName(self, u): self.english_name=u
 
-class PMDLoader(object):
+class IO(object):
     __slots__=['io', 'end', 'pos',
             'version', 'model_name', 'comment',
             'english_model_name', 'english_comment',
@@ -1142,200 +702,3 @@ class PMDLoader(object):
             struct.unpack("124s", self.io.read(124))[0]
         return True
 
-
-###############################################################################
-# VPD
-###############################################################################
-class LineLoader(object):
-    """
-    行指向の汎用ローダ
-    """
-    __slots__=['path', 'io', 'end']
-    def __str__(self):
-        return "<%s current:%d, end:%d>" % (
-                self.__class__, self.getPos(), self.getEnd())
-
-    def getPos(self):
-        return self.io.tell()
-
-    def getEnd(self):
-        return self.end
-
-    def readline(self):
-        return (self.io.readline()).strip()
-
-    def isEnd(self):
-        return self.io.tell()>=self.end
-
-    def load(self, path, io, end):
-        self.path=path
-        self.io=io
-        self.end=end
-        return self.process()
-
-    def process(self):
-        """
-        dummy. read to end.
-        """
-        while not self.isEnd():
-            self.io.readline()
-        return True
-
-
-class VPDLoader(LineLoader):
-    __slots__=['pose']
-    def __init__(self):
-        super(VPDLoader, self).__init__()
-        self.pose=[]
-
-    def __str__(self):
-        return "<VPD poses:%d>" % len(self.pose)
-
-    def process(self):
-        if self.readline()!="Vocaloid Pose Data file":
-            return
-
-        RE_OPEN=re.compile('^(\w+){(.*)')
-        RE_OSM=re.compile('^\w+\.osm;')
-        RE_COUNT=re.compile('^(\d+);')
-
-        bone_count=-1
-        while not self.isEnd():
-            line=self.readline()
-            if line=='':
-                continue
-            m=RE_OPEN.match(line)
-            if m:
-                if not self.parseBone(m.group(2)):
-                    raise Exception("invalid bone")
-                continue
-
-            m=RE_OSM.match(line)
-            if m:
-                continue
-
-            m=RE_COUNT.match(line)
-            if m:
-                bone_count=int(m.group(1))
-                continue
-
-        return len(self.pose)==bone_count
-
-    def parseBone(self, name):
-        bone=MotionData(name)
-        self.pose.append(bone)
-        bone.pos=Vector3(*[float(token) for token in self.readline().split(';')[0].split(',')])
-        bone.q=Quaternion(*[float(token) for token in self.readline().split(';')[0].split(',')])
-        return self.readline()=="}"
-
-
-###############################################################################
-# interface
-###############################################################################
-def load_pmd(path):
-    size=os.path.getsize(path)
-    f=open(path, "rb")
-    l=PMDLoader()
-    if l.load(path, f, size):
-        return l
-
-def load_vmd(path):
-    size=os.path.getsize(path)
-    f=open(path, "rb")
-    l=VMDLoader()
-    if l.load(path, f, size):
-        return l
-
-def load_vpd(path):
-    f=open(path, 'rb')
-    if not f:
-        return;
-    size=os.path.getsize(path)
-    l=VPDLoader()
-    if l.load(path, f, size):
-        return l
-
-
-###############################################################################
-# debug
-###############################################################################
-def debug_pmd(path):
-    l=load_pmd(path)
-    if not l:
-        print("fail to load")
-        sys.exit()
-
-    print(unicode(l).encode(ENCODING))
-    print(l.comment.encode(ENCODING))
-    print("<ボーン>".decode('utf-8').encode(ENCODING))
-    for bone in l.no_parent_bones:
-        print(bone.name.encode(ENCODING))
-        bone.display()
-    #for bone in l.bones:
-    #    uni="%s:%s" % (bone.english_name, bone.name)
-    #    print uni.encode(ENCODING)
-    #for skin in l.morph_list:
-    #    uni="%s:%s" % (skin.english_name, skin.name)
-    #    print uni.encode(ENCODING)
-    #for i, v in enumerate(l.vertices):
-    #    print i, v
-    #for i, f in enumerate(l.indices):
-    #    print i, f
-    for m in l.materials:
-        print(m)
-
-def debug_pmd_write(path, out):
-    l=load_pmd(path)
-    if not l:
-        print("fail to load")
-        sys.exit()
-
-    if not l.write(out):
-        print("fail to write")
-        sys.exit()
-
-def debug_vmd(path):
-    l=load_vmd(path)
-    if not l:
-        print("fail to load")
-        sys.exit()
-    print(unicode(l).encode(ENCODING))
-
-    #for m in l.motions[u'センター']:
-    #    print m.frame, m.pos
-    for n, m in l.shapes.items():
-        print(unicode(n).encode(ENCODING), getEnglishSkinName(n))
-
-def debug_vpd(path):
-    l=load_vpd(path)
-    if not l:
-        print("fail to load")
-        sys.exit()
-    for bone in l.pose:
-        print(unicode(bone).encode(ENCODING))
-
-if __name__=="__main__":
-    if len(sys.argv)<2:
-        print("usage: %s {pmd file}" % sys.argv[0])
-        print("usage: %s {vmd file}" % sys.argv[0])
-        print("usage: %s {vpd file}" % sys.argv[0])
-        print("usage: %s {pmd file} {export pmdfile}" % sys.argv[0])
-        sys.exit()
-
-    path=sys.argv[1]
-    if not os.path.exists(path):
-        print("no such file: %s" % path)
-
-    if path.lower().endswith('.pmd'):
-        if len(sys.argv)==2:
-            debug_pmd(path)
-        else:
-            debug_pmd_write(path, sys.argv[2])
-    elif path.lower().endswith('.vmd'):
-        debug_vmd(path)
-    elif path.lower().endswith('.vpd'):
-        debug_vpd(path)
-    else:
-        print("unknown file type: %s" % path)
-        sys.exit()
-
diff --git a/blender25-meshio/pymeshio/vmd.py b/blender25-meshio/pymeshio/vmd.py
new file mode 100644 (file)
index 0000000..81596a2
--- /dev/null
@@ -0,0 +1,223 @@
+###############################################################################
+# VMD
+###############################################################################
+class ShapeData(object):
+    __slots__=['name', 'frame', 'ratio']
+    def __init__(self, name):
+        self.name=name
+        self.frame=-1
+        self.ratio=0
+
+    def __cmp__(self, other):
+        return cmp(self.frame, other.frame)
+
+class MotionData(object):
+    __slots__=['name', 'frame', 'pos', 'q', 'complement']
+    def __init__(self, name):
+        self.name=name
+        self.frame=-1
+        self.pos=Vector3()
+        self.q=Quaternion()
+
+    def __cmp__(self, other):
+        return cmp(self.frame, other.frame)
+
+    def __str__(self):
+        return '<MotionData "%s" %d %s%s>' % (self.name, self.frame, self.pos, self.q)
+
+class VMDLoader(object):
+    __slots__=['io', 'end', 'signature',
+            'model_name', 'last_frame',
+            'motions', 'shapes', 'cameras', 'lights',
+            ]
+    def __init__(self):
+        self.model_name=''
+        self.motions=[]
+        self.shapes=[]
+        self.cameras=[]
+        self.lights=[]
+        self.last_frame=0
+
+    def __str__(self):
+        return '<VMDLoader model: "%s", motion: %d, shape: %d, camera: %d, light: %d>' % (
+            self.model_name, len(self.motions), len(self.shapes),
+            len(self.cameras), len(self.lights))
+
+    def load(self, path, io, end):
+        self.io=io
+        self.end=end
+
+        # signature
+        self.signature=truncate_zero(self.io.read(30))
+        version=self.validate_signature(self.signature)
+        if not version:
+            print("invalid signature", self.signature)
+            return False
+
+        if version==1:
+            if not self.load_verstion_1():
+                return False
+        elif version==2:
+            if not  self.load_verstion_2():
+                return False 
+        else:
+            raise Exception("unknown version") 
+
+        # post process
+        motions=self.motions
+        self.motions={}
+        for m in motions:
+            if not m.name in self.motions:
+                self.motions[m.name]=[]
+            self.motions[m.name].append(m)
+        for name in self.motions.keys():
+            self.motions[name].sort()
+
+        shapes=self.shapes
+        self.shapes={}
+        for s in shapes:
+            if not s.name in self.shapes:
+                self.shapes[s.name]=[]
+            self.shapes[s.name].append(s)
+        for name in self.shapes.keys():
+            self.shapes[name].sort()
+
+        return True
+
+    def getMotionCount(self):
+        count=0
+        for v in self.motions.values():
+            count+=len(v)
+        return count
+
+    def getShapeCount(self):
+        count=0
+        for v in self.shapes.values():
+            count+=len(v)
+        return count
+
+    def load_verstion_1(self):
+        # model name
+        self.model_name=truncate_zero(self.io.read(10))
+        if not self.loadMotion_1():
+            return False
+        return True
+
+    def loadMotion_1(self):
+        count=struct.unpack('H', self.io.read(2))[0]
+        self.io.read(2)
+        for i in xrange(0, count):
+            self.loadFrameData()
+        return True
+
+    ############################################################
+    def load_verstion_2(self):
+        # model name
+        self.model_name=truncate_zero(self.io.read(20))
+
+        if not self.loadMotion():
+            return False
+        if not self.loadShape():
+            return False
+        if not self.loadCamera():
+            return False
+        if not self.loadLight():
+            return False
+        #assert(self.io.tell()==self.end)
+        #self.motions.sort(lambda l, r: l.name<r.name)
+
+        return True
+
+    def validate_signature(self, signature):
+        if self.signature == "Vocaloid Motion Data 0002":
+            return 2
+        if self.signature == "Vocaloid Motion Data file":
+            return 1
+        else:
+            return None
+
+    def loadMotion(self):
+        count=struct.unpack('I', self.io.read(4))[0]
+        for i in xrange(0, count):
+            self.loadFrameData()
+        return True
+
+    def loadShape(self):
+        count=struct.unpack('I', self.io.read(4))[0]
+        for i in xrange(0, count):
+            self.loadShapeData()
+        return True
+
+    def loadCamera(self):
+        count=struct.unpack('I', self.io.read(4))[0]
+        for i in xrange(0, count):
+            # not implemented
+            assert(False)
+            pass
+        return True
+
+    def loadLight(self):
+        count=struct.unpack('I', self.io.read(4))[0]
+        for i in xrange(0, count):
+            # not implemented
+            assert(False)
+            pass
+        return True
+
+    def loadFrameData(self):
+        """
+        フレームひとつ分を読み込む
+        """
+        data=MotionData(truncate_zero(self.io.read(15)))
+        (data.frame, data.pos.x, data.pos.y, data.pos.z,
+        data.q.x, data.q.y, data.q.z, data.q.w) = struct.unpack(
+                'I7f', self.io.read(32))
+        # complement data
+        data.complement=''.join(
+                ['%x' % x for x in struct.unpack('64B', self.io.read(64))])
+        self.motions.append(data)
+        if data.frame>self.last_frame:
+            self.last_frame=data.frame
+
+    def loadShapeData(self):
+        """
+        モーフデータひとつ分を読み込む
+        """
+        data=ShapeData(truncate_zero(self.io.read(15)))
+        (data.frame, data.ratio)=struct.unpack('If', self.io.read(8))
+        self.shapes.append(data)
+        if data.frame>self.last_frame:
+            self.last_frame=data.frame
+
+    # vmd -> csv
+    ############################################################
+    def create_csv_line(m):
+        # quaternion -> euler angle
+        (roll, pitch, yaw)=m.q.getRollPitchYaw()
+        return '%s,%d,%g,%g,%g,%g,%g,%g,0x%s\n' % (
+                m.name, m.frame, m.pos.x, m.pos.y, m.pos.z,
+                to_degree(pitch), to_degree(yaw), to_degree(roll), m.complement
+                )
+
+    def write_csv(l, path):
+        sys.setdefaultencoding('cp932')
+        csv=open(path, "w")
+        csv.write('%s,0\n' % l.signature)
+        csv.write('%s\n' % l.model_name)
+        # motion
+        csv.write('%d\n' % len(l.motions))
+        for m in l.motions:
+            csv.write(create_csv_line(m))
+        # shape
+        csv.write('%d\n' % len(l.shapes))
+        for s in l.shapes:
+            csv.write('%s,%d,%f\n' % ( s.name, s.frame, s.ratio))
+        # camera
+        csv.write('%d\n' % len(l.cameras))
+        for camera in l.cameras:
+            assert(False)
+        # light
+        csv.write('%d\n' % len(l.lights))
+        for light in l.lights:
+            assert(False)
+
diff --git a/blender25-meshio/pymeshio/vpd.py b/blender25-meshio/pymeshio/vpd.py
new file mode 100644 (file)
index 0000000..ec3f124
--- /dev/null
@@ -0,0 +1,86 @@
+###############################################################################
+# VPD
+###############################################################################
+class LineLoader(object):
+    """
+    行指向の汎用ローダ
+    """
+    __slots__=['path', 'io', 'end']
+    def __str__(self):
+        return "<%s current:%d, end:%d>" % (
+                self.__class__, self.getPos(), self.getEnd())
+
+    def getPos(self):
+        return self.io.tell()
+
+    def getEnd(self):
+        return self.end
+
+    def readline(self):
+        return (self.io.readline()).strip()
+
+    def isEnd(self):
+        return self.io.tell()>=self.end
+
+    def load(self, path, io, end):
+        self.path=path
+        self.io=io
+        self.end=end
+        return self.process()
+
+    def process(self):
+        """
+        dummy. read to end.
+        """
+        while not self.isEnd():
+            self.io.readline()
+        return True
+
+
+class VPDLoader(LineLoader):
+    __slots__=['pose']
+    def __init__(self):
+        super(VPDLoader, self).__init__()
+        self.pose=[]
+
+    def __str__(self):
+        return "<VPD poses:%d>" % len(self.pose)
+
+    def process(self):
+        if self.readline()!="Vocaloid Pose Data file":
+            return
+
+        RE_OPEN=re.compile('^(\w+){(.*)')
+        RE_OSM=re.compile('^\w+\.osm;')
+        RE_COUNT=re.compile('^(\d+);')
+
+        bone_count=-1
+        while not self.isEnd():
+            line=self.readline()
+            if line=='':
+                continue
+            m=RE_OPEN.match(line)
+            if m:
+                if not self.parseBone(m.group(2)):
+                    raise Exception("invalid bone")
+                continue
+
+            m=RE_OSM.match(line)
+            if m:
+                continue
+
+            m=RE_COUNT.match(line)
+            if m:
+                bone_count=int(m.group(1))
+                continue
+
+        return len(self.pose)==bone_count
+
+    def parseBone(self, name):
+        bone=MotionData(name)
+        self.pose.append(bone)
+        bone.pos=Vector3(*[float(token) for token in self.readline().split(';')[0].split(',')])
+        bone.q=Quaternion(*[float(token) for token in self.readline().split(';')[0].split(',')])
+        return self.readline()=="}"
+
+
diff --git a/setup.cfg b/setup.cfg
new file mode 100644 (file)
index 0000000..ba0d4d6
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,5 @@
+[nosetests]
+verbosity = 3
+detailed-errors = 1
+exclude-dir=blender25-meshio
+#color=1
diff --git a/setup.py b/setup.py
new file mode 100644 (file)
index 0000000..4403a55
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,18 @@
+import setuptools
+
+setuptools.setup(
+        name='pymeshio',
+        version='1.1.0',
+        description='pure python 3d model io library',
+        keywords=[],
+        author='ousttrue',
+        author_email='ousttrue@gmail.com',
+        url='http://meshio.sourceforge.jp/',
+        license='zlib',
+        package_dir={
+            'pymeshio': 'blender25-meshio/pymeshio'
+            },
+        packages=['pymeshio'],
+        test_suite='nose.collector'
+        )
+
diff --git a/test/mqo_test.py b/test/mqo_test.py
new file mode 100644 (file)
index 0000000..12daf50
--- /dev/null
@@ -0,0 +1,9 @@
+import pymeshio.mqo
+import sys
+
+MQO_FILE="K:/model/cube.mqo"
+
+def test_mqo_load():
+    io=pymeshio.mqo.IO()
+    assert io.read(MQO_FILE)
+
diff --git a/test/mqo_test.pyc b/test/mqo_test.pyc
new file mode 100755 (executable)
index 0000000..ce866e4
Binary files /dev/null and b/test/mqo_test.pyc differ
diff --git a/test/pmd_test.py b/test/pmd_test.py
new file mode 100644 (file)
index 0000000..0a8944e
--- /dev/null
@@ -0,0 +1,9 @@
+import pymeshio.pmd
+import sys
+
+PMD_FILE="K:/MMD/model/official/miku.pmd"
+
+def test_pmd_load():
+    io=pymeshio.pmd.IO()
+    assert io.read(PMD_FILE)
+
diff --git a/test/pmd_test.pyc b/test/pmd_test.pyc
new file mode 100755 (executable)
index 0000000..53180c6
Binary files /dev/null and b/test/pmd_test.pyc differ