From: ousttrue Date: Thu, 6 Oct 2011 20:39:27 +0000 (+0900) Subject: implement converter X-Git-Url: http://git.osdn.net/view?p=meshio%2Fpymeshio.git;a=commitdiff_plain;h=1a59747c66623ef3b6b66412d25ffc4e613cd893 implement converter --- diff --git a/examples/pmxbuilder.py b/examples/pmxbuilder.py index 44a6907..b2b75c2 100644 --- a/examples/pmxbuilder.py +++ b/examples/pmxbuilder.py @@ -51,7 +51,7 @@ def build(path): m.diffuse_color[0], m.diffuse_color[1], m.diffuse_color[2], - m.diffuse_alpha) + m.alpha) if m.texture_index!=255: texturepath=os.path.join(basedir, model.textures[m.texture_index]) if os.path.isfile(texturepath): diff --git a/pymeshio/__init__.py b/pymeshio/__init__.py index 7921d15..5e4771a 100644 --- a/pymeshio/__init__.py +++ b/pymeshio/__init__.py @@ -1,8 +1,9 @@ +# coding: utf-8 +""" +======================== +pymeshio +======================== -def unicode(src): - import sys - if sys.version_info[0]<3: - return src.decode('utf-8') - else: - return src +3d mesh io library. +""" diff --git a/pymeshio/common.py b/pymeshio/common.py index 7177506..950e2d0 100644 --- a/pymeshio/common.py +++ b/pymeshio/common.py @@ -4,8 +4,21 @@ common utilities. """ import math import struct +import sys +def unicode(src): + """ + literal to unicode for python2 and python3 compatiblity. + + in python2 str to unicode. + in python3 str(as unicode) to str. + """ + if sys.version_info[0]<3: + return src.decode('utf-8') + else: + return src + """ common structures. """ @@ -24,6 +37,9 @@ class Vector2(object): def __eq__(self, rhs): return self.x==rhs.x and self.y==rhs.y + def __ne__(self, rhs): + return not self.__eq__(rhs) + def __getitem__(self, key): if key==0: return self.x @@ -56,6 +72,9 @@ class Vector3(object): def __eq__(self, rhs): return self.x==rhs.x and self.y==rhs.y and self.z==rhs.z + def __ne__(self, rhs): + return not self.__eq__(rhs) + def __getitem__(self, key): if key==0: return self.x @@ -221,6 +240,9 @@ class RGB(object): def __eq__(self, rhs): return self.r==rhs.r and self.g==rhs.g and self.b==rhs.b + def __ne__(self, rhs): + return not self.__eq__(rhs) + def __getitem__(self, key): if key==0: return self.r @@ -246,6 +268,9 @@ class RGBA(object): def __eq__(self, rhs): return self.r==rhs.r and self.g==rhs.g and self.b==rhs.b and self.a==rhs.a + def __ne__(self, rhs): + return not self.__eq__(rhs) + def __getitem__(self, key): if key==0: return self.r @@ -269,6 +294,9 @@ def radian_to_degree(x): class ParseException(Exception): + """ + Exception in reader + """ pass @@ -292,6 +320,16 @@ class BinaryReader(object): result=struct.unpack(fmt, self.ios.read(size)) return result[0] + def read_int(self, size): + if size==1: + return self.unpack("b", size) + if size==2: + return self.unpack("h", size) + if size==4: + return self.unpack("i", size) + print("not reach here") + raise ParseException("invalid int size: "+size) + def read_uint(self, size): if size==1: return self.unpack("B", size) @@ -335,6 +373,9 @@ class BinaryReader(object): class WriteException(Exception): + """ + Exception in writer + """ pass @@ -351,6 +392,16 @@ class BinaryWriter(object): def write_float(self, v): self.ios.write(struct.pack("f", v)) + def write_int(self, v, size): + if size==1: + self.ios.write(struct.pack("b", v)) + elif size==2: + self.ios.write(struct.pack("h", v)) + elif size==4: + self.ios.write(struct.pack("i", v)) + else: + raise WriteError("invalid int uint size") + def write_uint(self, v, size): if size==1: self.ios.write(struct.pack("B", v)) diff --git a/pymeshio/converter.py b/pymeshio/converter.py new file mode 100644 index 0000000..a78f322 --- /dev/null +++ b/pymeshio/converter.py @@ -0,0 +1,328 @@ +# coding: utf-8 +""" +convert model +""" + +import math +from . import common +from . import pmx +from . import pmd + +class ConvertException(Exception): + """ + Exception in writer + """ + pass + +def pmd_to_pmx(src): + """ + convert pmd model to pmx model. + """ + dst=pmx.Model() + dst.name=src.name.decode("cp932") + dst.english_name=src.english_name.decode("cp932") + dst.comment=src.comment.replace( + b"\n", b"\r\n").decode("cp932") + dst.english_comment=src.english_comment.replace( + b"\n", b"\r\n").decode("cp932") + def createDeform(bone0, bone1, weight0): + if weight0==0: + return pmx.Bdef1(bone1) + elif weight0==100: + return pmx.Bdef1(bone0) + else: + return pmx.Bdef2(bone0, bone1, weight0*0.01) + dst.vertices=[ + pmx.Vertex( + v.pos, + v.normal, + v.uv, + createDeform(v.bone0, v.bone1, v.weight0), + 1.0 if v.edge_flag==0 else 0.0 + ) + for v in src.vertices] + dst.indices=[i for i in src.indices] + + texture_map={} + def get_flag(m): + return ( + (1 if False else 0)+ + (2 if (m.edge_flag & 1!=0) else 0)+ + (4 if True else 0)+ + (8 if True else 0)+ + (16 if (m.edge_flag & 1!=0) else 0) + ) + def get_texture_file(path): + if len(path)==0: + return None + elif path.find(b'*')==-1: + return path + else: + return b'*'.split(path)[0] + def get_sphere_texture_file(path): + if len(path)==0: + return None + elif path.find(b'*')==-1: + return None + else: + return b'*'.split(path)[1] + def get_texture_index(path): + try: + return texture_map[get_texture_file(path)] + except KeyError: + return -1 + def get_sphere_texture_index(path): + try: + return texture_map[get_sphere_texture_file(path)] + except KeyError: + return -1 + def get_sphere_texture_flag(path): + sphere_texture=get_sphere_texture_file(path) + if sphere_texture: + if sphere_texture.endswith('.sph'): + return 1 + elif sphere_texture.endswith('.spa'): + return 2 + else: + raise ConvertException( + "invalid sphere texture: {0}".format(sphere_texture)) + return 0 + for m in src.materials: + texture=get_texture_file(m.texture_file) + if texture and not texture in texture_map: + texture_map[texture]=len(texture_map) + dst.textures.append(texture.decode("cp932")) + sphere_texture=get_sphere_texture_file(m.texture_file) + if sphere_texture and not sphere_texture in texture_map: + texture_map[sphere_texture]=len(texture_map) + dst.textures.append(sphere_texture.decode("cp932")) + dst.materials=[ + pmx.Material( + name=common.unicode(""), + english_name=common.unicode(""), + diffuse_color=m.diffuse_color, + alpha=m.alpha, + specular_factor=m.specular_factor, + specular_color=m.specular_color, + ambient_color=m.ambient_color, + flag=get_flag(m), + edge_color=common.RGBA(0.0, 0.0, 0.0, 1.0), + edge_size=1.0, + texture_index=get_texture_index(m.texture_file), + sphere_texture_index=get_sphere_texture_index(m.texture_file), + sphere_mode=get_sphere_texture_flag(m.texture_file), + toon_sharing_flag=1, + toon_texture_index=m.toon_index, + comment=common.unicode(""), + vertex_count=m.vertex_count + ) + for i, m in enumerate(src.materials)] + + ik_map={} + for ik in src.ik_list: + ik_map[ik.index]=ik + + def is_connected(b): + if isinstance(b, pmd.Bone_Rolling): + return False + if isinstance(b, pmd.Bone_Tweak): + return False + return True + def is_rotatable(b): + if isinstance(b, pmd.Bone_Rotate): + return True + if isinstance(b, pmd.Bone_RotateMove): + return True + if isinstance(b, pmd.Bone_RotateInfl): + return True + if isinstance(b, pmd.Bone_IKRotateInfl): + return True + if isinstance(b, pmd.Bone_Rolling): + return True + if isinstance(b, pmd.Bone_IKTarget): + return True + if isinstance(b, pmd.Bone_IK): + return True + if isinstance(b, pmd.Bone_Unvisible): + return True + if isinstance(b, pmd.Bone_Tweak): + return True + def is_movable(b): + if isinstance(b, pmd.Bone_RotateMove): + return True + if isinstance(b, pmd.Bone_IK): + return True + def is_visible(b): + if isinstance(b, pmd.Bone_Unvisible): + return False + if isinstance(b, pmd.Bone_IKTarget): + return False + if isinstance(b, pmd.Bone_Tweak): + return False + return True + def is_manupilatable(b): + return True + def has_ik(b): + if isinstance(b, pmd.Bone_IK): + return True + def is_external_rotation(b): + if isinstance(b, pmd.Bone_RotateInfl): + return True + if isinstance(b, pmd.Bone_Tweak): + return True + def is_fixed_axis(b): + if isinstance(b, pmd.Bone_Rolling): + return True + def is_local_axis(b): + pass + def after_physics(b): + pass + def external_parent(b): + pass + def get_bone_flag(b): + return ( + (1 if is_connected(b) else 0)+ + (2 if is_rotatable(b) else 0)+ + (4 if is_movable(b) else 0)+ + (8 if is_visible(b) else 0)+ + + (16 if is_manupilatable(b) else 0)+ + (32 if has_ik(b) else 0)+ + 0+ + 0+ + + (256 if is_external_rotation(b) else 0)+ + 0+ + (1024 if is_fixed_axis(b) else 0)+ + (2048 if is_local_axis(b) else 0)+ + + (4096 if after_physics(b) else 0)+ + (8192 if external_parent(b) else 0) + ) + + def get_tail_position(b): + return common.Vector3() + def get_tail_index(b): + if isinstance(b, pmd.Bone_Rolling): + return -1 + if isinstance(b, pmd.Bone_IKTarget): + return -1 + if isinstance(b, pmd.Bone_Unvisible): + return -1 + if isinstance(b, pmd.Bone_Tweak): + return -1 + return b.tail_index + def get_ik_link(bone_index): + b=src.bones[bone_index] + if b.english_name.find(b'knee')==-1: + return pmx.IkLink( + bone_index, 0, + common.Vector3(), + common.Vector3()) + else: + return pmx.IkLink( + bone_index, 1, + common.Vector3(-3.1415927410125732, 0.0, 0.0), + common.Vector3(-0.00872664619237184524536132812500, 0.0, 0.0)) + def get_ik(b): + if isinstance(b, pmd.Bone_IK): + ik=ik_map[b.index] + return pmx.Ik( + ik.target, ik.iterations, ik.weight * 4, [ + get_ik_link(child) for child in ik.children ]) + return None + def get_layer(b): + return 0 + dst.bones=[ + pmx.Bone( + name=b.name.decode('cp932'), + english_name=b.english_name.decode('cp932'), + position=b.pos, + parent_index=b.parent_index if b.parent_index!=65535 else -1, + layer=get_layer(b), + flag=get_bone_flag(b), + tail_position=get_tail_position(b), + tail_index=get_tail_index(b), + effect_index=-1, + effect_factor=0.0, + fixed_axis=common.Vector3(), + local_x_vector=common.Vector3(), + local_z_vector=common.Vector3(), + external_key=-1, + ik=get_ik(b), + ) + for i, b in enumerate(src.bones)] + + return dst + + def is_visible(b): + if isinstance(b, pmd.Bone_Unvisible): + return False + else: + return True + def is_manupilatable(b): + return True + def has_ik(b): + return False + def is_fixed_axis(b): + if isinstance(b, pmd.Bone_Rolling): + return True + def is_local_axis(b): + pass + def after_physics(b): + pass + def external_parent(b): + pass + def get_bone_flag(b): + return ( + (1 if is_connected(b) else 0)+ + (2 if is_rotatable(b) else 0)+ + (4 if is_movable(b) else 0)+ + (8 if is_visible(b) else 0)+ + + (16 if is_manupilatable(b) else 0)+ + (32 if has_ik(b) else 0)+ + 0+ + 0+ + + (256 if isinstance(b, pmd.Bone_RotateInfl) else 0)+ + 0+ + (1024 if is_fixed_axis(b) else 0)+ + (2048 if is_local_axis(b) else 0)+ + + (4096 if after_physics(b) else 0)+ + (8192 if external_parent(b) else 0) + ) + + def get_tail_position(b): + return common.Vector3() + def get_tail_index(b): + if isinstance(b, pmd.Bone_Rolling): + return -1 + return b.tail_index + def get_ik(b): + return None + def get_layer(b): + return 0 + dst.bones=[ + pmx.Bone( + name=b.name.decode('cp932'), + english_name=b.english_name.decode('cp932'), + position=b.pos, + parent_index=b.parent_index if b.parent_index!=65535 else -1, + layer=get_layer(b), + flag=get_bone_flag(b), + tail_position=get_tail_position(b), + tail_index=get_tail_index(b), + effect_index=-1, + effect_factor=0.0, + fixed_axis=common.Vector3(), + local_x_vector=common.Vector3(), + local_z_vector=common.Vector3(), + external_key=-1, + ik=get_ik(b), + ) + for i, b in enumerate(src.bones)] + + return dst + diff --git a/pymeshio/pmd/__init__.py b/pymeshio/pmd/__init__.py index f3c8e4f..839b637 100644 --- a/pymeshio/pmd/__init__.py +++ b/pymeshio/pmd/__init__.py @@ -25,16 +25,31 @@ from .. import 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 + """ + ========== + pmd vertex + ========== + two bone weighted vertex with normal and uv. + + format + ~~~~~~ + * http://blog.goo.ne.jp/torisu_tetosuki/e/5a1b16e2f61067838dfc66d010389707 + + :IVariables: + pos + Vector3 + normal + Vector3 + uv + Vector2 + bone0 + bone index + bone1 + bone index + weight0 + bone0 influence. min: 0, max: 100 + edge_flag + int flag. 0: edge on, 1: edge off """ __slots__=['pos', 'normal', 'uv', 'bone0', 'bone1', 'weight0', 'edge_flag'] def __init__(self, pos, normal, uv, @@ -77,18 +92,34 @@ class Vertex(object): 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 + """ + ============ + pmd material + ============ + + format + ~~~~~~ + * http://blog.goo.ne.jp/torisu_tetosuki/e/ea0bb1b1d4c6ad98a93edbfe359dac32 + + :IVariables: + 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', @@ -130,22 +161,40 @@ class Material(object): class Bone(object): - """pmd material struct. - - Attributes: - _name: - index: - type: - ik: - pos: - _english_name: - ik_index: - parent_index: - tail_index: - - parent: - tail: - children: + """ + ========== + pmd bone + ========== + + format + ~~~~~~ + * http://blog.goo.ne.jp/torisu_tetosuki/e/638463f52d0ad6ca1c46fd315a9b17d0 + + :IVariables: + name + bone name + english_name + bone english_name + index + boen index(append for internal use) + type + bone type + ik + ik(append for internal use) + pos + bone head position + ik_index + ik target bone index + parent_index + parent bone index + tail_index + tail bone index + parent + parent bone(append for internal use) + tail + tail bone(append for internal use) + children + children bone(append for internal use) """ # kinds ROTATE = 0 diff --git a/pymeshio/pmd/reader.py b/pymeshio/pmd/reader.py index 9183c0d..b120052 100644 --- a/pymeshio/pmd/reader.py +++ b/pymeshio/pmd/reader.py @@ -205,6 +205,7 @@ def read(ios): # build bone tree for i, child in enumerate(model.bones): + child.index=i if child.parent_index==0xFFFF: # no parent model.no_parent_bones.append(child) diff --git a/pymeshio/pmx/__init__.py b/pymeshio/pmx/__init__.py index 77d45a3..7afe5f2 100644 --- a/pymeshio/pmx/__init__.py +++ b/pymeshio/pmx/__init__.py @@ -30,7 +30,42 @@ from pymeshio import common -class Ik(object): +class DifferenceException(Exception): + pass + + +class Diff(object): + def _diff(self, rhs, key): + l=getattr(self, key) + r=getattr(rhs, key) + if l!=r: + print(l) + print(r) + raise DifferenceException(key) + + def _diff_array(self, rhs, key): + la=getattr(self, key) + ra=getattr(rhs, key) + if len(la)!=len(la): + raise DifferenceException(key) + for i, (l, r) in enumerate(zip(la, ra)): + if isinstance(l, Diff): + try: + l.diff(r) + except DifferenceException as e: + print(i) + print(l) + print(r) + raise DifferenceException("{0}: {1}".format(key, e.message)) + else: + if l!=r: + print(i) + print(l) + print(r) + raise DifferenceException("{0}".format(key)) + + +class Ik(Diff): """ik info """ __slots__=[ @@ -39,14 +74,28 @@ class Ik(object): 'limit_radian', 'link', ] - def __init__(self, target_index, loop, limit_radian): + def __init__(self, target_index, loop, limit_radian, link=[]): self.target_index=target_index self.loop=loop self.limit_radian=limit_radian - self.link=[] + self.link=link + + def __eq__(self, rhs): + return ( + self.target_index==rhs.target_index + and self.loop==rhs.loop + and self.limit_radian==rhs.limit_radian + and self.link==rhs.link + ) + def diff(self, rhs): + self._diff(rhs, 'target_index') + self._diff(rhs, 'loop') + self._diff(rhs, 'limit_radian') + self._diff_array(rhs, 'link') -class IkLink(object): + +class IkLink(Diff): """ik link info """ __slots__=[ @@ -55,14 +104,28 @@ class IkLink(object): 'limit_min', 'limit_max', ] - def __init__(self, bone_index, limit_angle): + def __init__(self, bone_index, limit_angle, limit_min=common.Vector3(), limit_max=common.Vector3()): self.bone_index=bone_index self.limit_angle=limit_angle - self.limit_min=None - self.limit_max=None + self.limit_min=limit_min + self.limit_max=limit_max + def __eq__(self, rhs): + return ( + self.bone_index==rhs.bone_index + and self.limit_angle==rhs.limit_angle + and self.limit_min==rhs.limit_min + and self.limit_max==rhs.limit_max + ) -class Bone(object): + def diff(self, rhs): + self._diff(rhs, 'bone_index') + self._diff(rhs, 'limit_angle') + self._diff(rhs, 'limit_min') + self._diff(rhs, 'limit_max') + + +class Bone(Diff): """material Bone: see __init__ @@ -75,7 +138,7 @@ class Bone(object): 'layer', 'flag', - 'tail_positoin', + 'tail_position', 'tail_index', 'effect_index', 'effect_factor', @@ -91,7 +154,16 @@ class Bone(object): position, parent_index, layer, - flag + flag, + tail_position=common.Vector3(), + tail_index=-1, + effect_index=-1, + effect_factor=0.0, + fixed_axis=common.Vector3(), + local_x_vector=common.Vector3(), + local_z_vector=common.Vector3(), + external_key=-1, + ik=None ): self.name=name self.english_name=english_name @@ -99,6 +171,15 @@ class Bone(object): self.parent_index=parent_index self.layer=layer self.flag=flag + self.tail_position=tail_position + self.tail_index=tail_index + self.effect_index=effect_index + self.effect_factor=effect_factor + self.fixed_axis=fixed_axis + self.local_x_vector=local_x_vector + self.local_z_vector=local_z_vector + self.external_key=external_key + self.ik=ik def __eq__(self, rhs): return ( @@ -110,6 +191,29 @@ class Bone(object): and self.flag==rhs.flag ) + def __ne__(self, rhs): + return not self.__eq__(rhs) + + def diff(self, rhs): + self._diff(rhs, 'name') + self._diff(rhs, 'english_name') + self._diff(rhs, 'position') + self._diff(rhs, 'parent_index') + #self._diff(rhs, 'layer') + self._diff(rhs, 'flag') + self._diff(rhs, 'tail_position') + self._diff(rhs, 'tail_index') + #self._diff(rhs, 'effect_index') + #self._diff(rhs, 'effect_factor') + #self._diff(rhs, 'fixed_axis') + self._diff(rhs, 'local_x_vector') + self._diff(rhs, 'local_z_vector') + self._diff(rhs, 'external_key') + if self.ik and rhs.ik: + self.ik.diff(rhs.ik) + else: + self._diff(rhs, 'ik') + def getConnectionFlag(self): return self.flag & 0x0001 @@ -132,7 +236,7 @@ class Bone(object): return (self.flag & 0x2000) >> 13 -class Material(object): +class Material(Diff): """material Attributes: see __init__ @@ -161,8 +265,8 @@ class Material(object): english_name, diffuse_color, alpha, - specular_color, specular_factor, + specular_color, ambient_color, flag, edge_color, @@ -170,7 +274,10 @@ class Material(object): texture_index, sphere_texture_index, sphere_mode, - toon_sharing_flag + toon_sharing_flag, + toon_texture_index=0, + comment=common.unicode(""), + vertex_count=0, ): self.name=name self.english_name=english_name @@ -186,10 +293,9 @@ class Material(object): self.sphere_texture_index=sphere_texture_index self.sphere_mode=sphere_mode self.toon_sharing_flag=toon_sharing_flag - # - self.toon_texture_index=None - self.comment=name.__class__() # unicode - self.vertex_count=0 + self.toon_texture_index=toon_texture_index + self.comment=comment + self.vertex_count=vertex_count def __eq__(self, rhs): return ( @@ -212,17 +318,35 @@ class Material(object): and self.vertex_count==rhs.vertex_count ) + def diff(self, rhs): + #self._diff(rhs, "name") + self._diff(rhs, "english_name") + self._diff(rhs, "diffuse_color") + self._diff(rhs, "alpha") + self._diff(rhs, "specular_color") + self._diff(rhs, "specular_factor") + self._diff(rhs, "ambient_color") + self._diff(rhs, "flag") + self._diff(rhs, "edge_color") + self._diff(rhs, "edge_size") + self._diff(rhs, "texture_index") + self._diff(rhs, "sphere_texture_index") + self._diff(rhs, "sphere_mode") + self._diff(rhs, "toon_sharing_flag") + self._diff(rhs, "toon_texture_index") + self._diff(rhs, "comment") + self._diff(rhs, "vertex_count") + + def __ne__(self, rhs): + return not self.__eq__(rhs) + def __str__(self): return ("".format( name=self.english_name )) -class Deform(object): - pass - - -class Bdef1(object): +class Bdef1(Diff): """bone deform. use a weight Attributes: see __init__ @@ -231,11 +355,17 @@ class Bdef1(object): def __init__(self, index0): self.index0=index0 + def __str__(self): + return "".format(self.index0) + def __eq__(self, rhs): return self.index0==rhs.index0 + def __ne__(self, rhs): + return not self.__eq__(rhs) + -class Bdef2(object): +class Bdef2(Diff): """bone deform. use two weights Attributes: see __init__ @@ -249,18 +379,38 @@ class Bdef2(object): self.index1=index1 self.weight0=weight0 + def __str__(self): + return "".format(self.index0, self.index1, self.weight0) + def __eq__(self, rhs): return ( self.index0==rhs.index0 and self.index1==rhs.index1 - and self.weight0==rhs.weight0 + #and self.weight0==rhs.weight0 + and abs(self.weight0-rhs.weight0)<1e-5 ) + def __ne__(self, rhs): + return not self.__eq__(rhs) -class Vertex(object): - """pmx vertex - Attributes: see __init__ +class Vertex(Diff): + """ + ========== + pmx vertex + ========== + + :IVariables: + position + Vector3 + normal + Vector3 + uv + Vector2 + deform + Bdef1, Bdef2 or Bdef4 + edge_factor + float """ __slots__=[ 'position', 'normal', 'uv', 'deform', 'edge_factor' ] def __init__(self, @@ -275,6 +425,11 @@ class Vertex(object): self.deform=deform self.edge_factor=edge_factor + def __str__(self): + return "0: raise pymeshio.common.ParseException( "extended uv is not supported", extended_uv) - self.read_vertex_index=lambda : self.read_uint(vertex_index_size) - self.read_texture_index=lambda : self.read_uint(texture_index_size) - self.read_material_index=lambda : self.read_uint(material_index_size) - self.read_bone_index=lambda : self.read_uint(bone_index_size) - self.read_morph_index=lambda : self.read_uint(morph_index_size) - self.read_rigidbody_index=lambda : self.read_uint(rigidbody_index_size) + self.read_vertex_index=lambda : self.read_int(vertex_index_size) + self.read_texture_index=lambda : self.read_int(texture_index_size) + self.read_material_index=lambda : self.read_int(material_index_size) + self.read_bone_index=lambda : self.read_int(bone_index_size) + self.read_morph_index=lambda : self.read_int(morph_index_size) + self.read_rigidbody_index=lambda : self.read_int(rigidbody_index_size) def __str__(self): return '' @@ -38,12 +38,12 @@ class Reader(pymeshio.common.BinaryReader): def get_read_text(self, text_encoding): if text_encoding==0: def read_text(): - size=self.read_uint(4) + size=self.read_int(4) return self.unpack("{0}s".format(size), size).decode("UTF16") return read_text elif text_encoding==1: def read_text(): - size=self.read_uint(4) + size=self.read_int(4) return self.unpack("{0}s".format(size), size).decode("UTF8") return read_text else: @@ -59,7 +59,7 @@ class Reader(pymeshio.common.BinaryReader): ) def read_deform(self): - deform_type=self.read_uint(1) + deform_type=self.read_int(1) if deform_type==0: return pymeshio.pmx.Bdef1(self.read_bone_index()) elif deform_type==1: @@ -85,24 +85,24 @@ class Reader(pymeshio.common.BinaryReader): specular_color=self.read_rgb(), specular_factor=self.read_float(), ambient_color=self.read_rgb(), - flag=self.read_uint(1), + flag=self.read_int(1), edge_color=self.read_rgba(), edge_size=self.read_float(), texture_index=self.read_texture_index(), sphere_texture_index=self.read_texture_index(), - sphere_mode=self.read_uint(1), - toon_sharing_flag=self.read_uint(1), + sphere_mode=self.read_int(1), + toon_sharing_flag=self.read_int(1), ) if material.toon_sharing_flag==0: material.toon_texture_index=self.read_texture_index() elif material.toon_sharing_flag==1: - material.toon_texture_index=self.read_uint(1) + material.toon_texture_index=self.read_int(1) else: raise pymeshio.common.ParseException( "unknown toon_sharing_flag {0}".format( material.toon_sharing_flag)) material.comment=self.read_text() - material.vertex_count=self.read_uint(4) + material.vertex_count=self.read_int(4) return material def read_bone(self): @@ -111,11 +111,11 @@ class Reader(pymeshio.common.BinaryReader): english_name=self.read_text(), position=self.read_vector3(), parent_index=self.read_bone_index(), - layer=self.read_uint(4), - flag=self.read_uint(2) + layer=self.read_int(4), + flag=self.read_int(2) ) if bone.getConnectionFlag()==0: - bone.tail_positoin=self.read_vector3() + bone.tail_position=self.read_vector3() elif bone.getConnectionFlag()==1: bone.tail_index=self.read_bone_index() else: @@ -135,7 +135,7 @@ class Reader(pymeshio.common.BinaryReader): bone.local_z_vector=self.read_vector3() if bone.getExternalParentDeformFlag()==1: - bone.external_key=self.read_uint(4) + bone.external_key=self.read_int(4) if bone.getIkFlag()==1: bone.ik=self.read_ik() @@ -145,9 +145,9 @@ class Reader(pymeshio.common.BinaryReader): def read_ik(self): ik=pymeshio.pmx.Ik( target_index=self.read_bone_index(), - loop=self.read_uint(4), + loop=self.read_int(4), limit_radian=self.read_float()) - link_size=self.read_uint(4) + link_size=self.read_int(4) ik.link=[self.read_ik_link() for _ in range(link_size)] return ik @@ -155,7 +155,7 @@ class Reader(pymeshio.common.BinaryReader): def read_ik_link(self): link=pymeshio.pmx.IkLink( self.read_bone_index(), - self.read_uint(1)) + self.read_int(1)) if link.limit_angle==0: pass elif link.limit_angle==1: @@ -170,9 +170,9 @@ class Reader(pymeshio.common.BinaryReader): def read_morgh(self): name=self.read_text() english_name=self.read_text() - panel=self.read_uint(1) - morph_type=self.read_uint(1) - offset_size=self.read_uint(4) + panel=self.read_int(1) + morph_type=self.read_int(1) + offset_size=self.read_int(4) if morph_type==0: # todo raise pymeshio.common.ParseException( @@ -221,10 +221,10 @@ class Reader(pymeshio.common.BinaryReader): def read_display_slot(self): display_slot=pymeshio.pmx.DisplaySlot(self.read_text(), self.read_text(), - self.read_uint(1)) - display_count=self.read_uint(4) + self.read_int(1)) + display_count=self.read_int(4) for _ in range(display_count): - display_type=self.read_uint(1) + display_type=self.read_int(1) if display_type==0: display_slot.refrences.append( (display_type, self.read_bone_index())) @@ -241,9 +241,9 @@ class Reader(pymeshio.common.BinaryReader): name=self.read_text(), english_name=self.read_text(), bone_index=self.read_bone_index(), - collision_group=self.read_uint(1), - no_collision_group=self.read_uint(2), - shape_type=self.read_uint(1), + collision_group=self.read_int(1), + no_collision_group=self.read_int(2), + shape_type=self.read_int(1), shape_size=self.read_vector3(), shape_position=self.read_vector3(), shape_rotation=self.read_vector3(), @@ -252,14 +252,14 @@ class Reader(pymeshio.common.BinaryReader): angular_damping=self.read_float(), restitution=self.read_float(), friction=self.read_float(), - mode=self.read_uint(1) + mode=self.read_int(1) ) def read_joint(self): return pymeshio.pmx.Joint( name=self.read_text(), english_name=self.read_text(), - joint_type=self.read_uint(1), + joint_type=self.read_int(1), rigidbody_index_a=self.read_rigidbody_index(), rigidbody_index_b=self.read_rigidbody_index(), position=self.read_vector3(), @@ -292,18 +292,18 @@ def read(ios): model=pymeshio.pmx.Model(version) # flags - flag_bytes=reader.read_uint(1) + flag_bytes=reader.read_int(1) if flag_bytes!=8: raise pymeshio.common.ParseException( "invalid flag length", reader.flag_bytes) - text_encoding=reader.read_uint(1) - extended_uv=reader.read_uint(1) - vertex_index_size=reader.read_uint(1) - texture_index_size=reader.read_uint(1) - material_index_size=reader.read_uint(1) - bone_index_size=reader.read_uint(1) - morph_index_size=reader.read_uint(1) - rigidbody_index_size=reader.read_uint(1) + text_encoding=reader.read_int(1) + extended_uv=reader.read_int(1) + vertex_index_size=reader.read_int(1) + texture_index_size=reader.read_int(1) + material_index_size=reader.read_int(1) + bone_index_size=reader.read_int(1) + morph_index_size=reader.read_int(1) + rigidbody_index_size=reader.read_int(1) # pmx custom reader reader=Reader(reader.ios, @@ -325,23 +325,23 @@ def read(ios): # model data model.vertices=[reader.read_vertex() - for _ in range(reader.read_uint(4))] + for _ in range(reader.read_int(4))] model.indices=[reader.read_vertex_index() - for _ in range(reader.read_uint(4))] + for _ in range(reader.read_int(4))] model.textures=[reader.read_text() - for _ in range(reader.read_uint(4))] + for _ in range(reader.read_int(4))] model.materials=[reader.read_material() - for _ in range(reader.read_uint(4))] + for _ in range(reader.read_int(4))] model.bones=[reader.read_bone() - for _ in range(reader.read_uint(4))] + for _ in range(reader.read_int(4))] model.morphs=[reader.read_morgh() - for _ in range(reader.read_uint(4))] + for _ in range(reader.read_int(4))] model.display_slots=[reader.read_display_slot() - for _ in range(reader.read_uint(4))] + for _ in range(reader.read_int(4))] model.rigidbodies=[reader.read_rigidbody() - for _ in range(reader.read_uint(4))] + for _ in range(reader.read_int(4))] model.joints=[reader.read_joint() - for _ in range(reader.read_uint(4))] + for _ in range(reader.read_int(4))] return model diff --git a/pymeshio/pmx/writer.py b/pymeshio/pmx/writer.py index bc0b13c..f823985 100644 --- a/pymeshio/pmx/writer.py +++ b/pymeshio/pmx/writer.py @@ -18,28 +18,28 @@ class Writer(common.BinaryWriter): if text_encoding==0: def write_text(unicode): utf16=unicode.encode('utf16') - self.write_uint(len(utf16), 4) + self.write_int(len(utf16), 4) self.write_bytes(utf16) self.write_text=write_text elif text_encoding==1: def write_text(unicode): utf8=unicode.encode('utf8') - self.write_uint(len(utf8), 4) + self.write_int(len(utf8), 4) self.write_bytes(utf8) self.write_text=write_text else: raise WriteError( "invalid text_encoding: {0}".format(text_encoding)) - self.write_vertex_index=lambda index: self.write_uint(index, vertex_index_size) - self.write_texture_index=lambda index: self.write_uint(index, texture_index_size) - self.write_material_index=lambda index: self.write_uint(index, material_index_size) - self.write_bone_index=lambda index: self.write_uint(index, bone_index_size) - self.write_morph_index=lambda index: self.write_uint(index, morph_index_size) - self.write_rigidbody_index=lambda index: self.write_uint(index, rigidbody_index_size) + self.write_vertex_index=lambda index: self.write_int(index, vertex_index_size) + self.write_texture_index=lambda index: self.write_int(index, texture_index_size) + self.write_material_index=lambda index: self.write_int(index, material_index_size) + self.write_bone_index=lambda index: self.write_int(index, bone_index_size) + self.write_morph_index=lambda index: self.write_int(index, morph_index_size) + self.write_rigidbody_index=lambda index: self.write_int(index, rigidbody_index_size) def write_vertices(self, vertices): - self.write_uint(len(vertices), 4) + self.write_int(len(vertices), 4) for v in vertices: self.write_vector3(v.position) self.write_vector3(v.normal) @@ -49,10 +49,10 @@ class Writer(common.BinaryWriter): def write_deform(self, deform): if isinstance(deform, pmx.Bdef1): - self.write_uint(0, 1) + self.write_int(0, 1) self.write_bone_index(deform.index0) elif isinstance(deform, pmx.Bdef2): - self.write_uint(1, 1) + self.write_int(1, 1) self.write_bone_index(deform.index0) self.write_bone_index(deform.index1) self.write_float(deform.weight0) @@ -65,17 +65,17 @@ class Writer(common.BinaryWriter): "unknown deform type: {0}".format(deform.type)) def write_indices(self, indices): - self.write_uint(len(indices), 4) + self.write_int(len(indices), 4) for i in indices: self.write_vertex_index(i) def write_textures(self, textures): - self.write_uint(len(textures), 4) + self.write_int(len(textures), 4) for t in textures: self.write_text(t) def write_materials(self, materials): - self.write_uint(len(materials), 4) + self.write_int(len(materials), 4) for m in materials: self.write_text(m.name) self.write_text(m.english_name) @@ -84,34 +84,34 @@ class Writer(common.BinaryWriter): self.write_rgb(m.specular_color) self.write_float(m.specular_factor) self.write_rgb(m.ambient_color) - self.write_uint(m.flag, 1) + self.write_int(m.flag, 1) self.write_rgba(m.edge_color) self.write_float(m.edge_size) self.write_texture_index(m.texture_index) self.write_texture_index(m.sphere_texture_index) - self.write_uint(m.sphere_mode, 1) - self.write_uint(m.toon_sharing_flag, 1) + self.write_int(m.sphere_mode, 1) + self.write_int(m.toon_sharing_flag, 1) if m.toon_sharing_flag==0: self.write_texture_index(m.toon_texture_index) elif m.toon_sharing_flag==1: - self.write_uint(m.toon_texture_index, 1) + self.write_int(m.toon_texture_index, 1) else: raise common.WriteException( "unknown toon_sharing_flag {0}".format(m.toon_sharing_flag)) self.write_text(m.comment) - self.write_uint(m.vertex_count, 4) + self.write_int(m.vertex_count, 4) def write_bones(self, bones): - self.write_uint(len(bones), 4) + self.write_int(len(bones), 4) for bone in bones: self.write_text(bone.name) self.write_text(bone.english_name) self.write_vector3(bone.position) self.write_bone_index(bone.parent_index) - self.write_uint(bone.layer, 4) - self.write_uint(bone.flag, 2) + self.write_int(bone.layer, 4) + self.write_int(bone.flag, 2) if bone.getConnectionFlag()==0: - self.write_vector3(bone.tail_positoin) + self.write_vector3(bone.tail_position) elif bone.getConnectionFlag()==1: self.write_bone_index(bone.tail_index) else: @@ -131,22 +131,22 @@ class Writer(common.BinaryWriter): self.write_vector3(bone.local_z_vector) if bone.getExternalParentDeformFlag()==1: - self.write_uint(bone.external_key, 4) + self.write_int(bone.external_key, 4) if bone.getIkFlag()==1: self.write_ik(bone.ik) def write_ik(self, ik): self.write_bone_index(ik.target_index) - self.write_uint(ik.loop, 4) + self.write_int(ik.loop, 4) self.write_float(ik.limit_radian) - self.write_uint(len(ik.link), 4) + self.write_int(len(ik.link), 4) for l in ik.link: self.write_ik_link(l) def write_ik_link(self, link): self.write_bone_index(link.bone_index) - self.write_uint(link.limit_angle, 1) + self.write_int(link.limit_angle, 1) if link.limit_angle==0: pass elif link.limit_angle==1: @@ -158,18 +158,18 @@ class Writer(common.BinaryWriter): link.limit_angle)) def write_morph(self, morphs): - self.write_uint(len(morphs), 4) + self.write_int(len(morphs), 4) for m in morphs: self.write_text(m.name) self.write_text(m.english_name) - self.write_uint(m.panel, 1) - self.write_uint(m.morph_type, 1) + self.write_int(m.panel, 1) + self.write_int(m.morph_type, 1) if m.morph_type==0: # todo raise pymeshio.common.WriteException( "not implemented GroupMorph") elif m.morph_type==1: - self.write_uint(len(m.offsets), 4) + self.write_int(len(m.offsets), 4) for o in m.offsets: self.write_vertex_index(o.vertex_index) self.write_vector3(o.position_offset) @@ -206,14 +206,14 @@ class Writer(common.BinaryWriter): "unknown morph type: {0}".format(m.morph_type)) def write_display_slots(self, display_slots): - self.write_uint(len(display_slots), 4) + self.write_int(len(display_slots), 4) for s in display_slots: self.write_text(s.name) self.write_text(s.english_name) - self.write_uint(s.special_flag, 1) - self.write_uint(len(s.refrences), 4) + self.write_int(s.special_flag, 1) + self.write_int(len(s.refrences), 4) for r in s.refrences: - self.write_uint(r[0], 1) + self.write_int(r[0], 1) if r[0]==0: self.write_bone_index(r[1]) elif r[0]==1: @@ -223,14 +223,14 @@ class Writer(common.BinaryWriter): "unknown display_type: {0}".format(r[0])) def write_rigidbodies(self, rigidbodies): - self.write_uint(len(rigidbodies), 4) + self.write_int(len(rigidbodies), 4) for rb in rigidbodies: self.write_text(rb.name) self.write_text(rb.english_name) self.write_bone_index(rb.bone_index) - self.write_uint(rb.collision_group, 1) - self.write_uint(rb.no_collision_group, 2) - self.write_uint(rb.shape_type, 1) + self.write_int(rb.collision_group, 1) + self.write_int(rb.no_collision_group, 2) + self.write_int(rb.shape_type, 1) self.write_vector3(rb.shape_size) self.write_vector3(rb.shape_position) self.write_vector3(rb.shape_rotation) @@ -239,14 +239,14 @@ class Writer(common.BinaryWriter): self.write_float(rb.param.angular_damping) self.write_float(rb.param.restitution) self.write_float(rb.param.friction) - self.write_uint(rb.mode, 1) + self.write_int(rb.mode, 1) def write_joints(self, joints): - self.write_uint(len(joints), 4) + self.write_int(len(joints), 4) for j in joints: self.write_text(j.name) self.write_text(j.english_name) - self.write_uint(j.joint_type, 1) + self.write_int(j.joint_type, 1) self.write_rigidbody_index(j.rigidbody_index_a) self.write_rigidbody_index(j.rigidbody_index_b) self.write_vector3(j.position) @@ -270,11 +270,11 @@ def write(ios, model, text_encoding=1): writer.write_float(model.version) # flags - writer.write_uint(8, 1) + writer.write_int(8, 1) # textencoding - writer.write_uint(text_encoding, 1) + writer.write_int(text_encoding, 1) # extend uv - writer.write_uint(0, 1) + writer.write_int(0, 1) def get_array_size(size): if size<128: return 1 @@ -287,22 +287,22 @@ def write(ios, model, text_encoding=1): "invalid array_size: {0}".format(size)) # vertex_index_size vertex_index_size=get_array_size(len(model.vertices)) - writer.write_uint(vertex_index_size, 1) + writer.write_int(vertex_index_size, 1) # texture_index_size texture_index_size=get_array_size(len(model.textures)) - writer.write_uint(texture_index_size, 1) + writer.write_int(texture_index_size, 1) # material_index_size material_index_size=get_array_size(len(model.materials)) - writer.write_uint(material_index_size, 1) + writer.write_int(material_index_size, 1) # bone_index_size bone_index_size=get_array_size(len(model.bones)) - writer.write_uint(bone_index_size, 1) + writer.write_int(bone_index_size, 1) # morph_index_size morph_index_size=get_array_size(len(model.morphs)) - writer.write_uint(morph_index_size, 1) + writer.write_int(morph_index_size, 1) # rigidbody_index_size rigidbody_index_size=get_array_size(len(model.rigidbodies)) - writer.write_uint(rigidbody_index_size, 1) + writer.write_int(rigidbody_index_size, 1) writer=Writer(writer.ios, text_encoding, 0, diff --git a/test/pmd_test.py b/test/pmd_test.py index 914f6fe..fa64485 100644 --- a/test/pmd_test.py +++ b/test/pmd_test.py @@ -2,12 +2,13 @@ import sys import io import unittest +import pymeshio.common import pymeshio.pmd import pymeshio.pmd.reader import pymeshio.pmd.writer -PMD_FILE=pymeshio.unicode('resources/初音ミクVer2.pmd') +PMD_FILE=pymeshio.common.unicode('resources/初音ミクVer2.pmd') class TestPmd(unittest.TestCase): @@ -18,9 +19,9 @@ class TestPmd(unittest.TestCase): def test_read(self): model=pymeshio.pmd.reader.read_from_file(PMD_FILE) self.assertEqual(pymeshio.pmd.Model, model.__class__) - self.assertEqual(pymeshio.unicode('初音ミク').encode('cp932'), model.name) - self.assertEqual(pymeshio.unicode('Miku Hatsune').encode('cp932'), model.english_name) - self.assertEqual(pymeshio.unicode( + self.assertEqual(pymeshio.common.unicode('初音ミク').encode('cp932'), model.name) + self.assertEqual(pymeshio.common.unicode('Miku Hatsune').encode('cp932'), model.english_name) + self.assertEqual(pymeshio.common.unicode( "PolyMo用モデルデータ:初音ミク ver.2.3\n"+ "(物理演算対応モデル)\n"+ "\n"+ @@ -28,7 +29,7 @@ class TestPmd(unittest.TestCase): "データ変換 :あにまさ氏\n"+ "Copyright :CRYPTON FUTURE MEDIA, INC").encode('cp932'), model.comment) - self.assertEqual(pymeshio.unicode( + self.assertEqual(pymeshio.common.unicode( "MMD Model: Miku Hatsune ver.2.3\n"+ "(Physical Model)\n"+ "\n"+ @@ -57,4 +58,3 @@ class TestPmd(unittest.TestCase): model.diff(model2) self.assertEqual(model, model2) - diff --git a/test/pmx_test.py b/test/pmx_test.py index e9185ee..858f55e 100644 --- a/test/pmx_test.py +++ b/test/pmx_test.py @@ -1,12 +1,15 @@ # coding: utf-8 import unittest import io -import pymeshio.pmd +import pymeshio.common +import pymeshio.pmd.reader import pymeshio.pmx.reader import pymeshio.pmx.writer +import pymeshio.converter -PMX_FILE=pymeshio.unicode('resources/初音ミクVer2.pmx') +PMD_FILE=pymeshio.common.unicode('resources/初音ミクVer2.pmd') +PMX_FILE=pymeshio.common.unicode('resources/初音ミクVer2.pmx') class TestPmx(unittest.TestCase): @@ -17,9 +20,9 @@ class TestPmx(unittest.TestCase): def test_read(self): model=pymeshio.pmx.reader.read_from_file(PMX_FILE) self.assertEqual(pymeshio.pmx.Model, model.__class__) - self.assertEqual(pymeshio.unicode('初音ミク'), model.name) - self.assertEqual(pymeshio.unicode('Miku Hatsune'), model.english_name) - self.assertEqual(pymeshio.unicode( + self.assertEqual(pymeshio.common.unicode('初音ミク'), model.name) + self.assertEqual(pymeshio.common.unicode('Miku Hatsune'), model.english_name) + self.assertEqual(pymeshio.common.unicode( "PolyMo用モデルデータ:初音ミク ver.2.3\r\n"+ "(物理演算対応モデル)\r\n"+ "\r\n"+ @@ -27,7 +30,7 @@ class TestPmx(unittest.TestCase): "データ変換 :あにまさ氏\r\n"+ "Copyright :CRYPTON FUTURE MEDIA, INC"), model.comment) - self.assertEqual(pymeshio.unicode( + self.assertEqual(pymeshio.common.unicode( "MMD Model: Miku Hatsune ver.2.3\r\n"+ "(Physical Model)\r\n"+ "\r\n"+ @@ -57,3 +60,14 @@ class TestPmx(unittest.TestCase): model2=pymeshio.pmx.reader.read(io.BytesIO(out.getvalue())) self.assertEqual(model, model2) + def test_convert(self): + # convert + pmd=pymeshio.pmd.reader.read_from_file(PMD_FILE) + converted=pymeshio.converter.pmd_to_pmx(pmd) + # validate + pmx=pymeshio.pmx.reader.read_from_file(PMX_FILE) + # check diffference + pmx.diff(converted) + #self.assertEqual(pmx, converted) + pymeshio.pmx.writer.write(io.open("tmp.pmx", "wb"), converted) +