4 http://blog.goo.ne.jp/torisu_tetosuki/e/209ad341d3ece2b1b4df24abf619d6e4
10 from .compatibility import *
22 weight0: bone0 influence
25 __slots__=['pos', 'normal', 'uv', 'bone0', 'bone1', 'weight0', 'edge_flag']
26 def __init__(self, x=0, y=0, z=0, nx=0, ny=0, nz=0, u=0, v=0,
27 bone0=0, bone1=0, weight0=0, edge_flag=0):
28 self.pos=Vector3(x, y, z)
29 self.normal=Vector3(nx, ny, nz)
34 self.edge_flag=edge_flag
37 return "<%s %s %s, (%d, %d, %d)>" % (
41 self.bone0, self.bone1, self.weight0)
43 def __getitem__(self, key):
54 class Material(object):
55 """pmd material struct.
62 vertex_count: indices length
63 _texture: texture file path
68 'diffuse', 'shinness', 'specular',
69 'ambient', 'vertex_count', '_texture', 'toon_index', 'flag',
71 def getTexture(self): return from_str(self._texture)
72 def setTexture(self, texture): self._texture=to_str(texture)
73 texture=property(getTexture, setTexture)
75 def __init__(self, dr=0, dg=0, db=0, alpha=1,
76 specular=0, sr=0, sg=0, sb=0, ar=0, ag=0, ab=0):
77 self.diffuse=RGBA(dr, dg, db, alpha)
78 self.specular=RGBA(sr, sg, sb)
79 self.shinness=specular
80 self.ambient=RGBA(ar, ag, ab)
87 return "<Material [%f, %f, %f, %f]>" % (
88 self.diffuse[0], self.diffuse[1],
89 self.diffuse[2], self.diffuse[3],
94 """pmd material struct.
122 __slots__=['_name', 'index', 'type', 'parent', 'ik', 'pos',
123 'children', '_english_name', 'ik_index',
124 'parent_index', 'tail_index', 'tail',
128 return str(multibyte) in python2
129 return bytes in python3
131 return from_str(self._name)
132 def setName(self, name): self._name=to_str(name)
133 name=property(getName, setName)
134 def getEnglishName(self): return from_str(self._english_name)
135 def setEnglishName(self, english_name): self._english_name=to_str(english_name)
136 english_name=property(getEnglishName, setEnglishName)
138 def __init__(self, name='bone', type=0):
142 self.parent_index=0xFFFF
144 self.tail=Vector3(0, 0, 0)
147 self.pos=Vector3(0, 0, 0)
152 return self.parent_index!=0xFFFF
155 return self.tail_index!=0
157 def display(self, indent=[]):
160 for i, is_end in enumerate(indent):
164 prefix+=' ' if is_end else ' |'
165 uni='%s +%s(%s)' % (prefix, unicode(self), self.english_name)
166 print(uni.encode(ENCODING))
168 uni='%s(%s)' % (unicode(self), self.english_name)
169 print(uni.encode(ENCODING))
171 child_count=len(self.children)
172 for i in range(child_count):
173 child=self.children[i]
175 child.display(indent+[False])
178 child.display(indent+[True])
181 class Bone_Rotate(Bone):
183 def __init__(self, name):
184 super(Bone_Rotate, self).__init__(name, 0)
186 return '<ROTATE %s>' % (self.name)
188 class Bone_RotateMove(Bone):
190 def __init__(self, name):
191 super(Bone_RotateMove, self).__init__(name, 1)
193 return '<ROTATE_MOVE %s>' % (self.name)
197 def __init__(self, name):
198 super(Bone_IK, self).__init__(name, 2)
200 return '<IK %s>' % (self.name)
202 class Bone_IKRotateInfl(Bone):
204 def __init__(self, name):
205 super(Bone_IKRotateInfl, self).__init__(name, 4)
207 return '<IK_ROTATE_INFL %s>' % (self.name)
209 class Bone_RotateInfl(Bone):
211 def __init__(self, name):
212 super(Bone_RotateInfl, self).__init__(name, 5)
214 return '<ROTATE_INFL %s>' % (self.name)
216 class Bone_IKTarget(Bone):
218 def __init__(self, name):
219 super(Bone_IKTarget, self).__init__(name, 6)
221 return '<IK_TARGET %s>' % (self.name)
223 class Bone_Unvisible(Bone):
225 def __init__(self, name):
226 super(Bone_Unvisible, self).__init__(name, 7)
228 return '<UNVISIBLE %s>' % (self.name)
230 class Bone_Rolling(Bone):
232 def __init__(self, name):
233 super(Bone_Rolling, self).__init__(name, 8)
235 return '<ROLLING %s>' % (self.name)
237 class Bone_Tweak(Bone):
239 def __init__(self, name):
240 super(Bone_Tweak, self).__init__(name, 9)
242 return '<TWEAK %s>' % (self.name)
245 def createBone(name, type):
247 return Bone_Rotate(name)
249 return Bone_RotateMove(name)
253 raise Exception("no used bone type: 3(%s)" % name)
255 return Bone_IKRotateInfl(name)
257 return Bone_RotateInfl(name)
259 return Bone_IKTarget(name)
261 return Bone_Unvisible(name)
263 return Bone_Rolling(name)
265 return Bone_Tweak(name)
267 raise Exception("unknown bone type: %d(%s)", type, name)
271 __slots__=['index', 'target', 'iterations', 'weight', 'length', 'children']
272 def __init__(self, index=0, target=0):
280 return "<IK index: %d, target: %d, iterations: %d, weight: %f, children: %s(%d)>" %(self.index, self.target, self.iterations, self.weight, '-'.join([str(i) for i in self.children]), len(self.children))
284 __slots__=['_name', 'type', 'indices', 'pos_list', '_english_name',
286 def getName(self): return from_str(self._name)
287 def setName(self, name): self._name=to_str(name)
288 name=property(getName, setName)
289 def getEnglishName(self): return from_str(self._english_name)
290 def setEnglishName(self, english_name): self._english_name=to_str(english_name)
291 english_name=property(getEnglishName, setEnglishName)
293 def __init__(self, name='skin'):
301 def append(self, index, x, y, z):
302 self.indices.append(index)
303 self.pos_list.append(Vector3(x, y, z))
306 return '<Skin name: "%s", type: %d, vertex: %d>' % (
307 self.name, self.type, len(self.indices))
310 class BoneGroup(object):
311 __slots__=['_name', '_english_name']
312 def getName(self): return from_str(self._name)
313 def setName(self, name): self._name=to_str(name)
314 name=property(getName, setName)
315 def getEnglishName(self): return from_str(self._english_name)
316 def setEnglishName(self, english_name): self._english_name=to_str(english_name)
317 english_name=property(getEnglishName, setEnglishName)
319 def __init__(self, name='group'): self._name=name; self._english_name='center'
326 RIGIDBODY_KINEMATICS=0
328 RIGIDBODY_PHYSICS_WITH_BONE=2
331 class RigidBody(object):
332 __slots__=['_name', 'boneIndex', 'group', 'target', 'shapeType',
333 'w', 'h', 'd', 'position', 'rotation', 'weight',
334 'linearDamping', 'angularDamping', 'restitution', 'friction', 'processType'
336 def getName(self): return from_str(self._name)
337 def setName(self, name): self._name=to_str(name)
338 name=property(getName, setName)
340 def __init__(self, name):
342 self.position=Vector3()
343 self.rotation=Vector3()
346 class Constraint(object):
347 __slots__=[ '_name', 'rigidA', 'rigidB', 'pos', 'rot',
348 'constraintPosMin', 'constraintPosMax',
349 'constraintRotMin', 'constraintRotMax',
350 'springPos', 'springRot',
352 def getName(self): return from_str(self._name)
353 def setName(self, name): self._name=to_str(name)
354 name=property(getName, setName)
356 def __init__(self, name):
360 self.constraintPosMin=Vector3()
361 self.constraintPosMax=Vector3()
362 self.constraintRotMin=Vector3()
363 self.constraintRotMax=Vector3()
364 self.springPos=Vector3()
365 self.springRot=Vector3()
368 class ToonTextures(object):
369 __slots__=['_toon_textures']
371 self._toon_textures=[]
373 self._toon_textures.append('toon%02d.bmp' % (i+1))
375 def __getitem__(self, key):
376 return from_str(self._toon_textures[key])
378 def __setitem__(self, key, value):
379 self._toon_textures[key]=to_str(value)
382 for toon_texture in self._toon_textures:
383 yield from_str(toon_texture)
394 version: pmd version number
397 __slots__=['io', 'end', 'pos',
398 'version', '_name', '_comment',
399 '_english_name', '_english_comment',
400 'vertices', 'indices', 'materials', 'bones',
401 'ik_list', 'morph_list',
402 'face_list', 'bone_group_list', 'bone_display_list',
405 'rigidbodies', 'constraints',
407 def getName(self): return from_str(self._name)
408 def setName(self, name): self._name=to_str(name)
409 name=property(getName, setName)
410 def getEnglishName(self): return from_str(self._english_name)
411 def setEnglishName(self, english_name): self._english_name=to_str(english_name)
412 english_name=property(getEnglishName, setEnglishName)
413 def getComment(self): return from_str(self._comment)
414 def setComment(self, comment): self._comment=to_str(comment)
415 comment=property(getComment, setComment)
416 def getEnglishComment(self): return from_str(self._english_comment)
417 def setEnglishComment(self, english_comment): self._english_comment=to_str(english_comment)
418 english_comment=property(getEnglishComment, setEnglishComment)
425 self.english_comment=''
433 self.bone_group_list=[]
434 self.bone_display_list=[]
436 self.toon_textures=ToonTextures()
440 self.no_parent_bones=[]
442 def each_vertex(self): return self.vertices
443 def getUV(self, i): return self.vertices[i].uv
446 self.vertices.append(v)
448 def addMaterial(self):
450 self.materials.append(m)
458 self.ik_list.append(ik)
462 self.morph_list.append(s)
464 def addBoneGroup(self):
466 self.bone_group_list.append(g)
468 def addBoneDisplay(self, b, g):
469 self.bone_display_list.append((b, g))
472 return '<PMDLoader version: %g, model: "%s", vertex: %d, face: %d, material: %d, bone: %d ik: %d, skin: %d>' % (
473 self.version, self.name, len(self.vertices), len(self.indices),
474 len(self.materials), len(self.bones), len(self.ik_list), len(self.morph_list))
476 def _check_position(self):
477 self.pos=self.io.tell()
479 def read(self, path):
480 size=os.path.getsize(path)
481 with open(path, "rb") as f:
482 return self.load(path, f, size)
484 def load(self, path, io, end):
486 self.pos=self.io.tell()
488 self._check_position()
490 if not self._loadHeader():
492 self._check_position()
494 if not self._loadVertex():
496 self._check_position()
498 if not self._loadFace():
500 self._check_position()
502 if not self._loadMaterial():
504 self._check_position()
506 if not self._loadBone():
508 self._check_position()
510 if not self._loadIK():
512 self._check_position()
514 if not self._loadSkin():
516 self._check_position()
518 if not self._loadSkinIndex():
520 self._check_position()
522 if not self._loadBoneName():
524 self._check_position()
526 if not self._loadBoneIndex():
528 self._check_position()
530 if not self._loadExtend():
531 print('fail to loadExtend')
535 if self.io.tell()!=self.end:
536 print("can not reach eof.")
537 print("current: %d, end: %d, remain: %d" % (
538 self.io.tell(), self.end, self.end-self.io.tell()))
541 for i, child in enumerate(self.bones):
542 if child.parent_index==0xFFFF:
544 self.no_parent_bones.append(child)
548 parent=self.bones[child.parent_index]
550 parent.children.append(child)
553 child.tail=self.bones[child.tail_index].pos
557 def write(self, path):
563 io.write(struct.pack("f", self.version))
564 io.write(struct.pack("20s", self.name))
565 io.write(struct.pack("256s", self.comment))
568 io.write(struct.pack("I", len(self.vertices)))
569 sVertex=struct.Struct("=8f2H2B") # 38byte
570 assert(sVertex.size==38)
571 for v in self.vertices:
573 v.pos[0], v.pos[1], v.pos[2],
574 v.normal[0], v.normal[1], v.normal[2],
576 v.bone0, v.bone1, v.weight0, v.edge_flag)
580 io.write(struct.pack("I", len(self.indices)))
581 io.write(struct.pack("=%dH" % len(self.indices), *self.indices))
584 io.write(struct.pack("I", len(self.materials)))
585 sMaterial=struct.Struct("=3fff3f3fBBI20s") # 70byte
586 assert(sMaterial.size==70)
587 for m in self.materials:
588 io.write(sMaterial.pack(
589 m.diffuse[0], m.diffuse[1], m.diffuse[2], m.diffuse[3],
591 m.specular[0], m.specular[1], m.specular[2],
592 m.ambient[0], m.ambient[1], m.ambient[2],
593 m.toon_index, m.flag,
599 io.write(struct.pack("H", len(self.bones)))
600 sBone=struct.Struct("=20sHHBH3f")
601 assert(sBone.size==39)
605 b.parent_index, b.tail_index, b.type, b.ik_index,
606 b.pos[0], b.pos[1], b.pos[2]))
609 io.write(struct.pack("H", len(self.ik_list)))
610 for ik in self.ik_list:
611 io.write(struct.pack("=2HBHf",
612 ik.index, ik.target, ik.length, ik.iterations, ik.weight
614 for c in ik.children:
615 io.write(struct.pack("H", c))
618 io.write(struct.pack("H", len(self.morph_list)))
619 for s in self.morph_list:
620 io.write(struct.pack("20sIB",
621 s.name, len(s.indices), s.type))
622 for i, v in zip(s.indices, s.pos_list):
623 io.write(struct.pack("I3f", i, v[0], v[1], v[2]))
626 io.write(struct.pack("B", len(self.face_list)))
627 for i in self.face_list:
628 io.write(struct.pack("H", i))
631 io.write(struct.pack("B", len(self.bone_group_list)))
632 for g in self.bone_group_list:
633 io.write(struct.pack("50s", g.name))
635 io.write(struct.pack("I", len(self.bone_display_list)))
636 for l in self.bone_display_list:
637 io.write(struct.pack("=HB", *l))
639 ############################################################
641 ############################################################
642 io.write(struct.pack("B", 1))
644 io.write(struct.pack("=20s", self.english_name))
645 io.write(struct.pack("=256s", self.english_comment))
647 for bone in self.bones:
648 io.write(struct.pack("=20s", bone.english_name))
650 for skin in self.morph_list:
652 if skin.name==b'base':
654 io.write(struct.pack("=20s", skin.english_name))
656 for bone_group in self.bone_group_list:
657 io.write(struct.pack("50s", bone_group.english_name))
659 for toon_texture in self.toon_textures:
660 io.write(struct.pack("=100s", toon_texture))
662 io.write(struct.pack("I", len(self.rigidbodies)))
663 for r in self.rigidbodies:
664 io.write(struct.pack("=20sHBHB14fB",
665 r.name, r.boneIndex, r.group, r.target, r.shapeType,
667 r.position.x, r.position.y, r.position.z,
668 r.rotation.x, r.rotation.y, r.rotation.z,
670 r.linearDamping, r.angularDamping, r.restitution,
671 r.friction, r.processType))
674 io.write(struct.pack("I", len(self.constraints)))
675 for c in self.constraints:
676 io.write(struct.pack("=20sII24f",
677 c.name, c.rigidA, c.rigidB,
678 c.pos.x, c.pos.y, c.pos.z,
679 c.rot.x, c.rot.y, c.rot.z,
680 c.constraintPosMin.x, c.constraintPosMin.y, c.constraintPosMin.z,
681 c.constraintPosMax.x, c.constraintPosMax.y, c.constraintPosMax.z,
682 c.constraintRotMin.x, c.constraintRotMin.y, c.constraintRotMin.z,
683 c.constraintRotMax.x, c.constraintRotMax.y, c.constraintRotMax.z,
684 c.springPos.x, c.springPos.y, c.springPos.z,
685 c.springRot.x, c.springRot.y, c.springRot.z
691 def _loadExtend(self):
692 ############################################################
693 # extend1: english name
694 ############################################################
695 if self.io.tell()>=self.end:
697 if struct.unpack("B", self.io.read(1))[0]==1:
698 if not self.loadEnglishName():
700 self._check_position()
702 ############################################################
703 # extend2: toon texture list
704 ############################################################
705 if self.io.tell()>=self.end:
707 if not self.loadToonTexture():
709 self._check_position()
711 ############################################################
713 ############################################################
714 if self.io.tell()>=self.end:
716 if not self.loadPhysics():
718 self._check_position()
722 def _loadHeader(self):
723 signature=struct.unpack("3s", self.io.read(3))[0]
724 if signature!=b"Pmd":
725 print("invalid signature", signature)
727 self.version=struct.unpack("f", self.io.read(4))[0]
728 self.name = truncate_zero(struct.unpack("20s", self.io.read(20))[0])
729 self.comment = truncate_zero(
730 struct.unpack("256s", self.io.read(256))[0])
733 def _loadVertex(self):
734 count = struct.unpack("I", self.io.read(4))[0]
735 for i in range(count):
736 self.vertices.append(Vertex(*struct.unpack("8f2H2B", self.io.read(38))))
740 count = struct.unpack("I", self.io.read(4))[0]
741 for i in range(0, count, 3):
742 self.indices+=struct.unpack("HHH", self.io.read(6))
745 def _loadMaterial(self):
746 count = struct.unpack("I", self.io.read(4))[0]
747 for i in range(count):
748 material=Material(*struct.unpack("4ff3f3f", self.io.read(44)))
749 material.toon_index=struct.unpack("B", self.io.read(1))[0]
750 material.flag=struct.unpack("B", self.io.read(1))[0]
751 material.vertex_count=struct.unpack("I", self.io.read(4))[0]
752 texture=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
754 #material.texture=texture.split('*')[0]
755 material.texture=texture
756 self.materials.append(material)
760 size = struct.unpack("H", self.io.read(2))[0]
761 for i in range(size):
762 name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
763 parent_index, tail_index = struct.unpack("HH", self.io.read(4))
764 type = struct.unpack("B", self.io.read(1))[0]
765 bone=createBone(name, type)
766 bone.parent_index=parent_index
767 bone.tail_index=tail_index
768 bone.ik_index = struct.unpack("H", self.io.read(2))[0]
769 bone.pos = Vector3(*struct.unpack("3f", self.io.read(12)))
770 bone.english_name="bone%03d" % len(self.bones)
771 self.bones.append(bone)
775 size = struct.unpack("H", self.io.read(2))[0]
776 for i in range(size):
777 ik=IK(*struct.unpack("2H", self.io.read(4)))
778 ik.length = struct.unpack("B", self.io.read(1))[0]
779 ik.iterations = struct.unpack("H", self.io.read(2))[0]
780 ik.weight = struct.unpack("f", self.io.read(4))[0]
781 for j in range(ik.length):
782 ik.children.append(struct.unpack("H", self.io.read(2))[0])
783 self.ik_list.append(ik)
787 size = struct.unpack("H", self.io.read(2))[0]
788 for i in range(size):
789 skin=Skin(truncate_zero(struct.unpack("20s", self.io.read(20))[0]))
790 skin_size = struct.unpack("I", self.io.read(4))[0]
791 skin.type = struct.unpack("B", self.io.read(1))[0]
792 for j in range(skin_size):
793 skin.indices.append(struct.unpack("I", self.io.read(4))[0])
794 skin.pos_list.append(
795 Vector3(*struct.unpack("3f", self.io.read(12))))
796 skin.english_name="skin%03d" % len(self.morph_list)
797 self.morph_list.append(skin)
800 def _loadSkinIndex(self):
801 size = struct.unpack("B", self.io.read(1))[0]
802 for i in range(size):
803 self.face_list.append(struct.unpack("H", self.io.read(2))[0])
806 def _loadBoneName(self):
807 size = struct.unpack("B", self.io.read(1))[0]
808 for i in range(size):
809 self.bone_group_list.append(BoneGroup(
810 truncate_zero(struct.unpack("50s", self.io.read(50))[0])))
813 def _loadBoneIndex(self):
814 size = struct.unpack("I", self.io.read(4))[0]
815 for i in range(size):
816 first=struct.unpack("H", self.io.read(2))[0]
817 second=struct.unpack("B", self.io.read(1))[0]
818 self.bone_display_list.append((first, second))
821 def loadToonTexture(self):
826 self.toon_textures[i]=truncate_zero(struct.unpack("100s", self.io.read(100))[0])
829 def loadEnglishName(self):
831 self.english_name=truncate_zero(
832 struct.unpack("20s", self.io.read(20))[0])
833 self.english_comment=truncate_zero(
834 struct.unpack("256s", self.io.read(256))[0])
835 self._check_position()
837 for bone in self.bones:
838 english_name=truncate_zero(
839 struct.unpack("20s", self.io.read(20))[0])
840 bone.english_name=english_name
841 self._check_position()
843 for skin in self.morph_list:
844 if skin.name==b'base':
846 english_name=truncate_zero(
847 struct.unpack("20s", self.io.read(20))[0])
848 #skin=self.morph_list[index]
849 if english_name!=skin.name:
850 skin.english_name=english_name
851 self._check_position()
853 for i in range(0, len(self.bone_group_list)):
854 self.bone_group_list[i].english_name=truncate_zero(
855 struct.unpack("50s", self.io.read(50))[0])
856 self._check_position()
859 def loadPhysics(self):
861 count = struct.unpack("I", self.io.read(4))[0]
862 for i in range(count):
863 name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
864 rigidbody=RigidBody(name)
865 rigidbody.boneIndex=struct.unpack("H", self.io.read(2))[0]
866 rigidbody.group=struct.unpack("B", self.io.read(1))[0]
867 rigidbody.target=struct.unpack("H", self.io.read(2))[0]
868 rigidbody.shapeType=struct.unpack("B", self.io.read(1))[0]
869 rigidbody.w=struct.unpack("f", self.io.read(4))[0]
870 rigidbody.h=struct.unpack("f", self.io.read(4))[0]
871 rigidbody.d=struct.unpack("f", self.io.read(4))[0]
872 rigidbody.position.x=struct.unpack("f", self.io.read(4))[0]
873 rigidbody.position.y=struct.unpack("f", self.io.read(4))[0]
874 rigidbody.position.z=struct.unpack("f", self.io.read(4))[0]
875 rigidbody.rotation.x=struct.unpack("f", self.io.read(4))[0]
876 rigidbody.rotation.y=struct.unpack("f", self.io.read(4))[0]
877 rigidbody.rotation.z=struct.unpack("f", self.io.read(4))[0]
878 rigidbody.weight=struct.unpack("f", self.io.read(4))[0]
879 rigidbody.linearDamping=struct.unpack("f", self.io.read(4))[0]
880 rigidbody.angularDamping=struct.unpack("f", self.io.read(4))[0]
881 rigidbody.restitution=struct.unpack("f", self.io.read(4))[0]
882 rigidbody.friction=struct.unpack("f", self.io.read(4))[0]
883 rigidbody.processType=struct.unpack("B", self.io.read(1))[0]
884 self.rigidbodies.append(rigidbody)
885 self._check_position()
888 count = struct.unpack("I", self.io.read(4))[0]
889 for i in range(count):
890 name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
891 constraint=Constraint(name)
892 constraint.rigidA=struct.unpack("I", self.io.read(4))[0]
893 constraint.rigidB=struct.unpack("I", self.io.read(4))[0]
894 constraint.pos.x=struct.unpack("f", self.io.read(4))[0]
895 constraint.pos.y=struct.unpack("f", self.io.read(4))[0]
896 constraint.pos.z=struct.unpack("f", self.io.read(4))[0]
897 constraint.rot.x=struct.unpack("f", self.io.read(4))[0]
898 constraint.rot.y=struct.unpack("f", self.io.read(4))[0]
899 constraint.rot.z=struct.unpack("f", self.io.read(4))[0]
900 constraint.constraintPosMin.x=struct.unpack("f", self.io.read(4))[0]
901 constraint.constraintPosMin.y=struct.unpack("f", self.io.read(4))[0]
902 constraint.constraintPosMin.z=struct.unpack("f", self.io.read(4))[0]
903 constraint.constraintPosMax.x=struct.unpack("f", self.io.read(4))[0]
904 constraint.constraintPosMax.y=struct.unpack("f", self.io.read(4))[0]
905 constraint.constraintPosMax.z=struct.unpack("f", self.io.read(4))[0]
906 constraint.constraintRotMin.x=struct.unpack("f", self.io.read(4))[0]
907 constraint.constraintRotMin.y=struct.unpack("f", self.io.read(4))[0]
908 constraint.constraintRotMin.z=struct.unpack("f", self.io.read(4))[0]
909 constraint.constraintRotMax.x=struct.unpack("f", self.io.read(4))[0]
910 constraint.constraintRotMax.y=struct.unpack("f", self.io.read(4))[0]
911 constraint.constraintRotMax.z=struct.unpack("f", self.io.read(4))[0]
912 constraint.springPos.x=struct.unpack("f", self.io.read(4))[0]
913 constraint.springPos.y=struct.unpack("f", self.io.read(4))[0]
914 constraint.springPos.z=struct.unpack("f", self.io.read(4))[0]
915 constraint.springRot.x=struct.unpack("f", self.io.read(4))[0]
916 constraint.springRot.y=struct.unpack("f", self.io.read(4))[0]
917 constraint.springRot.z=struct.unpack("f", self.io.read(4))[0]
918 self.constraints.append(constraint)
919 self._check_position()