From: ousttrue Date: Sun, 2 Oct 2011 08:18:57 +0000 (+0900) Subject: refactoring pmd X-Git-Url: http://git.osdn.jp/view?a=commitdiff_plain;h=c9f342063f2c03949e23a4dd12960efa11fe2cb7;p=meshio%2Fpymeshio.git refactoring pmd --- diff --git a/pymeshio/common.py b/pymeshio/common.py index b0af81c..dca807d 100644 --- a/pymeshio/common.py +++ b/pymeshio/common.py @@ -273,6 +273,9 @@ class BinaryLoader(object): def __init__(self, io): self.io=io + def is_end(self): + return not self.io.readable() + def unpack(self, fmt, size): result=struct.unpack(fmt, self.io.read(size)) return result[0] diff --git a/pymeshio/pmd.py b/pymeshio/pmd.py deleted file mode 100644 index 713bd38..0000000 --- a/pymeshio/pmd.py +++ /dev/null @@ -1,922 +0,0 @@ -# coding: utf-8 -""" -PMDの読み込み -http://blog.goo.ne.jp/torisu_tetosuki/e/209ad341d3ece2b1b4df24abf619d6e4 -""" -import os -import sys -import struct -from .common import * -from .compatibility import * - - -class Vertex(object): - """pmd vertex struct. - - Attributes: - pos: Vector3 - normal: Vector3 - uv: Vector2 - bone0: bone index - bone1: bone index - weight0: bone0 influence - edge_flag: int flag - """ - __slots__=['pos', 'normal', 'uv', 'bone0', 'bone1', 'weight0', 'edge_flag'] - def __init__(self, x=0, y=0, z=0, nx=0, ny=0, nz=0, u=0, v=0, - bone0=0, bone1=0, weight0=0, edge_flag=0): - self.pos=Vector3(x, y, z) - self.normal=Vector3(nx, ny, nz) - self.uv=Vector2(u, v) - self.bone0=bone0 - self.bone1=bone1 - self.weight0=weight0 - self.edge_flag=edge_flag - - def __str__(self): - return "<%s %s %s, (%d, %d, %d)>" % ( - str(self.pos), - str(self.normal), - str(self.uv), - self.bone0, self.bone1, self.weight0) - - def __getitem__(self, key): - if key==0: - return self.pos.x - elif key==1: - return self.pos.y - elif key==2: - return self.pos.z - else: - assert(False) - - -class Material(object): - """pmd material struct. - - Attributes: - diffuse: RGBA - shinness: float - specular: RGB - ambient: RGB - vertex_count: indices length - _texture: texture file path - toon_index: int - flag: int - """ - __slots__=[ - 'diffuse', 'shinness', 'specular', - 'ambient', 'vertex_count', '_texture', 'toon_index', 'flag', - ] - def getTexture(self): return from_str(self._texture) - def setTexture(self, texture): self._texture=to_str(texture) - texture=property(getTexture, setTexture) - - def __init__(self, dr=0, dg=0, db=0, alpha=1, - specular=0, sr=0, sg=0, sb=0, ar=0, ag=0, ab=0): - self.diffuse=RGBA(dr, dg, db, alpha) - self.specular=RGBA(sr, sg, sb) - self.shinness=specular - self.ambient=RGBA(ar, ag, ab) - self.vertex_count=0 - self.texture='' - self.toon_index=0 - self.flag=0 - - def __str__(self): - return "" % ( - self.diffuse[0], self.diffuse[1], - self.diffuse[2], self.diffuse[3], - ) - - -class Bone(object): - """pmd material struct. - - Attributes: - _name: - index: - type: - ik: - pos: - _english_name: - ik_index: - parent_index: - tail_index: - - parent: - tail: - children: - """ - # kinds - ROTATE = 0 - ROTATE_MOVE = 1 - IK = 2 - IK_ROTATE_INFL = 4 - ROTATE_INFL = 5 - IK_TARGET = 6 - UNVISIBLE = 7 - # since v4.0 - ROLLING=8 # ? - TWEAK=9 - __slots__=['_name', 'index', 'type', 'parent', 'ik', 'pos', - 'children', '_english_name', 'ik_index', - 'parent_index', 'tail_index', 'tail', - ] - def getName(self): - """ - return str(multibyte) in python2 - return bytes in python3 - """ - return from_str(self._name) - def setName(self, name): self._name=to_str(name) - name=property(getName, setName) - def getEnglishName(self): return from_str(self._english_name) - def setEnglishName(self, english_name): self._english_name=to_str(english_name) - english_name=property(getEnglishName, setEnglishName) - - def __init__(self, name='bone', type=0): - self.name=name - self.index=0 - self.type=type - self.parent_index=0xFFFF - self.tail_index=0 - self.tail=Vector3(0, 0, 0) - self.parent=None - self.ik_index=0xFFFF - self.pos=Vector3(0, 0, 0) - self.children=[] - self.english_name='' - - def hasParent(self): - return self.parent_index!=0xFFFF - - def hasChild(self): - return self.tail_index!=0 - - def display(self, indent=[]): - if len(indent)>0: - prefix='' - for i, is_end in enumerate(indent): - if i==len(indent)-1: - break - else: - prefix+=' ' if is_end else ' |' - uni='%s +%s(%s)' % (prefix, unicode(self), self.english_name) - print(uni.encode(ENCODING)) - else: - uni='%s(%s)' % (unicode(self), self.english_name) - print(uni.encode(ENCODING)) - - child_count=len(self.children) - for i in range(child_count): - child=self.children[i] - if i' % (self.name) -# 1 -class Bone_RotateMove(Bone): - __slots__=[] - def __init__(self, name): - super(Bone_RotateMove, self).__init__(name, 1) - def __str__(self): - return '' % (self.name) -# 2 -class Bone_IK(Bone): - __slots__=[] - def __init__(self, name): - super(Bone_IK, self).__init__(name, 2) - def __str__(self): - return '' % (self.name) -# 4 -class Bone_IKRotateInfl(Bone): - __slots__=[] - def __init__(self, name): - super(Bone_IKRotateInfl, self).__init__(name, 4) - def __str__(self): - return '' % (self.name) -# 5 -class Bone_RotateInfl(Bone): - __slots__=[] - def __init__(self, name): - super(Bone_RotateInfl, self).__init__(name, 5) - def __str__(self): - return '' % (self.name) -# 6 -class Bone_IKTarget(Bone): - __slots__=[] - def __init__(self, name): - super(Bone_IKTarget, self).__init__(name, 6) - def __str__(self): - return '' % (self.name) -# 7 -class Bone_Unvisible(Bone): - __slots__=[] - def __init__(self, name): - super(Bone_Unvisible, self).__init__(name, 7) - def __str__(self): - return '' % (self.name) -# 8 -class Bone_Rolling(Bone): - __slots__=[] - def __init__(self, name): - super(Bone_Rolling, self).__init__(name, 8) - def __str__(self): - return '' % (self.name) -# 9 -class Bone_Tweak(Bone): - __slots__=[] - def __init__(self, name): - super(Bone_Tweak, self).__init__(name, 9) - def __str__(self): - return '' % (self.name) - - -def createBone(name, type): - if type==0: - return Bone_Rotate(name) - elif type==1: - return Bone_RotateMove(name) - elif type==2: - return Bone_IK(name) - elif type==3: - raise Exception("no used bone type: 3(%s)" % name) - elif type==4: - return Bone_IKRotateInfl(name) - elif type==5: - return Bone_RotateInfl(name) - elif type==6: - return Bone_IKTarget(name) - elif type==7: - return Bone_Unvisible(name) - elif type==8: - return Bone_Rolling(name) - elif type==9: - return Bone_Tweak(name) - else: - raise Exception("unknown bone type: %d(%s)", type, name) - - -class IK(object): - __slots__=['index', 'target', 'iterations', 'weight', 'length', 'children'] - def __init__(self, index=0, target=0): - self.index=index - self.target=target - self.iterations=None - self.weight=None - self.children=[] - - def __str__(self): - return "" %(self.index, self.target, self.iterations, self.weight, '-'.join([str(i) for i in self.children]), len(self.children)) - - -class Skin(object): - __slots__=['_name', 'type', 'indices', 'pos_list', '_english_name', - 'vertex_count'] - def getName(self): return from_str(self._name) - def setName(self, name): self._name=to_str(name) - name=property(getName, setName) - def getEnglishName(self): return from_str(self._english_name) - def setEnglishName(self, english_name): self._english_name=to_str(english_name) - english_name=property(getEnglishName, setEnglishName) - - def __init__(self, name='skin'): - self.name=name - self.type=None - self.indices=[] - self.pos_list=[] - self.english_name='' - self.vertex_count=0 - - def append(self, index, x, y, z): - self.indices.append(index) - self.pos_list.append(Vector3(x, y, z)) - - def __str__(self): - return '' % ( - self.name, self.type, len(self.indices)) - - -class BoneGroup(object): - __slots__=['_name', '_english_name'] - def getName(self): return from_str(self._name) - def setName(self, name): self._name=to_str(name) - name=property(getName, setName) - def getEnglishName(self): return from_str(self._english_name) - def setEnglishName(self, english_name): self._english_name=to_str(english_name) - english_name=property(getEnglishName, setEnglishName) - - def __init__(self, name='group'): self._name=name; self._english_name='center' - - -SHAPE_SPHERE=0 -SHAPE_BOX=1 -SHAPE_CAPSULE=2 - -RIGIDBODY_KINEMATICS=0 -RIGIDBODY_PHYSICS=1 -RIGIDBODY_PHYSICS_WITH_BONE=2 - - -class RigidBody(object): - __slots__=['_name', 'boneIndex', 'group', 'target', 'shapeType', - 'w', 'h', 'd', 'position', 'rotation', 'weight', - 'linearDamping', 'angularDamping', 'restitution', 'friction', 'processType' - ] - def getName(self): return from_str(self._name) - def setName(self, name): self._name=to_str(name) - name=property(getName, setName) - - def __init__(self, name): - self.name=name - self.position=Vector3() - self.rotation=Vector3() - - -class Constraint(object): - __slots__=[ '_name', 'rigidA', 'rigidB', 'pos', 'rot', - 'constraintPosMin', 'constraintPosMax', - 'constraintRotMin', 'constraintRotMax', - 'springPos', 'springRot', - ] - def getName(self): return from_str(self._name) - def setName(self, name): self._name=to_str(name) - name=property(getName, setName) - - def __init__(self, name): - self.name=name - self.pos=Vector3() - self.rot=Vector3() - self.constraintPosMin=Vector3() - self.constraintPosMax=Vector3() - self.constraintRotMin=Vector3() - self.constraintRotMax=Vector3() - self.springPos=Vector3() - self.springRot=Vector3() - - -class ToonTextures(object): - __slots__=['_toon_textures'] - def __init__(self): - self._toon_textures=[] - for i in range(10): - self._toon_textures.append('toon%02d.bmp' % (i+1)) - - def __getitem__(self, key): - return from_str(self._toon_textures[key]) - - def __setitem__(self, key, value): - self._toon_textures[key]=to_str(value) - - def __iter__(self): - for toon_texture in self._toon_textures: - yield from_str(toon_texture) - - -class IO(object): - """pmd loader class. - - Attributes: - io: internal use. - end: internal use. - pos: internal user. - - version: pmd version number - _name: internal - """ - __slots__=['io', 'end', 'pos', - 'version', '_name', '_comment', - '_english_name', '_english_comment', - 'vertices', 'indices', 'materials', 'bones', - 'ik_list', 'morph_list', - 'face_list', 'bone_group_list', 'bone_display_list', - 'toon_textures', - 'no_parent_bones', - 'rigidbodies', 'constraints', - ] - def getName(self): return from_str(self._name) - def setName(self, name): self._name=to_str(name) - name=property(getName, setName) - def getEnglishName(self): return from_str(self._english_name) - def setEnglishName(self, english_name): self._english_name=to_str(english_name) - english_name=property(getEnglishName, setEnglishName) - def getComment(self): return from_str(self._comment) - def setComment(self, comment): self._comment=to_str(comment) - comment=property(getComment, setComment) - def getEnglishComment(self): return from_str(self._english_comment) - def setEnglishComment(self, english_comment): self._english_comment=to_str(english_comment) - english_comment=property(getEnglishComment, setEnglishComment) - - def __init__(self): - self.version=1.0 - self.name='' - self.comment='' - self.english_name='' - self.english_comment='' - self.vertices=[] - self.indices=[] - self.materials=[] - self.bones=[] - self.ik_list=[] - self.morph_list=[] - self.face_list=[] - self.bone_group_list=[] - self.bone_display_list=[] - # extend - self.toon_textures=ToonTextures() - self.rigidbodies=[] - self.constraints=[] - # innner use - self.no_parent_bones=[] - - def each_vertex(self): return self.vertices - def getUV(self, i): return self.vertices[i].uv - def addVertex(self): - v=Vertex() - self.vertices.append(v) - return v - def addMaterial(self): - m=Material() - self.materials.append(m) - return m - def addBone(self): - b=Bone() - self.bones.append(b) - return b - def addIK(self): - ik=IK() - self.ik_list.append(ik) - return ik - def addMorph(self): - s=Skin() - self.morph_list.append(s) - return s - def addBoneGroup(self): - g=BoneGroup() - self.bone_group_list.append(g) - return g - def addBoneDisplay(self, b, g): - self.bone_display_list.append((b, g)) - - def __str__(self): - return '' % ( - self.version, self.name, len(self.vertices), len(self.indices), - len(self.materials), len(self.bones), len(self.ik_list), len(self.morph_list)) - - def _check_position(self): - self.pos=self.io.tell() - - def read(self, path): - size=os.path.getsize(path) - with open(path, "rb") as f: - return self.load(path, f, size) - - def load(self, path, io, end): - self.io=io - self.pos=self.io.tell() - self.end=end - self._check_position() - - if not self._loadHeader(): - return False - self._check_position() - - if not self._loadVertex(): - return False - self._check_position() - - if not self._loadFace(): - return False - self._check_position() - - if not self._loadMaterial(): - return False - self._check_position() - - if not self._loadBone(): - return False - self._check_position() - - if not self._loadIK(): - return False - self._check_position() - - if not self._loadSkin(): - return False - self._check_position() - - if not self._loadSkinIndex(): - return False - self._check_position() - - if not self._loadBoneName(): - return False - self._check_position() - - if not self._loadBoneIndex(): - return False - self._check_position() - - if not self._loadExtend(): - print('fail to loadExtend') - return False - - # 終端 - if self.io.tell()!=self.end: - print("can not reach eof.") - print("current: %d, end: %d, remain: %d" % ( - self.io.tell(), self.end, self.end-self.io.tell())) - - # build bone tree - for i, child in enumerate(self.bones): - if child.parent_index==0xFFFF: - # no parent - self.no_parent_bones.append(child) - child.parent=None - else: - # has parent - parent=self.bones[child.parent_index] - child.parent=parent - parent.children.append(child) - # 後位置 - if child.hasChild(): - child.tail=self.bones[child.tail_index].pos - - return True - - def write(self, path): - io=open(path, 'wb') - if not io: - return False - # Header - io.write(b"Pmd") - io.write(struct.pack("f", self.version)) - io.write(struct.pack("20s", self.name)) - io.write(struct.pack("256s", self.comment)) - - # Vertices - io.write(struct.pack("I", len(self.vertices))) - sVertex=struct.Struct("=8f2H2B") # 38byte - assert(sVertex.size==38) - for v in self.vertices: - data=sVertex.pack( - v.pos[0], v.pos[1], v.pos[2], - v.normal[0], v.normal[1], v.normal[2], - v.uv[0], v.uv[1], - v.bone0, v.bone1, v.weight0, v.edge_flag) - io.write(data) - - # Faces - io.write(struct.pack("I", len(self.indices))) - io.write(struct.pack("=%dH" % len(self.indices), *self.indices)) - - # material - io.write(struct.pack("I", len(self.materials))) - sMaterial=struct.Struct("=3fff3f3fBBI20s") # 70byte - assert(sMaterial.size==70) - for m in self.materials: - io.write(sMaterial.pack( - m.diffuse[0], m.diffuse[1], m.diffuse[2], m.diffuse[3], - m.shinness, - m.specular[0], m.specular[1], m.specular[2], - m.ambient[0], m.ambient[1], m.ambient[2], - m.toon_index, m.flag, - m.vertex_count, - m.texture - )) - - # bone - io.write(struct.pack("H", len(self.bones))) - sBone=struct.Struct("=20sHHBH3f") - assert(sBone.size==39) - for b in self.bones: - io.write(sBone.pack( - b.name, - b.parent_index, b.tail_index, b.type, b.ik_index, - b.pos[0], b.pos[1], b.pos[2])) - - # IK - io.write(struct.pack("H", len(self.ik_list))) - for ik in self.ik_list: - io.write(struct.pack("=2HBHf", - ik.index, ik.target, ik.length, ik.iterations, ik.weight - )) - for c in ik.children: - io.write(struct.pack("H", c)) - - # skin - io.write(struct.pack("H", len(self.morph_list))) - for s in self.morph_list: - io.write(struct.pack("20sIB", - s.name, len(s.indices), s.type)) - for i, v in zip(s.indices, s.pos_list): - io.write(struct.pack("I3f", i, v[0], v[1], v[2])) - - # skin disp list - io.write(struct.pack("B", len(self.face_list))) - for i in self.face_list: - io.write(struct.pack("H", i)) - - # bone disp list - io.write(struct.pack("B", len(self.bone_group_list))) - for g in self.bone_group_list: - io.write(struct.pack("50s", g.name)) - - io.write(struct.pack("I", len(self.bone_display_list))) - for l in self.bone_display_list: - io.write(struct.pack("=HB", *l)) - - ############################################################ - # extend data - ############################################################ - io.write(struct.pack("B", 1)) - # english name - io.write(struct.pack("=20s", self.english_name)) - io.write(struct.pack("=256s", self.english_comment)) - # english bone name - for bone in self.bones: - io.write(struct.pack("=20s", bone.english_name)) - # english skin list - for skin in self.morph_list: - #print(skin.name) - if skin.name==b'base': - continue - io.write(struct.pack("=20s", skin.english_name)) - # english bone list - for bone_group in self.bone_group_list: - io.write(struct.pack("50s", bone_group.english_name)) - # toon texture - for toon_texture in self.toon_textures: - io.write(struct.pack("=100s", toon_texture)) - # rigid - io.write(struct.pack("I", len(self.rigidbodies))) - for r in self.rigidbodies: - io.write(struct.pack("=20sHBHB14fB", - r.name, r.boneIndex, r.group, r.target, r.shapeType, - r.w, r.h, r.d, - r.position.x, r.position.y, r.position.z, - r.rotation.x, r.rotation.y, r.rotation.z, - r.weight, - r.linearDamping, r.angularDamping, r.restitution, - r.friction, r.processType)) - - # constraint - io.write(struct.pack("I", len(self.constraints))) - for c in self.constraints: - io.write(struct.pack("=20sII24f", - c.name, c.rigidA, c.rigidB, - c.pos.x, c.pos.y, c.pos.z, - c.rot.x, c.rot.y, c.rot.z, - c.constraintPosMin.x, c.constraintPosMin.y, c.constraintPosMin.z, - c.constraintPosMax.x, c.constraintPosMax.y, c.constraintPosMax.z, - c.constraintRotMin.x, c.constraintRotMin.y, c.constraintRotMin.z, - c.constraintRotMax.x, c.constraintRotMax.y, c.constraintRotMax.z, - c.springPos.x, c.springPos.y, c.springPos.z, - c.springRot.x, c.springRot.y, c.springRot.z - )) - - return True - - - def _loadExtend(self): - ############################################################ - # extend1: english name - ############################################################ - if self.io.tell()>=self.end: - return True - if struct.unpack("B", self.io.read(1))[0]==1: - if not self.loadEnglishName(): - return False - self._check_position() - - ############################################################ - # extend2: toon texture list - ############################################################ - if self.io.tell()>=self.end: - return True - if not self.loadToonTexture(): - return False - self._check_position() - - ############################################################ - # extend3: physics - ############################################################ - if self.io.tell()>=self.end: - return True - if not self.loadPhysics(): - return False - self._check_position() - - return True - - def _loadHeader(self): - signature=struct.unpack("3s", self.io.read(3))[0] - if signature!=b"Pmd": - print("invalid signature", signature) - return False - self.version=struct.unpack("f", self.io.read(4))[0] - self.name = truncate_zero(struct.unpack("20s", self.io.read(20))[0]) - self.comment = truncate_zero( - struct.unpack("256s", self.io.read(256))[0]) - return True - - def _loadVertex(self): - count = struct.unpack("I", self.io.read(4))[0] - for i in range(count): - self.vertices.append(Vertex(*struct.unpack("8f2H2B", self.io.read(38)))) - return True - - def _loadFace(self): - count = struct.unpack("I", self.io.read(4))[0] - for i in range(0, count, 3): - self.indices+=struct.unpack("HHH", self.io.read(6)) - return True - - def _loadMaterial(self): - count = struct.unpack("I", self.io.read(4))[0] - for i in range(count): - material=Material(*struct.unpack("4ff3f3f", self.io.read(44))) - material.toon_index=struct.unpack("B", self.io.read(1))[0] - material.flag=struct.unpack("B", self.io.read(1))[0] - material.vertex_count=struct.unpack("I", self.io.read(4))[0] - texture=truncate_zero(struct.unpack("20s", self.io.read(20))[0]) - # todo sphere map - #material.texture=texture.split('*')[0] - material.texture=texture - self.materials.append(material) - return True - - def _loadBone(self): - size = struct.unpack("H", self.io.read(2))[0] - for i in range(size): - name=truncate_zero(struct.unpack("20s", self.io.read(20))[0]) - parent_index, tail_index = struct.unpack("HH", self.io.read(4)) - type = struct.unpack("B", self.io.read(1))[0] - bone=createBone(name, type) - bone.parent_index=parent_index - bone.tail_index=tail_index - bone.ik_index = struct.unpack("H", self.io.read(2))[0] - bone.pos = Vector3(*struct.unpack("3f", self.io.read(12))) - bone.english_name="bone%03d" % len(self.bones) - self.bones.append(bone) - return True - - def _loadIK(self): - size = struct.unpack("H", self.io.read(2))[0] - for i in range(size): - ik=IK(*struct.unpack("2H", self.io.read(4))) - ik.length = struct.unpack("B", self.io.read(1))[0] - ik.iterations = struct.unpack("H", self.io.read(2))[0] - ik.weight = struct.unpack("f", self.io.read(4))[0] - for j in range(ik.length): - ik.children.append(struct.unpack("H", self.io.read(2))[0]) - self.ik_list.append(ik) - return True - - def _loadSkin(self): - size = struct.unpack("H", self.io.read(2))[0] - for i in range(size): - skin=Skin(truncate_zero(struct.unpack("20s", self.io.read(20))[0])) - skin_size = struct.unpack("I", self.io.read(4))[0] - skin.type = struct.unpack("B", self.io.read(1))[0] - for j in range(skin_size): - skin.indices.append(struct.unpack("I", self.io.read(4))[0]) - skin.pos_list.append( - Vector3(*struct.unpack("3f", self.io.read(12)))) - skin.english_name="skin%03d" % len(self.morph_list) - self.morph_list.append(skin) - return True - - def _loadSkinIndex(self): - size = struct.unpack("B", self.io.read(1))[0] - for i in range(size): - self.face_list.append(struct.unpack("H", self.io.read(2))[0]) - return True - - def _loadBoneName(self): - size = struct.unpack("B", self.io.read(1))[0] - for i in range(size): - self.bone_group_list.append(BoneGroup( - truncate_zero(struct.unpack("50s", self.io.read(50))[0]))) - return True - - def _loadBoneIndex(self): - size = struct.unpack("I", self.io.read(4))[0] - for i in range(size): - first=struct.unpack("H", self.io.read(2))[0] - second=struct.unpack("B", self.io.read(1))[0] - self.bone_display_list.append((first, second)) - return True - - def loadToonTexture(self): - """ - 100bytex10 - """ - for i in range(10): - self.toon_textures[i]=truncate_zero(struct.unpack("100s", self.io.read(100))[0]) - return True - - def loadEnglishName(self): - # english name - self.english_name=truncate_zero( - struct.unpack("20s", self.io.read(20))[0]) - self.english_comment=truncate_zero( - struct.unpack("256s", self.io.read(256))[0]) - self._check_position() - # english bone name - for bone in self.bones: - english_name=truncate_zero( - struct.unpack("20s", self.io.read(20))[0]) - bone.english_name=english_name - self._check_position() - # english skin list - for skin in self.morph_list: - if skin.name==b'base': - continue - english_name=truncate_zero( - struct.unpack("20s", self.io.read(20))[0]) - #skin=self.morph_list[index] - if english_name!=skin.name: - skin.english_name=english_name - self._check_position() - # english bone list - for i in range(0, len(self.bone_group_list)): - self.bone_group_list[i].english_name=truncate_zero( - struct.unpack("50s", self.io.read(50))[0]) - self._check_position() - return True - - def loadPhysics(self): - # 剛体リスト - count = struct.unpack("I", self.io.read(4))[0] - for i in range(count): - name=truncate_zero(struct.unpack("20s", self.io.read(20))[0]) - rigidbody=RigidBody(name) - rigidbody.boneIndex=struct.unpack("H", self.io.read(2))[0] - rigidbody.group=struct.unpack("B", self.io.read(1))[0] - rigidbody.target=struct.unpack("H", self.io.read(2))[0] - rigidbody.shapeType=struct.unpack("B", self.io.read(1))[0] - rigidbody.w=struct.unpack("f", self.io.read(4))[0] - rigidbody.h=struct.unpack("f", self.io.read(4))[0] - rigidbody.d=struct.unpack("f", self.io.read(4))[0] - rigidbody.position.x=struct.unpack("f", self.io.read(4))[0] - rigidbody.position.y=struct.unpack("f", self.io.read(4))[0] - rigidbody.position.z=struct.unpack("f", self.io.read(4))[0] - rigidbody.rotation.x=struct.unpack("f", self.io.read(4))[0] - rigidbody.rotation.y=struct.unpack("f", self.io.read(4))[0] - rigidbody.rotation.z=struct.unpack("f", self.io.read(4))[0] - rigidbody.weight=struct.unpack("f", self.io.read(4))[0] - rigidbody.linearDamping=struct.unpack("f", self.io.read(4))[0] - rigidbody.angularDamping=struct.unpack("f", self.io.read(4))[0] - rigidbody.restitution=struct.unpack("f", self.io.read(4))[0] - rigidbody.friction=struct.unpack("f", self.io.read(4))[0] - rigidbody.processType=struct.unpack("B", self.io.read(1))[0] - self.rigidbodies.append(rigidbody) - self._check_position() - - # ジョイントリスト - count = struct.unpack("I", self.io.read(4))[0] - for i in range(count): - name=truncate_zero(struct.unpack("20s", self.io.read(20))[0]) - constraint=Constraint(name) - constraint.rigidA=struct.unpack("I", self.io.read(4))[0] - constraint.rigidB=struct.unpack("I", self.io.read(4))[0] - constraint.pos.x=struct.unpack("f", self.io.read(4))[0] - constraint.pos.y=struct.unpack("f", self.io.read(4))[0] - constraint.pos.z=struct.unpack("f", self.io.read(4))[0] - constraint.rot.x=struct.unpack("f", self.io.read(4))[0] - constraint.rot.y=struct.unpack("f", self.io.read(4))[0] - constraint.rot.z=struct.unpack("f", self.io.read(4))[0] - constraint.constraintPosMin.x=struct.unpack("f", self.io.read(4))[0] - constraint.constraintPosMin.y=struct.unpack("f", self.io.read(4))[0] - constraint.constraintPosMin.z=struct.unpack("f", self.io.read(4))[0] - constraint.constraintPosMax.x=struct.unpack("f", self.io.read(4))[0] - constraint.constraintPosMax.y=struct.unpack("f", self.io.read(4))[0] - constraint.constraintPosMax.z=struct.unpack("f", self.io.read(4))[0] - constraint.constraintRotMin.x=struct.unpack("f", self.io.read(4))[0] - constraint.constraintRotMin.y=struct.unpack("f", self.io.read(4))[0] - constraint.constraintRotMin.z=struct.unpack("f", self.io.read(4))[0] - constraint.constraintRotMax.x=struct.unpack("f", self.io.read(4))[0] - constraint.constraintRotMax.y=struct.unpack("f", self.io.read(4))[0] - constraint.constraintRotMax.z=struct.unpack("f", self.io.read(4))[0] - constraint.springPos.x=struct.unpack("f", self.io.read(4))[0] - constraint.springPos.y=struct.unpack("f", self.io.read(4))[0] - constraint.springPos.z=struct.unpack("f", self.io.read(4))[0] - constraint.springRot.x=struct.unpack("f", self.io.read(4))[0] - constraint.springRot.y=struct.unpack("f", self.io.read(4))[0] - constraint.springRot.z=struct.unpack("f", self.io.read(4))[0] - self.constraints.append(constraint) - self._check_position() - - return True - diff --git a/pymeshio/pmd/__init__.py b/pymeshio/pmd/__init__.py new file mode 100644 index 0000000..c365c07 --- /dev/null +++ b/pymeshio/pmd/__init__.py @@ -0,0 +1,459 @@ +# coding: utf-8 +""" +PMDの読み込み +http://blog.goo.ne.jp/torisu_tetosuki/e/209ad341d3ece2b1b4df24abf619d6e4 +""" +import os +import sys +import struct +import warnings +import pymeshio.common + + +class Vertex(object): + """pmd vertex struct. + + Attributes: + pos: Vector3 + normal: Vector3 + uv: Vector2 + bone0: bone index + bone1: bone index + weight0: bone0 influence + edge_flag: int flag + """ + __slots__=['pos', 'normal', 'uv', 'bone0', 'bone1', 'weight0', 'edge_flag'] + def __init__(self, pos, normal, uv, + bone0, bone1, weight0, edge_flag): + self.pos=pos + self.normal=normal + self.uv=uv + self.bone0=bone0 + self.bone1=bone1 + self.weight0=weight0 + self.edge_flag=edge_flag + + def __str__(self): + return "<%s %s %s, (%d, %d, %d)>" % ( + str(self.pos), + str(self.normal), + str(self.uv), + self.bone0, self.bone1, self.weight0) + + def __getitem__(self, key): + if key==0: + return self.pos.x + elif key==1: + return self.pos.y + elif key==2: + return self.pos.z + else: + assert(False) + + +class Material(object): + """pmd material struct. + + Attributes: + diffuse_color: RGB + alpha: float + specular_factor: float + specular_color: RGB + ambient_color: RGB + toon_index: int + edge_flag: int + vertex_count: indices length + texture_file: texture file path + """ + __slots__=[ + 'diffuse_color', 'alpha', + 'specular_factor', 'specular_color', 'ambient_color', + 'toon_index', 'edge_flag', + 'vertex_count', 'texture_file', + ] + def __init__(self, diffuse_color, alpha, + specular_factor, specular_color, ambient_color, + toon_index, edge_flag, vertex_count, texture_file): + self.diffuse_color=diffuse_color + self.alpha=alpha + self.specular_factor=specular_factor + self.specular_color=specular_color + self.ambient_color=ambient_color + self.toon_index=toon_index + self.edge_flag=edge_flag + self.vertex_count=vertex_count + self.texture_file=texture_file + + def __str__(self): + return "" % ( + self.diffuse[0], self.diffuse[1], + self.diffuse[2], self.diffuse[3], + ) + + +class Bone(object): + """pmd material struct. + + Attributes: + _name: + index: + type: + ik: + pos: + _english_name: + ik_index: + parent_index: + tail_index: + + parent: + tail: + children: + """ + # kinds + ROTATE = 0 + ROTATE_MOVE = 1 + IK = 2 + IK_ROTATE_INFL = 4 + ROTATE_INFL = 5 + IK_TARGET = 6 + UNVISIBLE = 7 + # since v4.0 + ROLLING=8 # ? + TWEAK=9 + __slots__=['name', 'index', 'type', 'parent', 'ik', 'pos', + 'children', 'english_name', 'ik_index', + 'parent_index', 'tail_index', 'tail', + ] + def __init__(self, name=b'bone', type=0): + self.name=name + self.index=0 + self.type=type + self.parent_index=0xFFFF + self.tail_index=0 + self.tail=pymeshio.common.Vector3(0, 0, 0) + self.parent=None + self.ik_index=0xFFFF + self.pos=pymeshio.common.Vector3(0, 0, 0) + self.children=[] + self.english_name='' + + def hasParent(self): + return self.parent_index!=0xFFFF + + def hasChild(self): + return self.tail_index!=0 + + def display(self, indent=[]): + if len(indent)>0: + prefix='' + for i, is_end in enumerate(indent): + if i==len(indent)-1: + break + else: + prefix+=' ' if is_end else ' |' + uni='%s +%s(%s)' % (prefix, unicode(self), self.english_name) + print(uni.encode(ENCODING)) + else: + uni='%s(%s)' % (unicode(self), self.english_name) + print(uni.encode(ENCODING)) + + child_count=len(self.children) + for i in range(child_count): + child=self.children[i] + if i' % (self.name) +# 1 +class Bone_RotateMove(Bone): + __slots__=[] + def __init__(self, name): + super(Bone_RotateMove, self).__init__(name, 1) + def __str__(self): + return '' % (self.name) +# 2 +class Bone_IK(Bone): + __slots__=[] + def __init__(self, name): + super(Bone_IK, self).__init__(name, 2) + def __str__(self): + return '' % (self.name) +# 4 +class Bone_IKRotateInfl(Bone): + __slots__=[] + def __init__(self, name): + super(Bone_IKRotateInfl, self).__init__(name, 4) + def __str__(self): + return '' % (self.name) +# 5 +class Bone_RotateInfl(Bone): + __slots__=[] + def __init__(self, name): + super(Bone_RotateInfl, self).__init__(name, 5) + def __str__(self): + return '' % (self.name) +# 6 +class Bone_IKTarget(Bone): + __slots__=[] + def __init__(self, name): + super(Bone_IKTarget, self).__init__(name, 6) + def __str__(self): + return '' % (self.name) +# 7 +class Bone_Unvisible(Bone): + __slots__=[] + def __init__(self, name): + super(Bone_Unvisible, self).__init__(name, 7) + def __str__(self): + return '' % (self.name) +# 8 +class Bone_Rolling(Bone): + __slots__=[] + def __init__(self, name): + super(Bone_Rolling, self).__init__(name, 8) + def __str__(self): + return '' % (self.name) +# 9 +class Bone_Tweak(Bone): + __slots__=[] + def __init__(self, name): + super(Bone_Tweak, self).__init__(name, 9) + def __str__(self): + return '' % (self.name) + + +def createBone(name, type): + if type==0: + return Bone_Rotate(name) + elif type==1: + return Bone_RotateMove(name) + elif type==2: + return Bone_IK(name) + elif type==3: + raise Exception("no used bone type: 3(%s)" % name) + elif type==4: + return Bone_IKRotateInfl(name) + elif type==5: + return Bone_RotateInfl(name) + elif type==6: + return Bone_IKTarget(name) + elif type==7: + return Bone_Unvisible(name) + elif type==8: + return Bone_Rolling(name) + elif type==9: + return Bone_Tweak(name) + else: + raise Exception("unknown bone type: %d(%s)", type, name) + + +class IK(object): + __slots__=['index', 'target', 'iterations', 'weight', 'length', 'children'] + def __init__(self, index=0, target=0): + self.index=index + self.target=target + self.iterations=None + self.weight=None + self.children=[] + + def __str__(self): + return "" %(self.index, self.target, self.iterations, self.weight, '-'.join([str(i) for i in self.children]), len(self.children)) + + +class Skin(object): + __slots__=['name', 'type', 'indices', 'pos_list', 'english_name', + 'vertex_count'] + def __init__(self, name='skin'): + self.name=name + self.type=None + self.indices=[] + self.pos_list=[] + self.english_name='' + self.vertex_count=0 + + def append(self, index, x, y, z): + self.indices.append(index) + self.pos_list.append(Vector3(x, y, z)) + + def __str__(self): + return '' % ( + self.name, self.type, len(self.indices)) + + +class BoneGroup(object): + __slots__=['_name', '_english_name'] + def __init__(self, name='group'): self._name=name; self._english_name='center' + + +SHAPE_SPHERE=0 +SHAPE_BOX=1 +SHAPE_CAPSULE=2 + +RIGIDBODY_KINEMATICS=0 +RIGIDBODY_PHYSICS=1 +RIGIDBODY_PHYSICS_WITH_BONE=2 + + +class RigidBody(object): + __slots__=['name', + 'bone_index', + 'collision_group', + 'no_collision_group', + 'shape_type', + 'shape_size', + 'shape_position', + 'shape_rotation', + 'mass', + 'linear_damping', + 'angular_damping', + 'restitution', + 'friction', + 'mode' + ] + def __init__(self, name, + bone_index, + collision_group, + no_collision_group, + shape_type, + shape_size, + shape_position, + shape_rotation, + mass, + linear_damping, + angular_damping, + restitution, + friction, + mode + ): + self.name=name + self.bone_index=bone_index + self.collision_group=collision_group + self.no_collision_group=no_collision_group + self.shape_type=shape_type + self.shape_size=shape_size + self.shape_position=shape_position + self.shape_rotation=shape_rotation + self.mass=mass + self.linear_damping=linear_damping + self.angular_damping=angular_damping + self.restitution=restitution + self.friction=friction + self.mode=mode + + +class Joint(object): + __slots__=[ 'name', 'rigidbody_index_a', 'rigidbody_index_b', + 'position', 'rotation', + 'translation_limit_max', 'translation_limit_min', + 'rotation_limit_max', 'rotation_limit_min', + 'spring_constant_translation', 'spring_constant_rotation', + ] + def __init__(self, name, + rigidbody_index_a, rigidbody_index_b, + position, rotation, + translation_limit_max, translation_limit_min, + rotation_limit_max, rotation_limit_min, + spring_constant_translation, spring_constant_rotation + ): + self.name=name + self.rigidbody_index_a=rigidbody_index_a + self.rigidbody_index_b=rigidbody_index_b + self.position=position + self.rotation=rotation + self.translation_limit_max=translation_limit_max + self.translation_limit_min=translation_limit_min + self.rotation_limit_max=rotation_limit_max + self.rotation_limit_min=rotation_limit_min + self.spring_constant_translation=spring_constant_translation + self.spring_constant_rotation=spring_constant_rotation + + +class ToonTextures(object): + __slots__=['_toon_textures'] + def __init__(self): + self._toon_textures=[] + for i in range(10): + self._toon_textures.append('toon%02d.bmp' % (i+1)) + + def __getitem__(self, key): + return from_str(self._toon_textures[key]) + + def __setitem__(self, key, value): + self._toon_textures[key]=to_str(value) + + def __iter__(self): + for toon_texture in self._toon_textures: + yield from_str(toon_texture) + + +class Model(object): + """pmd loader class. + + Attributes: + io: internal use. + end: internal use. + pos: internal user. + + version: pmd version number + _name: internal + """ + __slots__=[ + 'version', 'name', 'comment', + 'english_name', 'english_comment', + 'vertices', 'indices', 'materials', 'bones', + 'ik_list', 'morphs', + 'morph_indices', 'bone_group_list', 'bone_display_list', + 'toon_textures', + 'no_parent_bones', + 'rigidbodies', 'joints', + ] + def __init__(self, version): + self.version=version + self.name=b'' + self.comment=b'' + self.english_name=b'' + self.english_comment=b'' + self.vertices=[] + self.indices=[] + self.materials=[] + self.bones=[] + self.ik_list=[] + self.morphs=[] + self.morph_indices=[] + self.bone_group_list=[] + self.bone_display_list=[] + # extend + self.toon_textures=ToonTextures() + self.rigidbodies=[] + self.joints=[] + # innner use + self.no_parent_bones=[] + + def each_vertex(self): return self.vertices + def getUV(self, i): return self.vertices[i].uv + + def __str__(self): + return '' % ( + self.version, self.name, len(self.vertices), len(self.indices), + len(self.materials), len(self.bones), len(self.ik_list), len(self.morph_list)) + + +class IO(object): + def __init__(self): + pass + + def read(self, path): + warnings.warn("'pymeshio.mqo.IO.read' will be replaced by 'pymeshio.mqo.loader.load'") + model=pymeshio.pmd.loader.load(path) + if model: + return True + diff --git a/pymeshio/pmd/loader.py b/pymeshio/pmd/loader.py new file mode 100644 index 0000000..c897f22 --- /dev/null +++ b/pymeshio/pmd/loader.py @@ -0,0 +1,348 @@ +#coding: utf-8 +import io +import pymeshio.common +import pymeshio.pmd + + +class Loader(pymeshio.common.BinaryLoader): + """pmx loader + """ + def __init__(self, io, version): + super(Loader, self).__init__(io) + self.version=version + + def read_text(self, size): + """read cp932 text + """ + src=self.unpack("%ds" % size, size) + assert(type(src)==bytes) + pos = src.find(b"\x00") + if pos==-1: + return src + else: + return src[:pos] + + def read_vertex(self): + return pymeshio.pmd.Vertex( + self.read_vector3(), + self.read_vector3(), + self.read_vector2(), + self.read_uint(2), + self.read_uint(2), + self.read_uint(1), + self.read_uint(1)) + + def read_material(self): + return pymeshio.pmd.Material( + diffuse_color=self.read_rgb(), + alpha=self.read_float(), + specular_factor=self.read_float(), + specular_color=self.read_rgb(), + ambient_color=self.read_rgb(), + toon_index=self.read_uint(1), + edge_flag=self.read_uint(1), + vertex_count=self.read_uint(4), + texture_file=self.read_text(20) + ) + + def read_bone(self): + name=self.read_text(20) + parent_index=self.read_uint(2) + tail_index=self.read_uint(2) + bone=pymeshio.pmd.createBone(name, self.read_uint(1)) + bone.parent_index=parent_index + bone.tail_index=tail_index + bone.ik_index = self.read_uint(2) + bone.pos = self.read_vector3() + return bone + + def read_ik(self): + ik=pymeshio.pmd.IK(self.read_uint(2), self.read_uint(2)) + ik.length = self.read_uint(1) + ik.iterations = self.read_uint(2) + ik.weight = self.read_float() + ik.children=[self.read_uint(2) for _ in range(ik.length)] + return ik + + def read_morph(self): + skin=pymeshio.pmd.Skin(self.read_text(20)) + skin_size = self.read_uint(4) + skin.type = self.read_uint(1) + for j in range(skin_size): + skin.indices.append(self.read_uint(4)) + skin.pos_list.append(self.read_vector3()) + return skin + + def read_rigidbody(self): + return pymeshio.pmd.RigidBody( + name=self.read_text(20), + bone_index=self.read_uint(2), + collision_group=self.read_uint(1), + no_collision_group=self.read_uint(2), + shape_type=self.read_uint(1), + shape_size=self.read_vector3(), + shape_position=self.read_vector3(), + shape_rotation=self.read_vector3(), + mass=self.read_float(), + linear_damping=self.read_float(), + angular_damping=self.read_float(), + restitution=self.read_float(), + friction=self.read_float(), + mode=self.read_uint(1) + ) + + def read_joint(self): + return pymeshio.pmd.Joint( + name=self.read_text(20), + rigidbody_index_a=self.read_uint(4), + rigidbody_index_b=self.read_uint(4), + position=self.read_vector3(), + rotation=self.read_vector3(), + translation_limit_min=self.read_vector3(), + translation_limit_max=self.read_vector3(), + rotation_limit_min=self.read_vector3(), + rotation_limit_max=self.read_vector3(), + spring_constant_translation=self.read_vector3(), + spring_constant_rotation=self.read_vector3()) + + + +def __load(loader, model): + # model info + model.name=loader.read_text(20) + model.comment=loader.read_text(256) + + # model data + model.vertices=[loader.read_vertex() + for _ in range(loader.read_uint(4))] + model.indices=[loader.read_uint(2) + for _ in range(loader.read_uint(4))] + model.materials=[loader.read_material() + for _ in range(loader.read_uint(4))] + model.bones=[loader.read_bone() + for _ in range(loader.read_uint(2))] + model.ik_list=[loader.read_ik() + for _ in range(loader.read_uint(2))] + model.morphs=[loader.read_morph() + for _ in range(loader.read_uint(2))] + model.morph_indices=[loader.read_uint(2) + for _ in range(loader.read_uint(1))] + model.bone_group_list=[loader.read_text(50) + for _ in range(loader.read_uint(1))] + model.bone_display_list=[(loader.read_uint(2), loader.read_uint(1)) + for _i in range(loader.read_uint(4))] + + if loader.is_end(): + # EOF + return True + + ############################################################ + # extend1: english name + ############################################################ + if loader.read_uint(1)==0: + print("no extend flag") + return True + model.english_name=loader.read_text(20) + model.english_comment=loader.read_text(256) + for bone in model.bones: + bone.english_name=loader.read_text(20) + for morph in model.morphs: + if morph.name==b'base': + continue + morph.english_name=loader.read_text(20) + for bone_group in model.bone_group_list: + bone_group=loader.read_text(50) + + ############################################################ + # extend2: toon_textures + ############################################################ + if loader.is_end(): + # EOF + return True + model.toon_textures=[loader.read_text(100) + for _ in range(10)] + + ############################################################ + # extend2: rigidbodies and joints + ############################################################ + if loader.is_end(): + # EOF + return True + model.rigidbodies=[loader.read_rigidbody() + for _ in range(loader.read_uint(4))] + model.joints=[loader.read_joint() + for _ in range(loader.read_uint(4))] + + return True + + +def load(path): + # general binary loader + #loader=pymeshio.common.BinaryLoader(open(path, 'rb')) + loader=pymeshio.common.BinaryLoader(io.BytesIO(pymeshio.common.readall(path))) + + # header + signature=loader.unpack("3s", 3) + if signature!=b"Pmd": + raise pymeshio.common.ParseException( + "invalid signature: {0}".format(signature)) + version=loader.read_float() + + model=pymeshio.pmd.Model(version) + loader=Loader(loader.io, version) + if(__load(loader, model)): + # check eof + if not loader.is_end(): + print("can not reach eof.") + + # build bone tree + for i, child in enumerate(model.bones): + if child.parent_index==0xFFFF: + # no parent + model.no_parent_bones.append(child) + child.parent=None + else: + # has parent + parent=model.bones[child.parent_index] + child.parent=parent + parent.children.append(child) + # ŒãˆÊ’u + if child.hasChild(): + child.tail=model.bones[child.tail_index].pos + + return model + + +def save(self, path): + io=open(path, 'wb') + if not io: + return False + # Header + io.write(b"Pmd") + io.write(struct.pack("f", self.version)) + io.write(struct.pack("20s", self.name)) + io.write(struct.pack("256s", self.comment)) + + # Vertices + io.write(struct.pack("I", len(self.vertices))) + sVertex=struct.Struct("=8f2H2B") # 38byte + assert(sVertex.size==38) + for v in self.vertices: + data=sVertex.pack( + v.pos[0], v.pos[1], v.pos[2], + v.normal[0], v.normal[1], v.normal[2], + v.uv[0], v.uv[1], + v.bone0, v.bone1, v.weight0, v.edge_flag) + io.write(data) + + # Faces + io.write(struct.pack("I", len(self.indices))) + io.write(struct.pack("=%dH" % len(self.indices), *self.indices)) + + # material + io.write(struct.pack("I", len(self.materials))) + sMaterial=struct.Struct("=3fff3f3fBBI20s") # 70byte + assert(sMaterial.size==70) + for m in self.materials: + io.write(sMaterial.pack( + m.diffuse[0], m.diffuse[1], m.diffuse[2], m.diffuse[3], + m.shinness, + m.specular[0], m.specular[1], m.specular[2], + m.ambient[0], m.ambient[1], m.ambient[2], + m.toon_index, m.flag, + m.vertex_count, + m.texture + )) + + # bone + io.write(struct.pack("H", len(self.bones))) + sBone=struct.Struct("=20sHHBH3f") + assert(sBone.size==39) + for b in self.bones: + io.write(sBone.pack( + b.name, + b.parent_index, b.tail_index, b.type, b.ik_index, + b.pos[0], b.pos[1], b.pos[2])) + + # IK + io.write(struct.pack("H", len(self.ik_list))) + for ik in self.ik_list: + io.write(struct.pack("=2HBHf", + ik.index, ik.target, ik.length, ik.iterations, ik.weight + )) + for c in ik.children: + io.write(struct.pack("H", c)) + + # skin + io.write(struct.pack("H", len(self.morph_list))) + for s in self.morph_list: + io.write(struct.pack("20sIB", + s.name, len(s.indices), s.type)) + for i, v in zip(s.indices, s.pos_list): + io.write(struct.pack("I3f", i, v[0], v[1], v[2])) + + # skin disp list + io.write(struct.pack("B", len(self.face_list))) + for i in self.face_list: + io.write(struct.pack("H", i)) + + # bone disp list + io.write(struct.pack("B", len(self.bone_group_list))) + for g in self.bone_group_list: + io.write(struct.pack("50s", g.name)) + + io.write(struct.pack("I", len(self.bone_display_list))) + for l in self.bone_display_list: + io.write(struct.pack("=HB", *l)) + + ############################################################ + # extend data + ############################################################ + io.write(struct.pack("B", 1)) + # english name + io.write(struct.pack("=20s", self.english_name)) + io.write(struct.pack("=256s", self.english_comment)) + # english bone name + for bone in self.bones: + io.write(struct.pack("=20s", bone.english_name)) + # english skin list + for skin in self.morph_list: + #print(skin.name) + if skin.name==b'base': + continue + io.write(struct.pack("=20s", skin.english_name)) + # english bone list + for bone_group in self.bone_group_list: + io.write(struct.pack("50s", bone_group.english_name)) + # toon texture + for toon_texture in self.toon_textures: + io.write(struct.pack("=100s", toon_texture)) + # rigid + io.write(struct.pack("I", len(self.rigidbodies))) + for r in self.rigidbodies: + io.write(struct.pack("=20sHBHB14fB", + r.name, r.boneIndex, r.group, r.target, r.shapeType, + r.w, r.h, r.d, + r.position.x, r.position.y, r.position.z, + r.rotation.x, r.rotation.y, r.rotation.z, + r.weight, + r.linearDamping, r.angularDamping, r.restitution, + r.friction, r.processType)) + + # constraint + io.write(struct.pack("I", len(self.constraints))) + for c in self.constraints: + io.write(struct.pack("=20sII24f", + c.name, c.rigidA, c.rigidB, + c.pos.x, c.pos.y, c.pos.z, + c.rot.x, c.rot.y, c.rot.z, + c.constraintPosMin.x, c.constraintPosMin.y, c.constraintPosMin.z, + c.constraintPosMax.x, c.constraintPosMax.y, c.constraintPosMax.z, + c.constraintRotMin.x, c.constraintRotMin.y, c.constraintRotMin.z, + c.constraintRotMax.x, c.constraintRotMax.y, c.constraintRotMax.z, + c.springPos.x, c.springPos.y, c.springPos.z, + c.springRot.x, c.springRot.y, c.springRot.z + )) + + return True + diff --git a/pymeshio/pmx/__init__.py b/pymeshio/pmx/__init__.py index c1614af..d5665dc 100644 --- a/pymeshio/pmx/__init__.py +++ b/pymeshio/pmx/__init__.py @@ -345,7 +345,7 @@ class RigidBody(object): english_name: bone_index: collision_group: - no_collision_flag: + no_collision_group: shape: param: mode: @@ -355,7 +355,7 @@ class RigidBody(object): 'english_name', 'bone_index', 'collision_group', - 'no_collision_flag', + 'no_collision_group', 'shape', 'param', 'mode', @@ -365,7 +365,7 @@ class RigidBody(object): english_name, bone_index, collision_group, - no_collision_flag, + no_collision_group, shape_type, shape_size, shape_position, @@ -381,7 +381,7 @@ class RigidBody(object): self.english_name=english_name self.bone_index=bone_index self.collision_group=collision_group - self.no_collision_flag=no_collision_flag + self.no_collision_group=no_collision_group if shape_type==0: self.shape=SphereShape(shape_size.x) elif shape_type==1: diff --git a/pymeshio/pmx/loader.py b/pymeshio/pmx/loader.py index c578f68..2802b43 100644 --- a/pymeshio/pmx/loader.py +++ b/pymeshio/pmx/loader.py @@ -237,7 +237,7 @@ class Loader(pymeshio.common.BinaryLoader): english_name=self.read_text(), bone_index=self.read_bone_index(), collision_group=self.read_uint(1), - no_collision_flag=self.read_uint(2), + no_collision_group=self.read_uint(2), shape_type=self.read_uint(1), shape_size=self.read_vector3(), shape_position=self.read_vector3(), @@ -279,7 +279,7 @@ def load(path): signature=loader.unpack("4s", 4) if signature!=b"PMX ": raise pymeshio.common.ParseException( - "invalid signature", loader.signature) + "invalid signature", signature) version=loader.read_float() if version!=2.0: diff --git a/test/pmd_test.py b/test/pmd_test.py index 0a8944e..606ca10 100644 --- a/test/pmd_test.py +++ b/test/pmd_test.py @@ -1,9 +1,50 @@ +# coding: utf-8 import pymeshio.pmd +import pymeshio.pmd.loader import sys +import unittest -PMD_FILE="K:/MMD/model/official/miku.pmd" -def test_pmd_load(): +PMD_FILE=u'resources/初音ミクVer2.pmd' + + +def test_old_pmd_load(): io=pymeshio.pmd.IO() assert io.read(PMD_FILE) + +class TestPmd(unittest.TestCase): + + def setUp(self): + pass + + def test_read(self): + model=pymeshio.pmd.loader.load(PMD_FILE) + self.assertEqual(pymeshio.pmd.Model, model.__class__) + self.assertEqual(u'初音ミク'.encode('cp932'), model.name) + self.assertEqual(u'Miku Hatsune'.encode('cp932'), model.english_name) + self.assertEqual(( + u"PolyMo用モデルデータ:初音ミク ver.2.3\n"+ + u"(物理演算対応モデル)\n"+ + u"\n"+ + u"モデリング :あにまさ氏\n"+ + u"データ変換 :あにまさ氏\n"+ + u"Copyright :CRYPTON FUTURE MEDIA, INC").encode('cp932'), + model.comment) + self.assertEqual(( + u"MMD Model: Miku Hatsune ver.2.3\n"+ + u"(Physical Model)\n"+ + u"\n"+ + u"Modeling by Animasa\n"+ + u"Converted by Animasa\n"+ + u"Copyright CRYPTON FUTURE MEDIA, INC").encode('cp932'), + model.english_comment) + self.assertEqual(12354, len(model.vertices)) + self.assertEqual(22961 * 3, len(model.indices)) + print("{0} textures".format(len(model.toon_textures))) + self.assertEqual(17, len(model.materials)) + self.assertEqual(140, len(model.bones)) + self.assertEqual(31, len(model.morphs)) + self.assertEqual(45, len(model.rigidbodies)) + self.assertEqual(27, len(model.joints)) + diff --git a/test/pmd_test.pyc b/test/pmd_test.pyc index 27b54cf..cc09a74 100644 Binary files a/test/pmd_test.pyc and b/test/pmd_test.pyc differ diff --git a/test/pmx_test.py b/test/pmx_test.py index 352cdb2..c8e060a 100644 --- a/test/pmx_test.py +++ b/test/pmx_test.py @@ -6,7 +6,7 @@ import unittest PMX_FILE=u'resources/初音ミクVer2.pmx' -class TestSequenceFunctions(unittest.TestCase): +class TestPmx(unittest.TestCase): def setUp(self): pass