From 094992419e74b3946ad4362e4fc9ab6aee0ff256 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Sun, 2 Oct 2011 22:37:47 +0900 Subject: [PATCH] refactoring pmd.writer --- pymeshio/common.py | 51 ++++++++++++-- pymeshio/mqo/__init__.py | 2 +- pymeshio/mqo/loader.py | 113 ++++++++++++++++--------------- pymeshio/pmd/__init__.py | 122 +++++++++++++++++++++++++++++++-- pymeshio/pmd/loader.py | 172 ++++++----------------------------------------- pymeshio/pmd/writer.py | 152 +++++++++++++++++++++++++++++++++++++++++ pymeshio/pmx/loader.py | 16 ++--- test/mqo_test.py | 2 +- test/mqo_test.pyc | Bin 901 -> 911 bytes test/pmd_test.py | 25 +++++-- test/pmd_test.pyc | Bin 2300 -> 2808 bytes test/pmx_test.py | 2 +- 12 files changed, 428 insertions(+), 229 deletions(-) create mode 100644 pymeshio/pmd/writer.py diff --git a/pymeshio/common.py b/pymeshio/common.py index dca807d..c8c2d75 100644 --- a/pymeshio/common.py +++ b/pymeshio/common.py @@ -21,6 +21,9 @@ class Vector2(object): def __str__(self): return "<%f %f>" % (self.x, self.y) + def __eq__(self, rhs): + return self.x==rhs.x and self.y==rhs.y + def __getitem__(self, key): if key==0: return self.x @@ -50,6 +53,9 @@ class Vector3(object): def __str__(self): return "<%f %f %f>" % (self.x, self.y, self.z) + def __eq__(self, rhs): + return self.x==rhs.x and self.y==rhs.y and self.z==rhs.z + def __getitem__(self, key): if key==0: return self.x @@ -212,6 +218,9 @@ class RGB(object): self.g=g self.b=b + def __eq__(self, rhs): + return self.r==rhs.r and self.g==rhs.g and self.b==rhs.b + def __getitem__(self, key): if key==0: return self.r @@ -270,14 +279,14 @@ def readall(path): class BinaryLoader(object): """general BinaryLoader """ - def __init__(self, io): - self.io=io + def __init__(self, ios): + self.ios=ios def is_end(self): - return not self.io.readable() + return not self.ios.readable() def unpack(self, fmt, size): - result=struct.unpack(fmt, self.io.read(size)) + result=struct.unpack(fmt, self.ios.read(size)) return result[0] def read_uint(self, size): @@ -321,3 +330,37 @@ class BinaryLoader(object): self.read_float() ) + +class BinaryWriter(object): + def __init__(self, ios): + self.ios=ios + + def write_text(self, v, size=None): + if size: + self.ios.write(struct.pack("={0}s".format(size), v)) + else: + self.ios.write(v) + + def write_float(self, v): + self.ios.write(struct.pack("f", v)) + + def write_uint(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_vector2(self, v): + self.ios.write(struct.pack("=2f", v.x, v.y)) + + def write_vector3(self, v): + self.ios.write(struct.pack("=3f", v.x, v.y, v.z)) + + def write_rgb(self, v): + self.ios.write(struct.pack("=3f", v.r, v.g, v.b)) + + diff --git a/pymeshio/mqo/__init__.py b/pymeshio/mqo/__init__.py index e00d9ae..45aca2e 100644 --- a/pymeshio/mqo/__init__.py +++ b/pymeshio/mqo/__init__.py @@ -233,7 +233,7 @@ class IO(object): def read(self, path): warnings.warn("'pymeshio.mqo.IO.read' will be replaced by 'pymeshio.mqo.loader.load'") - model=pymeshio.mqo.loader.load(path) + model=pymeshio.mqo.loader.load_from_file(path) if model: self.has_mikoto=model.has_mikoto self.materials=model.materials diff --git a/pymeshio/mqo/loader.py b/pymeshio/mqo/loader.py index 561dd67..60f7318 100644 --- a/pymeshio/mqo/loader.py +++ b/pymeshio/mqo/loader.py @@ -23,8 +23,8 @@ class Loader(object): "eof", "io", "lines", "materials", "objects", ] - def __init__(self, io): - self.io=io + def __init__(self, ios): + self.ios=ios self.eof=False self.lines=0 @@ -33,7 +33,7 @@ class Loader(object): self.lines, len(self.materials), len(self.objects)) def getline(self): - line=self.io.readline() + line=self.ios.readline() self.lines+=1 if line=="": self.eof=True @@ -168,59 +168,64 @@ class Loader(object): return False -def load(path): - with open(path, 'rb') as io: - loader=Loader(io) - model=pymeshio.mqo.Model() +def load_from_file(path): + with open(path, 'rb') as ios: + load(ios) - line=loader.getline() - if line!="Metasequoia Document": - print("invalid signature") - return False - line=loader.getline() - if line!="Format Text Ver 1.0": - print("unknown version: %s" % line) +def load(ios): + assert(isinstance(ios, io.IOBase)) + loader=Loader(ios) + model=pymeshio.mqo.Model() - while True: - line=loader.getline() - if line==None: - # eof - break; - if line=="": - # empty line - continue + line=loader.getline() + if line!="Metasequoia Document": + print("invalid signature") + return False - tokens=line.split() - key=tokens[0] - if key=="Eof": - return model - elif key=="Scene": - if not loader.readChunk(): - return - elif key=="Material": - materials=loader.readMaterial() - if not materials: - return - model.materials=materials - elif key=="Object": - firstQuote=line.find('"') - secondQuote=line.find('"', firstQuote+1) - obj=loader.readObject(line[firstQuote+1:secondQuote]) - if not obj: - return - model.objects.append(obj) - elif key=="BackImage": - if not loader.readChunk(): - return - elif key=="IncludeXml": - firstQuote=line.find('"') - secondQuote=line.find('"', firstQuote+1) - print("IncludeXml", line[firstQuote+1:secondQuote]) - else: - print("unknown key: %s" % key) - if not loader.readChunk(): - return - # error not reach here - raise ParseException("invalid eof") + line=loader.getline() + if line!="Format Text Ver 1.0": + print("unknown version: %s" % line) + + while True: + line=loader.getline() + if line==None: + # eof + break; + if line=="": + # empty line + continue + + tokens=line.split() + key=tokens[0] + if key=="Eof": + return model + elif key=="Scene": + if not loader.readChunk(): + return + elif key=="Material": + materials=loader.readMaterial() + if not materials: + return + model.materials=materials + elif key=="Object": + firstQuote=line.find('"') + secondQuote=line.find('"', firstQuote+1) + obj=loader.readObject(line[firstQuote+1:secondQuote]) + if not obj: + return + model.objects.append(obj) + elif key=="BackImage": + if not loader.readChunk(): + return + elif key=="IncludeXml": + firstQuote=line.find('"') + secondQuote=line.find('"', firstQuote+1) + print("IncludeXml", line[firstQuote+1:secondQuote]) + else: + print("unknown key: %s" % key) + if not loader.readChunk(): + return + # error not reach here + raise ParseException("invalid eof") diff --git a/pymeshio/pmd/__init__.py b/pymeshio/pmd/__init__.py index c365c07..e8c9a44 100644 --- a/pymeshio/pmd/__init__.py +++ b/pymeshio/pmd/__init__.py @@ -40,6 +40,17 @@ class Vertex(object): str(self.uv), self.bone0, self.bone1, self.weight0) + def __eq__(self, rhs): + return ( + self.pos==rhs.pos + and self.normal==rhs.normal + and self.uv==rhs.uv + and self.bone0==rhs.bone0 + and self.bone1==rhs.bone1 + and self.weight0==rhs.weight0 + and self.edge_flag==rhs.edge_flag + ) + def __getitem__(self, key): if key==0: return self.pos.x @@ -90,6 +101,19 @@ class Material(object): self.diffuse[2], self.diffuse[3], ) + def __eq__(self, rhs): + return ( + self.diffuse_color==rhs.diffuse_color + and self.alpha==rhs.alpha + and self.specular_factor==rhs.specular_factor + and self.specular_color==rhs.specular_color + and self.ambient_color==rhs.ambient_color + and self.toon_index==rhs.toon_index + and self.edge_flag==rhs.edge_flag + and self.vertex_count==rhs.vertex_count + and self.texture_file==rhs.texture_file + ) + class Bone(object): """pmd material struct. @@ -137,6 +161,20 @@ class Bone(object): self.children=[] self.english_name='' + def __eq__(self, rhs): + return ( + self.name==rhs.name + and self.index==rhs.index + and self.type==rhs.type + and self.parent_index==rhs.parent_index + and self.tail_index==rhs.tail_index + and self.tail==rhs.tail + and self.ik_index==rhs.ik_index + and self.pos==rhs.pos + and self.children==rhs.children + and self.english_name==rhs.english_name + ) + def hasParent(self): return self.parent_index!=0xFFFF @@ -268,11 +306,20 @@ class IK(object): def __str__(self): return "" %(self.index, self.target, self.iterations, self.weight, '-'.join([str(i) for i in self.children]), len(self.children)) + def __eq__(self, rhs): + return ( + self.index==rhs.index + and self.target==rhs.target + and self.iterations==rhs.iterations + and self.weight==rhs.weight + and self.children==rhs.children + ) + -class Skin(object): +class Morph(object): __slots__=['name', 'type', 'indices', 'pos_list', 'english_name', 'vertex_count'] - def __init__(self, name='skin'): + def __init__(self, name): self.name=name self.type=None self.indices=[] @@ -288,6 +335,16 @@ class Skin(object): return '' % ( self.name, self.type, len(self.indices)) + def __eq__(self, rhs): + return ( + self.name==rhs.name + and self.type==rhs.type + and self.indices==rhs.indices + and self.pos_list==rhs.pos_list + and self.english_name==rhs.english_name + and self.vertex_count==rhs.vertex_count + ) + class BoneGroup(object): __slots__=['_name', '_english_name'] @@ -349,6 +406,24 @@ class RigidBody(object): self.friction=friction self.mode=mode + def __eq__(self, rhs): + return ( + self.name==rhs.name + and self.bone_index==rhs.bone_index + and self.collision_group==rhs.collision_group + and self.no_collision_group==rhs.no_collision_group + and self.shape_type==rhs.shape_type + and self.shape_size==rhs.shape_size + and self.shape_position==rhs.shape_position + and self.shape_rotation==rhs.shape_rotation + and self.mass==rhs.mass + and self.linear_damping==rhs.linear_damping + and self.angular_damping==rhs.angular_damping + and self.restitution==rhs.restitution + and self.friction==rhs.friction + and self.mode==rhs.mode + ) + class Joint(object): __slots__=[ 'name', 'rigidbody_index_a', 'rigidbody_index_b', @@ -376,6 +451,21 @@ class Joint(object): self.spring_constant_translation=spring_constant_translation self.spring_constant_rotation=spring_constant_rotation + def __eq__(self, rhs): + return ( + self.name==rhs.name + and self.rigidbody_index_a==rhs.rigidbody_index_a + and self.rigidbody_index_b==rhs.rigidbody_index_b + and self.position==rhs.position + and self.rotation==rhs.rotation + and self.translation_limit_max==rhs.translation_limit_max + and self.translation_limit_min==rhs.translation_limit_min + and self.rotation_limit_max==rhs.rotation_limit_max + and self.rotation_limit_min==rhs.rotation_limit_min + and self.spring_constant_translation==rhs.spring_constant_translation + and self.spring_constant_rotation==rhs.spring_constant_rotation + ) + class ToonTextures(object): __slots__=['_toon_textures'] @@ -412,9 +502,11 @@ class Model(object): 'vertices', 'indices', 'materials', 'bones', 'ik_list', 'morphs', 'morph_indices', 'bone_group_list', 'bone_display_list', + 'bone_group_english_list', 'toon_textures', - 'no_parent_bones', 'rigidbodies', 'joints', + + 'no_parent_bones', ] def __init__(self, version): self.version=version @@ -432,6 +524,7 @@ class Model(object): self.bone_group_list=[] self.bone_display_list=[] # extend + self.bone_group_english_list=[] self.toon_textures=ToonTextures() self.rigidbodies=[] self.joints=[] @@ -446,6 +539,27 @@ class Model(object): 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 __eq__(self, rhs): + return ( + self.name==rhs.name + and self.comment==rhs.comment + and self.english_name==rhs.english_name + and self.english_comment==rhs.english_comment + and self.vertices==rhs.vertices + and self.indices==rhs.indices + and self.materials==rhs.materials + and self.bones==rhs.bones + and self.ik_list==rhs.ik_list + and self.morphs==rhs.morphs + and self.morph_indices==rhs.morph_indices + and self.bone_group_list==rhs.bone_group_list + and self.bone_display_list==rhs.bone_display_list + and self.bone_group_english_list==rhs.bone_group_english_list + and self.toon_textures==rhs.toon_textures + and self.rigidbodies==rhs.rigidbodies + and self.joints==rhs.joints + ) + class IO(object): def __init__(self): @@ -453,7 +567,7 @@ class IO(object): def read(self, path): warnings.warn("'pymeshio.mqo.IO.read' will be replaced by 'pymeshio.mqo.loader.load'") - model=pymeshio.pmd.loader.load(path) + model=pymeshio.pmd.loader.load_from_file(path) if model: return True diff --git a/pymeshio/pmd/loader.py b/pymeshio/pmd/loader.py index c897f22..3f16099 100644 --- a/pymeshio/pmd/loader.py +++ b/pymeshio/pmd/loader.py @@ -7,8 +7,8 @@ import pymeshio.pmd class Loader(pymeshio.common.BinaryLoader): """pmx loader """ - def __init__(self, io, version): - super(Loader, self).__init__(io) + def __init__(self, ios, version): + super(Loader, self).__init__(ios) self.version=version def read_text(self, size): @@ -65,13 +65,13 @@ class Loader(pymeshio.common.BinaryLoader): 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 + morph=pymeshio.pmd.Morph(self.read_text(20)) + morph_size = self.read_uint(4) + morph.type = self.read_uint(1) + for j in range(morph_size): + morph.indices.append(self.read_uint(4)) + morph.pos_list.append(self.read_vector3()) + return morph def read_rigidbody(self): return pymeshio.pmd.RigidBody( @@ -150,8 +150,8 @@ def __load(loader, model): 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) + model.bone_group_english_list=[loader.read_text(50) + for _ in model.bone_group_list] ############################################################ # extend2: toon_textures @@ -176,10 +176,13 @@ def __load(loader, model): 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))) +def load_from_file(path): + return load(io.BytesIO(pymeshio.common.readall(path))) + + +def load(ios): + assert(isinstance(ios, io.IOBase)) + loader=pymeshio.common.BinaryLoader(ios) # header signature=loader.unpack("3s", 3) @@ -189,11 +192,12 @@ def load(path): version=loader.read_float() model=pymeshio.pmd.Model(version) - loader=Loader(loader.io, version) + loader=Loader(loader.ios, version) if(__load(loader, model)): # check eof if not loader.is_end(): - print("can not reach eof.") + #print("can not reach eof.") + pass # build bone tree for i, child in enumerate(model.bones): @@ -206,143 +210,11 @@ def load(path): 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/pmd/writer.py b/pymeshio/pmd/writer.py new file mode 100644 index 0000000..b1340c4 --- /dev/null +++ b/pymeshio/pmd/writer.py @@ -0,0 +1,152 @@ +# coding: utf-8 +import io +import struct +import pymeshio.common +import pymeshio.pmd + + +class Writer(pymeshio.common.BinaryWriter): + def write_veritices(self, vertices): + self.write_uint(len(vertices), 4) + for v in vertices: + self.write_vector3(v.pos) + self.write_vector3(v.normal) + self.write_vector2(v.uv) + self.write_uint(v.bone0, 2) + self.write_uint(v.bone1, 2) + self.write_uint(v.weight0, 1) + self.write_uint(v.edge_flag, 1) + + def write_indices(self, indices): + self.write_uint(len(indices), 4) + self.ios.write(struct.pack("=%dH" % len(indices), *indices)) + + def write_materials(self, materials): + self.write_uint(len(materials), 4) + for m in materials: + self.write_rgb(m.diffuse_color) + self.write_float(m.alpha) + self.write_float(m.specular_factor) + self.write_rgb(m.specular_color) + self.write_rgb(m.ambient_color) + self.write_uint(m.toon_index, 1) + self.write_uint(m.edge_flag, 1) + self.write_uint(m.vertex_count, 4) + self.write_text(m.texture_file, 20) + + def write_bones(self, bones): + self.write_uint(len(bones), 2) + sBone=struct.Struct("=20sHHBH3f") + assert(sBone.size==39) + for b in bones: + self.write_text(b.name, 20) + self.write_uint(b.parent_index, 2) + self.write_uint(b.tail_index, 2) + self.write_uint(b.type, 1) + self.write_uint(b.ik_index, 2) + self.write_vector3(b.pos) + + def write_ik_list(self, ik_list): + self.write_uint(len(ik_list), 2) + for ik in ik_list: + self.write_uint(ik.index, 2) + self.write_uint(ik.target, 2) + self.write_uint(len(ik.children), 1) + self.write_uint(ik.iterations, 2) + self.write_float(ik.weight) + self.ios.write(struct.pack("=%dH" % len(ik.children), *ik.children)) + + def write_morphs(self, morphs): + self.write_uint(len(morphs), 2) + for morph in morphs: + self.write_text(morph.name, 20) + self.write_uint(len(morph.indices), 4) + self.write_uint(morph.type, 1) + for i, v in zip(morph.indices, morph.pos_list): + self.write_uint(i, 4) + self.write_vector3(v) + + def write_morph_indices(self, morph_indices): + self.write_uint(len(morph_indices), 1) + self.ios.write(struct.pack("=%dH" % len(morph_indices), *morph_indices)) + + def write_bone_group_list(self, bone_group_list): + self.write_uint(len(bone_group_list), 1) + for g in bone_group_list: + self.write_text(g, 50) + + def write_bone_display_list(self, bone_display_list): + self.write_uint(len(bone_display_list), 4) + for l in bone_display_list: + self.write_uint(l[0], 2) + self.write_uint(l[1], 1) + + def write_rigidbodies(self, rigidbodies): + self.write_uint(len(rigidbodies), 4) + for r in rigidbodies: + self.write_text(r.name, 20) + self.write_uint(r.bone_index, 2) + self.write_uint(r.collision_group, 1) + self.write_uint(r.no_collision_group, 2) + self.write_uint(r.shape_type, 1) + self.write_vector3(r.shape_size) + self.write_vector3(r.shape_position) + self.write_vector3(r.shape_rotation) + self.write_float(r.mass) + self.write_float(r.linear_damping) + self.write_float(r.angular_damping) + self.write_float(r.restitution) + self.write_float(r.friction) + self.write_uint(r.mode, 1) + + def write_joints(self, joints): + self.write_uint(len(joints), 4) + for j in joints: + self.write_text(j.name, 20) + self.write_uint(j.rigidbody_index_a, 4) + self.write_uint(j.rigidbody_index_b, 4) + self.write_vector3(j.position) + self.write_vector3(j.rotation) + self.write_vector3(j.translation_limit_min) + self.write_vector3(j.translation_limit_max) + self.write_vector3(j.rotation_limit_min) + self.write_vector3(j.rotation_limit_max) + self.write_vector3(j.spring_constant_translation) + self.write_vector3(j.spring_constant_rotation) + + +def write(ios, model): + assert(isinstance(ios, io.IOBase)) + assert(isinstance(model, pymeshio.pmd.Model)) + writer=Writer(ios) + writer.write_text(b"Pmd") + writer.write_float(model.version) + writer.write_text(model.name, 20) + writer.write_text(model.comment, 256) + writer.write_veritices(model.vertices) + writer.write_indices(model.indices) + writer.write_materials(model.materials) + writer.write_bones(model.bones) + writer.write_ik_list(model.ik_list) + writer.write_morphs(model.morphs) + writer.write_morph_indices(model.morph_indices) + writer.write_bone_group_list(model.bone_group_list) + writer.write_bone_display_list(model.bone_display_list) + # extend data + writer.write_uint(1, 1) + writer.write_text(model.english_name, 20) + writer.write_text(model.english_comment, 256) + for bone in model.bones: + writer.write_text(bone.english_name, 20) + for skin in model.morphs: + if skin.name==b'base': + continue + writer.write_text(skin.english_name, 20) + for english in model.bone_group_english_list: + writer.write_text(english, 50) + for toon_texture in model.toon_textures: + writer.write_text(toon_texture, 100) + writer.write_rigidbodies(model.rigidbodies) + writer.write_joints(model.joints) + return True + diff --git a/pymeshio/pmx/loader.py b/pymeshio/pmx/loader.py index 2802b43..b78ed96 100644 --- a/pymeshio/pmx/loader.py +++ b/pymeshio/pmx/loader.py @@ -7,7 +7,7 @@ import pymeshio.pmx class Loader(pymeshio.common.BinaryLoader): """pmx loader """ - def __init__(self, io, + def __init__(self, ios, text_encoding, extended_uv, vertex_index_size, @@ -17,7 +17,7 @@ class Loader(pymeshio.common.BinaryLoader): morph_index_size, rigidbody_index_size ): - super(Loader, self).__init__(io) + super(Loader, self).__init__(ios) self.read_text=self.get_read_text(text_encoding) if extended_uv>0: raise pymeshio.common.ParseException( @@ -267,14 +267,14 @@ class Loader(pymeshio.common.BinaryLoader): spring_constant_rotation=self.read_vector3()) -def load(path): - # general binary loader - loader=pymeshio.common.BinaryLoader( - io.BytesIO( - pymeshio.common.readall(path))) - #loader=pymeshio.common.BinaryLoader(open(path, 'rb')) +def load_from_file(path): + return load(io.BytesIO(pymeshio.common.readall(path))) +def load(ios): + assert(isinstance(ios, io.IOBase)) + loader=pymeshio.common.BinaryLoader(ios) + # header signature=loader.unpack("4s", 4) if signature!=b"PMX ": diff --git a/test/mqo_test.py b/test/mqo_test.py index 5b054c8..1be8cae 100644 --- a/test/mqo_test.py +++ b/test/mqo_test.py @@ -8,7 +8,7 @@ def test_old_mqo_load(): assert io.read(MQO_FILE) def test_mqo_load(): - model=pymeshio.mqo.loader.load(MQO_FILE) + model=pymeshio.mqo.loader.load_from_file(MQO_FILE) print(model.materials) assert pymeshio.mqo.Model==model.__class__ assert 6==len(model.materials) diff --git a/test/mqo_test.pyc b/test/mqo_test.pyc index 3f8c2e30ada66cff2aea74afbc6aaa58c9edd5c3..c489dfc339ab6915cbd66e06cd08ecc522387f04 100644 GIT binary patch delta 40 vcmZo=?`LOc{>;l&;MB2^U6DzMkAZ<9CqFSIKCLJ}H$E*hCv~#{Qz#<<+)N8u delta 30 lcmeBYZ)Im^{>;nuYC+pZc10!*76t}}oczR;%~njIi~xmx2onGR diff --git a/test/pmd_test.py b/test/pmd_test.py index 606ca10..a4dc095 100644 --- a/test/pmd_test.py +++ b/test/pmd_test.py @@ -1,16 +1,18 @@ # coding: utf-8 -import pymeshio.pmd -import pymeshio.pmd.loader import sys +import io import unittest +import pymeshio.pmd +import pymeshio.pmd.loader +import pymeshio.pmd.writer PMD_FILE=u'resources/初音ミクVer2.pmd' def test_old_pmd_load(): - io=pymeshio.pmd.IO() - assert io.read(PMD_FILE) + loader=pymeshio.pmd.IO() + assert loader.read(PMD_FILE) class TestPmd(unittest.TestCase): @@ -18,8 +20,8 @@ class TestPmd(unittest.TestCase): def setUp(self): pass - def test_read(self): - model=pymeshio.pmd.loader.load(PMD_FILE) + def test_load(self): + model=pymeshio.pmd.loader.load_from_file(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) @@ -48,3 +50,14 @@ class TestPmd(unittest.TestCase): self.assertEqual(45, len(model.rigidbodies)) self.assertEqual(27, len(model.joints)) + def test_write(self): + # read source file + buf=pymeshio.common.readall(PMD_FILE) + # load and write to out + model=pymeshio.pmd.loader.load(io.BytesIO(buf)) + out=io.BytesIO() + pymeshio.pmd.writer.write(out, model) + # read out buffer again + model2=pymeshio.pmd.loader.load(io.BytesIO(out.getvalue())) + self.assertEqual(model, model2) + diff --git a/test/pmd_test.pyc b/test/pmd_test.pyc index cc09a74f13e21074e9c937a1b299da1c82d846ed..2a940e5d034b45e94b2c071805bf0a903d2a0337 100644 GIT binary patch delta 751 zcmZ8eJ#W-N5S`uickUtx385h%NF;-z14W`opcFI#HWhA8cjrB@Wyg`d&gmpaS6n0z z9db=WN1Y!*$i&`?k?vpFM#?HRxM*f;xje_#K#wGco1!Fc@PXacK8;QuLFrP0Os zF~|U-znDS9x;%%7cUVAVb=dv~I|gH?3$cI;r1BuPKygTYn64w2P1z;Dn<)5He+wL( zn-!y2mF;bQ*uH05tlxfS4d}hEGK=sUjziku zQP@W>(Lj^1Ns;Hp2~Gtl)hHfinY0i~>b+75cfvJRnO{PV;zhC8e#s+2%E@^>Eng6^`)jKRUmM*Z=?k delta 314 zcmew%`bV&y`7iV?N z7*c?;tPCm43@tz{Yz!$Z45=&(S?mmHK<%s`!Da@A$S4kwp}`t#Kno^L-^<1Xq%-p; zZ{T#9yogbZk$dt^MlA&?pkOM@UXW=_AWa|!Gec0Y2Ge97rWQt_%@dgxF^iOdOv=em zOi3*&VSzF?d$R>FvKFN#rie~nz;3{#!7{m)Q7dq$IVtWO6Q7xd0DPfQJzbnc0{*SpgljIAs6; diff --git a/test/pmx_test.py b/test/pmx_test.py index c8e060a..0a040b5 100644 --- a/test/pmx_test.py +++ b/test/pmx_test.py @@ -12,7 +12,7 @@ class TestPmx(unittest.TestCase): pass def test_read(self): - model=pymeshio.pmx.loader.load(PMX_FILE) + model=pymeshio.pmx.loader.load_from_file(PMX_FILE) self.assertEqual(pymeshio.pmx.Model, model.__class__) self.assertEqual(u'初音ミク', model.name) self.assertEqual(u'Miku Hatsune', model.english_name) -- 2.11.0