OSDN Git Service

implement pmx vertex read
authorousttrue <ousttrue@gmail.com>
Fri, 30 Sep 2011 00:24:24 +0000 (09:24 +0900)
committerousttrue <ousttrue@gmail.com>
Fri, 30 Sep 2011 00:24:24 +0000 (09:24 +0900)
pymeshio/pmx.py
test/pmx_test.py

index ff04e6f..52b124b 100644 (file)
@@ -8,18 +8,77 @@ pmx file format:
 """\r
 __author__="ousttrue"\r
 __license__="zlib"\r
-__versioon__="0.0.1"\r
+__versioon__="1.0.0"\r
 \r
 \r
 import io\r
 import os\r
 import struct\r
+from . import common\r
+\r
+\r
+class ParseException(Exception):\r
+    pass\r
+\r
+\r
+class Deform(object):\r
+    pass\r
+\r
+\r
+class Bdef1(object):\r
+    """bone deform. use a weight\r
+\r
+    Attributes: see __init__\r
+    """\r
+    __slots__=[ 'bone_index']\r
+    def __init__(self, bone_index: int):\r
+        self.bone_index=bone_index\r
+\r
+\r
+class Bdef2(object):\r
+    """bone deform. use two weights\r
+\r
+    Attributes: see __init__\r
+    """\r
+    __slots__=[ 'index0', 'index1', 'weight0']\r
+    def __init__(self, \r
+            index0: int,\r
+            index1: int,\r
+            weight0: float):\r
+        self.index0=index0\r
+        self.index1=index1\r
+        self.weight0=weight0\r
+\r
+\r
+class Vertex(object):\r
+    """pmx vertex\r
+\r
+    Attributes: see __init__\r
+    """\r
+    __slots__=[ 'position', 'normal', 'uv', 'deform', 'edge_factor' ]\r
+    def __init__(self, \r
+            position: common.Vector3, \r
+            normal: common.Vector3, \r
+            uv: common.Vector2, \r
+            deform: Deform, \r
+            edge_factor: float):\r
+        self.position=position \r
+        self.normal=normal\r
+        self.uv=uv\r
+        self.deform=deform\r
+        self.edge_factor=edge_factor\r
 \r
 \r
 class Model(object):\r
-    """pmx data holder\r
+    """pmx data representation\r
 \r
-    version: pmx version\r
+    Attributes:\r
+        version: pmx version(expected 2.0)\r
+        name: \r
+        english_name: \r
+        comment: \r
+        english_comment: \r
+        vertices:\r
     """\r
     __slots__=[\r
             'version', # pmx version\r
@@ -27,16 +86,29 @@ class Model(object):
             'english_name', # model name in english\r
             'comment', # model comment\r
             'english_comment', # model comment in english\r
+            'vertices'\r
             ]\r
     def __init__(self):\r
         self.version=0.0\r
+        self.name=''\r
+        self.english_name=''\r
+        self.comment=''\r
+        self.english_comment=''\r
+        self.vertices=[]\r
 \r
 \r
 class IO(object):\r
     """pmx loader\r
 \r
     Attributes:\r
-        name: model name\r
+        text_encoding: \r
+        extended_uv:\r
+        vertex_index_size:\r
+        texture_index_size:\r
+        material_index_size:\r
+        bone_index_size:\r
+        morph_index_size:\r
+        rigidbody_index_size:\r
     """\r
     def __init__(self):\r
         self.__io=None\r
@@ -47,22 +119,62 @@ class IO(object):
     def read(self, path: 'filepath') -> Model:\r
         size=os.path.getsize(path)\r
         with open(path, "rb") as f:\r
-            if self.load(path, f, size):\r
+            if self.__load(path, f, size):\r
                 return self.__model\r
 \r
-    def load(self, path: 'filepath', io: io.IOBase, size: int) -> bool: \r
+    def __load(self, path: 'filepath', io: io.IOBase, size: int) -> bool: \r
         self.__io=io\r
         self.__end=size\r
-        self.__check_position()\r
+        self.__pos=0\r
 \r
-        if not self.__loadHeader():\r
+        ####################\r
+        # header\r
+        ####################\r
+        signature=self.__unpack("4s", 4)\r
+        if signature!=b"PMX ":\r
+            print("invalid signature", self.signature)\r
             return False\r
-        self.__check_position()\r
+        version=self.__unpack("f", 4)\r
+        if version!=2.0:\r
+            print("unknown version", version)\r
+        self.__model.version=version\r
+        # flags\r
+        flag_bytes=self.__unpack("B", 1)\r
+        if flag_bytes!=8:\r
+            print("invalid flag length", self.flag_bytes)\r
+            return False\r
+        # text encoding\r
+        self.text_encoding=self.__unpack("B", 1)\r
+        self.__read_text=self.__get_read_text()\r
+        # uv\r
+        self.extended_uv=self.__unpack("B", 1)\r
+        if self.extended_uv>0:\r
+            print("extended uv is not supported", self.extended_uv)\r
+            return False\r
+        # index size\r
+        self.vertex_index_size=self.__unpack("B", 1)\r
+        self.texture_index_size=self.__unpack("B", 1)\r
+        self.material_index_size=self.__unpack("B", 1)\r
+        self.bone_index_size=self.__unpack("B", 1)\r
+        self.morph_index_size=self.__unpack("B", 1)\r
+        self.rigidbody_index_size=self.__unpack("B", 1)\r
+\r
+        ####################\r
         # model info\r
+        ####################\r
         self.__model.name = self.__read_text()\r
         self.__model.english_name = self.__read_text()\r
         self.__model.comment = self.__read_text()\r
         self.__model.english_comment = self.__read_text()\r
+\r
+        ####################\r
+        # vertices\r
+        ####################\r
+        #vertex_count=self.__read_int(self.vertex_index_size)\r
+        # pmdeditor 131c bug?\r
+        vertex_count=self.__read_int(4)\r
+        self.__model.vertices=[self.__read_vertex() for i in range(vertex_count)]\r
+\r
         return True\r
 \r
     def __str__(self) -> str:\r
@@ -72,42 +184,79 @@ class IO(object):
         self.__pos=self.__io.tell()\r
 \r
     def __unpack(self, fmt: str, size: int) -> "read value as format":\r
-        return struct.unpack(fmt, self.__io.read(size))[0]\r
+        result=struct.unpack(fmt, self.__io.read(size))\r
+        self.__check_position()\r
+        return result[0]\r
 \r
-    def __loadHeader(self) -> bool:\r
-        signature=self.__unpack("4s", 4)\r
-        if signature!=b"PMX ":\r
-            print("invalid signature", signature)\r
-            return False\r
-        version=self.__unpack("f", 4)\r
-        if version!=2.0:\r
-            print("unknown version", version)\r
-        self.__model.version=version\r
-        # flags\r
-        flag_bytes=self.__unpack("B", 1)\r
-        if flag_bytes!=8:\r
-            print("invalid flag length", flag_bytes)\r
-            return False\r
-        # text encoding\r
-        text_encoding=self.__unpack("B", 1)\r
-        if text_encoding==0:\r
+    def __get_read_text(self) -> "text process function":\r
+        if self.text_encoding==0:\r
             def read_text():\r
                 size=self.__unpack("I", 4)\r
                 return self.__unpack("{0}s".format(size), size).decode("UTF16")\r
-        elif text_encoding==1:\r
+            return read_text\r
+        elif self.text_encoding==1:\r
             def read_text():\r
                 size=self.__unpack("I", 4)\r
                 return self.__unpack("{0}s".format(size), size).decode("UTF8")\r
+            return read_text\r
         else:\r
-            print("unknown text encoding", text_encoding)\r
-            return False\r
-        self.__read_text=read_text\r
-        self.__unpack("B", 1)\r
-        self.__unpack("B", 1)\r
-        self.__unpack("B", 1)\r
-        self.__unpack("B", 1)\r
-        self.__unpack("B", 1)\r
-        self.__unpack("B", 1)\r
-        self.__unpack("B", 1)\r
-        return True\r
+            print("unknown text encoding", self.text_encoding)\r
+\r
+    def __read_int(self, size):\r
+        if size==1:\r
+            return self.__unpack("B", size)\r
+        if size==2:\r
+            return self.__unpack("H", size)\r
+        if size==4:\r
+            return self.__unpack("I", size)\r
+        print("not reach here")\r
+        raise ParseException("invalid int size: "+size)\r
+\r
+    def __read_vertex(self):\r
+        return Vertex(\r
+                self.__read_vector3(), # pos\r
+                self.__read_vector3(), # normal\r
+                self.__read_vector2(), # uv\r
+                self.__read_deform(), # deform(bone weight)\r
+                self.__unpack("f", 4) # edge factor\r
+                )\r
+\r
+    def __read_vector2(self):\r
+        print(self.__pos)\r
+        return common.Vector2(\r
+                self.__unpack("f", 4), \r
+                self.__unpack("f", 4)\r
+                )\r
+\r
+    def __read_vector3(self):\r
+        print(self.__pos)\r
+        return common.Vector3(\r
+                self.__unpack("f", 4), \r
+                self.__unpack("f", 4), \r
+                self.__unpack("f", 4)\r
+                )\r
+\r
+    def __read_deform(self):\r
+        print(self.__pos)\r
+        deform_type=self.__unpack("B", 1)\r
+        if deform_type==0:\r
+            return Bdef1(self.__read_int(self.bone_index_size))\r
+        if deform_type==1:\r
+            return Bdef2(\r
+                    self.__read_int(self.bone_index_size),\r
+                    self.__read_int(self.bone_index_size),\r
+                    self.__unpack("f", 4)\r
+                    )\r
+        """\r
+        if deform_type==2:\r
+            return Bdef4(\r
+                    self.__read_int(self.bone_index_size),\r
+                    self.__read_int(self.bone_index_size),\r
+                    self.__read_int(self.bone_index_size),\r
+                    self.__read_int(self.bone_index_size),\r
+                    self.__unpack("f", 4), self.__unpack("f", 4),\r
+                    self.__unpack("f", 4), self.__unpack("f", 4)\r
+                    )\r
+        """\r
+        raise ParseException("unknown deform type: {0}".format(deform_type))\r
 \r
index 1c88dd1..fdf29a9 100644 (file)
@@ -4,7 +4,7 @@ import pymeshio.pmx
 \r
 PMX_MODEL='resources/初音ミクVer2.pmx'\r
 \r
-def test_load():\r
+def test_read():\r
     io=pymeshio.pmx.IO()\r
     model=io.read(PMX_MODEL)\r
     assert model.__class__==pymeshio.pmx.Model\r
@@ -27,3 +27,4 @@ def test_load():
             "Copyright         CRYPTON FUTURE MEDIA, INC"\r
             )\r
 \r
+    assert len(model.vertices)==12354\r