7 ###############################################################################
9 ###############################################################################
11 __slots__=['pos', 'normal', 'uv', 'bone0', 'bone1', 'weight0', 'edge_flag']
12 def __init__(self, x=0, y=0, z=0, nx=0, ny=0, nz=0, u=0, v=0,
13 bone0=0, bone1=0, weight0=0, edge_flag=0):
14 self.pos=Vector3(x, y, z)
15 self.normal=Vector3(nx, ny, nz)
20 self.edge_flag=edge_flag
23 return "<%s %s %s, (%d, %d, %d)>" % (str(self.pos), str(self.normal), str(self.uv), self.bone0, self.bone1, self.weight0)
25 def __getitem__(self, key):
36 class Material(object):
38 'diffuse', 'shinness', 'specular',
39 'ambient', 'vertex_count', '_texture', 'toon_index', 'flag',
41 def getTexture(self): return self._texture
42 def setTexture(self, texture): self._texture=to_str(texture)
43 texture=property(getTexture, setTexture)
45 def __init__(self, dr=0, dg=0, db=0, alpha=1,
46 specular=0, sr=0, sg=0, sb=0, ar=0, ag=0, ab=0):
47 self.diffuse=RGBA(dr, dg, db, alpha)
48 self.specular=RGBA(sr, sg, sb)
49 self.shinness=specular
50 self.ambient=RGBA(ar, ag, ab)
57 return "<Material [%f, %f, %f, %f]>" % (
58 self.diffuse[0], self.diffuse[1],
59 self.diffuse[2], self.diffuse[3],
63 # @return 各マテリアルについて、そのマテリアルが保持する面の回数だけ
65 def material_per_face(materials):
67 for x in range(int(m.vertex_count/3)):
83 __slots__=['_name', 'index', 'type', 'parent', 'ik', 'pos',
84 'children', '_english_name', 'ik_index',
85 'parent_index', 'tail_index', 'tail',
87 def getName(self): return self._name
88 def setName(self, name): self._name=to_str(name)
89 name=property(getName, setName)
90 def getEnglishName(self): return self._english_name
91 def setEnglishName(self, english_name): self._english_name=to_str(english_name)
92 english_name=property(getEnglishName, setEnglishName)
94 def __init__(self, name='bone', type=0):
98 self.parent_index=0xFFFF
100 self.tail=Vector3(0, 0, 0)
103 self.pos=Vector3(0, 0, 0)
108 return self.parent_index!=0xFFFF
111 return self.tail_index!=0
113 def display(self, indent=[]):
116 for i, is_end in enumerate(indent):
120 prefix+=' ' if is_end else ' |'
121 uni='%s +%s(%s)' % (prefix, unicode(self), self.english_name)
122 print(uni.encode(ENCODING))
124 uni='%s(%s)' % (unicode(self), self.english_name)
125 print(uni.encode(ENCODING))
127 child_count=len(self.children)
128 for i in range(child_count):
129 child=self.children[i]
131 child.display(indent+[False])
134 child.display(indent+[True])
137 class Bone_Rotate(Bone):
139 def __init__(self, name):
140 super(Bone_Rotate, self).__init__(name, 0)
142 return '<ROTATE %s>' % (self.name)
144 class Bone_RotateMove(Bone):
146 def __init__(self, name):
147 super(Bone_RotateMove, self).__init__(name, 1)
149 return '<ROTATE_MOVE %s>' % (self.name)
153 def __init__(self, name):
154 super(Bone_IK, self).__init__(name, 2)
156 return '<IK %s>' % (self.name)
158 class Bone_IKRotateInfl(Bone):
160 def __init__(self, name):
161 super(Bone_IKRotateInfl, self).__init__(name, 4)
163 return '<IK_ROTATE_INFL %s>' % (self.name)
165 class Bone_RotateInfl(Bone):
167 def __init__(self, name):
168 super(Bone_RotateInfl, self).__init__(name, 5)
170 return '<ROTATE_INFL %s>' % (self.name)
172 class Bone_IKTarget(Bone):
174 def __init__(self, name):
175 super(Bone_IKTarget, self).__init__(name, 6)
177 return '<IK_TARGET %s>' % (self.name)
179 class Bone_Unvisible(Bone):
181 def __init__(self, name):
182 super(Bone_Unvisible, self).__init__(name, 7)
184 return '<UNVISIBLE %s>' % (self.name)
186 class Bone_Rolling(Bone):
188 def __init__(self, name):
189 super(Bone_Rolling, self).__init__(name, 8)
191 return '<ROLLING %s>' % (self.name)
193 class Bone_Tweak(Bone):
195 def __init__(self, name):
196 super(Bone_Tweak, self).__init__(name, 9)
198 return '<TWEAK %s>' % (self.name)
201 def createBone(name, type):
203 return Bone_Rotate(name)
205 return Bone_RotateMove(name)
209 raise Exception("no used bone type: 3(%s)" % name)
211 return Bone_IKRotateInfl(name)
213 return Bone_RotateInfl(name)
215 return Bone_IKTarget(name)
217 return Bone_Unvisible(name)
219 return Bone_Rolling(name)
221 return Bone_Tweak(name)
223 raise Exception("unknown bone type: %d(%s)", type, name)
227 __slots__=['index', 'target', 'iterations', 'weight', 'length', 'children']
228 def __init__(self, index=0, target=0):
236 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))
240 __slots__=['_name', 'type', 'indices', 'pos_list', '_english_name',
242 def getName(self): return self._name
243 def setName(self, name): self._name=to_str(name)
244 name=property(getName, setName)
245 def getEnglishName(self): return self._english_name
246 def setEnglishName(self, english_name): self._english_name=to_str(english_name)
247 english_name=property(getEnglishName, setEnglishName)
249 def __init__(self, name='skin'):
257 def append(self, index, x, y, z):
258 self.indices.append(index)
259 self.pos_list.append(Vector3(x, y, z))
262 return '<Skin name: "%s", type: %d, vertex: %d>' % (
263 self.name, self.type, len(self.indices))
266 class BoneGroup(object):
267 __slots__=['_name', '_english_name']
268 def getName(self): return self._name
269 def setName(self, name): self._name=to_str(name)
270 name=property(getName, setName)
271 def getEnglishName(self): return self._english_name
272 def setEnglishName(self, english_name): self._english_name=to_str(english_name)
273 english_name=property(getEnglishName, setEnglishName)
275 def __init__(self, name='group'): self._name=name; self._english_name='center'
282 RIGIDBODY_KINEMATICS=0
284 RIGIDBODY_PHYSICS_WITH_BONE=2
287 class RigidBody(object):
288 __slots__=['_name', 'boneIndex', 'group', 'target', 'shapeType',
289 'w', 'h', 'd', 'position', 'rotation', 'weight',
290 'linearDamping', 'angularDamping', 'restitution', 'friction', 'processType'
292 def getName(self): return self._name
293 def setName(self, name): self._name=to_str(name)
294 name=property(getName, setName)
296 def __init__(self, name):
298 self.position=Vector3()
299 self.rotation=Vector3()
302 class Constraint(object):
303 __slots__=[ '_name', 'rigidA', 'rigidB', 'pos', 'rot',
304 'constraintPosMin', 'constraintPosMax',
305 'constraintRotMin', 'constraintRotMax',
306 'springPos', 'springRot',
308 def getName(self): return self._name
309 def setName(self, name): self._name=to_str(name)
310 name=property(getName, setName)
312 def __init__(self, name):
316 self.constraintPosMin=Vector3()
317 self.constraintPosMax=Vector3()
318 self.constraintRotMin=Vector3()
319 self.constraintRotMax=Vector3()
320 self.springPos=Vector3()
321 self.springRot=Vector3()
324 class ToonTextures(object):
325 __slots__=['_toon_textures']
327 self._toon_textures=[]
329 self._toon_textures.append('toon%02d.bmp' % (i+1))
331 def __getitem__(self, key):
332 return self._toon_textures[key]
334 def __setitem__(self, key, value):
335 self._toon_textures[key]=to_str(value)
341 for toon_texture in self._toon_textures:
346 __slots__=['io', 'end', 'pos',
347 'version', '_name', '_comment',
348 '_english_name', '_english_comment',
349 'vertices', 'indices', 'materials', 'bones',
350 'ik_list', 'morph_list',
351 'face_list', 'bone_group_list', 'bone_display_list',
354 'rigidbodies', 'constraints',
356 def getName(self): return self._name
357 def setName(self, name): self._name=to_str(name)
358 name=property(getName, setName)
359 def getEnglishName(self): return self._english_name
360 def setEnglishName(self, english_name): self._english_name=to_str(english_name)
361 english_name=property(getEnglishName, setEnglishName)
362 def getComment(self): return self._comment
363 def setComment(self, comment): self._comment=to_str(comment)
364 comment=property(getComment, setComment)
365 def getEnglishComment(self): return self._english_comment
366 def setEnglishComment(self, english_comment): self._english_comment=to_str(english_comment)
367 english_comment=property(getEnglishComment, setEnglishComment)
372 self.comment='default'
373 self.english_name='default'
374 self.english_comment='default'
382 self.bone_group_list=[]
383 self.bone_display_list=[]
385 self.toon_textures=ToonTextures()
389 self.no_parent_bones=[]
391 def each_vertex(self): return self.vertices
392 def getUV(self, i): return self.vertices[i].uv
395 self.vertices.append(v)
397 def addMaterial(self):
399 self.materials.append(m)
407 self.ik_list.append(ik)
411 self.morph_list.append(s)
413 def addBoneGroup(self):
415 self.bone_group_list.append(g)
417 def addBoneDisplay(self, b, g):
418 self.bone_display_list.append((b, g))
421 return '<PMDLoader version: %g, model: "%s", vertex: %d, face: %d, material: %d, bone: %d ik: %d, skin: %d>' % (
422 self.version, self.name, len(self.vertices), len(self.indices),
423 len(self.materials), len(self.bones), len(self.ik_list), len(self.morph_list))
425 def _check_position(self):
426 self.pos=self.io.tell()
428 def read(self, path):
429 size=os.path.getsize(path)
430 with open(path, "rb") as f:
431 return self.load(path, f, size)
433 def load(self, path, io, end):
435 self.pos=self.io.tell()
437 self._check_position()
439 if not self._loadHeader():
441 self._check_position()
443 if not self._loadVertex():
445 self._check_position()
447 if not self._loadFace():
449 self._check_position()
451 if not self._loadMaterial():
453 self._check_position()
455 if not self._loadBone():
457 self._check_position()
459 if not self._loadIK():
461 self._check_position()
463 if not self._loadSkin():
465 self._check_position()
467 if not self._loadSkinIndex():
469 self._check_position()
471 if not self._loadBoneName():
473 self._check_position()
475 if not self._loadBoneIndex():
477 self._check_position()
479 if not self._loadExtend():
480 print('fail to loadExtend')
484 if self.io.tell()!=self.end:
485 print("can not reach eof.")
486 print("current: %d, end: %d, remain: %d" % (
487 self.io.tell(), self.end, self.end-self.io.tell()))
490 for i, child in enumerate(self.bones):
491 if child.parent_index==0xFFFF:
493 self.no_parent_bones.append(child)
497 parent=self.bones[child.parent_index]
499 parent.children.append(child)
502 child.tail=self.bones[child.tail_index].pos
506 def write(self, path):
512 io.write(struct.pack("f", self.version))
513 io.write(struct.pack("20s", self.name))
514 io.write(struct.pack("256s", self.comment))
517 io.write(struct.pack("I", len(self.vertices)))
518 sVertex=struct.Struct("=8f2H2B") # 38byte
519 assert(sVertex.size==38)
520 for v in self.vertices:
522 v.pos[0], v.pos[1], v.pos[2],
523 v.normal[0], v.normal[1], v.normal[2],
525 v.bone0, v.bone1, v.weight0, v.edge_flag)
529 io.write(struct.pack("I", len(self.indices)))
530 io.write(struct.pack("=%dH" % len(self.indices), *self.indices))
533 io.write(struct.pack("I", len(self.materials)))
534 sMaterial=struct.Struct("=3fff3f3fBBI20s") # 70byte
535 assert(sMaterial.size==70)
536 for m in self.materials:
537 io.write(sMaterial.pack(
538 m.diffuse[0], m.diffuse[1], m.diffuse[2], m.diffuse[3],
540 m.specular[0], m.specular[1], m.specular[2],
541 m.ambient[0], m.ambient[1], m.ambient[2],
542 m.toon_index, m.flag,
548 io.write(struct.pack("H", len(self.bones)))
549 sBone=struct.Struct("=20sHHBH3f")
550 assert(sBone.size==39)
554 b.parent_index, b.tail_index, b.type, b.ik_index,
555 b.pos[0], b.pos[1], b.pos[2]))
558 io.write(struct.pack("H", len(self.ik_list)))
559 for ik in self.ik_list:
560 io.write(struct.pack("=2HBHf",
561 ik.index, ik.target, ik.length, ik.iterations, ik.weight
563 for c in ik.children:
564 io.write(struct.pack("H", c))
567 io.write(struct.pack("H", len(self.morph_list)))
568 for s in self.morph_list:
569 io.write(struct.pack("20sIB",
570 s.name, len(s.indices), s.type))
571 for i, v in zip(s.indices, s.pos_list):
572 io.write(struct.pack("I3f", i, v[0], v[1], v[2]))
575 io.write(struct.pack("B", len(self.face_list)))
576 for i in self.face_list:
577 io.write(struct.pack("H", i))
580 io.write(struct.pack("B", len(self.bone_group_list)))
581 for g in self.bone_group_list:
582 io.write(struct.pack("50s", g.name))
584 io.write(struct.pack("I", len(self.bone_display_list)))
585 for l in self.bone_display_list:
586 io.write(struct.pack("=HB", *l))
588 ############################################################
590 ############################################################
591 io.write(struct.pack("B", 1))
593 io.write(struct.pack("=20s", self.english_name))
594 io.write(struct.pack("=256s", self.english_comment))
596 for bone in self.bones:
597 io.write(struct.pack("=20s", bone.english_name))
599 for skin in self.morph_list:
601 if skin.name==b'base':
603 io.write(struct.pack("=20s", skin.english_name))
605 for bone_group in self.bone_group_list:
606 io.write(struct.pack("50s", bone_group.english_name))
608 for toon_texture in self.toon_textures:
609 io.write(struct.pack("=100s", toon_texture))
611 io.write(struct.pack("I", len(self.rigidbodies)))
612 for r in self.rigidbodies:
613 io.write(struct.pack("=20sHBHB14fB",
614 r.name, r.boneIndex, r.group, r.target, r.shapeType,
616 r.position.x, r.position.y, r.position.z,
617 r.rotation.x, r.rotation.y, r.rotation.z,
619 r.linearDamping, r.angularDamping, r.restitution,
620 r.friction, r.processType))
623 io.write(struct.pack("I", len(self.constraints)))
624 for c in self.constraints:
625 io.write(struct.pack("=20sII24f",
626 c.name, c.rigidA, c.rigidB,
627 c.pos.x, c.pos.y, c.pos.z,
628 c.rot.x, c.rot.y, c.rot.z,
629 c.constraintPosMin.x, c.constraintPosMin.y, c.constraintPosMin.z,
630 c.constraintPosMax.x, c.constraintPosMax.y, c.constraintPosMax.z,
631 c.constraintRotMin.x, c.constraintRotMin.y, c.constraintRotMin.z,
632 c.constraintRotMax.x, c.constraintRotMax.y, c.constraintRotMax.z,
633 c.springPos.x, c.springPos.y, c.springPos.z,
634 c.springRot.x, c.springRot.y, c.springRot.z
640 def _loadExtend(self):
641 ############################################################
642 # extend1: english name
643 ############################################################
644 if self.io.tell()>=self.end:
646 if struct.unpack("B", self.io.read(1))[0]==1:
647 if not self.loadEnglishName():
649 self._check_position()
651 ############################################################
652 # extend2: toon texture list
653 ############################################################
654 if self.io.tell()>=self.end:
656 if not self.loadToonTexture():
658 self._check_position()
660 ############################################################
662 ############################################################
663 if self.io.tell()>=self.end:
665 if not self.loadPhysics():
667 self._check_position()
671 def _loadHeader(self):
672 signature=struct.unpack("3s", self.io.read(3))[0]
673 if signature!=b"Pmd":
674 print("invalid signature", signature)
676 self.version=struct.unpack("f", self.io.read(4))[0]
677 self.name = truncate_zero(struct.unpack("20s", self.io.read(20))[0])
678 self.comment = truncate_zero(
679 struct.unpack("256s", self.io.read(256))[0])
682 def _loadVertex(self):
683 count = struct.unpack("I", self.io.read(4))[0]
684 for i in range(count):
685 self.vertices.append(Vertex(*struct.unpack("8f2H2B", self.io.read(38))))
689 count = struct.unpack("I", self.io.read(4))[0]
690 for i in range(0, count, 3):
691 self.indices+=struct.unpack("HHH", self.io.read(6))
694 def _loadMaterial(self):
695 count = struct.unpack("I", self.io.read(4))[0]
696 for i in range(count):
697 material=Material(*struct.unpack("4ff3f3f", self.io.read(44)))
698 material.toon_index=struct.unpack("B", self.io.read(1))[0]
699 material.flag=struct.unpack("B", self.io.read(1))[0]
700 material.vertex_count=struct.unpack("I", self.io.read(4))[0]
701 texture=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
703 #material.texture=texture.split('*')[0]
704 material.texture=texture
705 self.materials.append(material)
709 size = struct.unpack("H", self.io.read(2))[0]
710 for i in range(size):
711 name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
712 parent_index, tail_index = struct.unpack("HH", self.io.read(4))
713 type = struct.unpack("B", self.io.read(1))[0]
714 bone=createBone(name, type)
715 bone.parent_index=parent_index
716 bone.tail_index=tail_index
717 bone.ik_index = struct.unpack("H", self.io.read(2))[0]
718 bone.pos = Vector3(*struct.unpack("3f", self.io.read(12)))
719 bone.english_name="bone%03d" % len(self.bones)
720 self.bones.append(bone)
724 size = struct.unpack("H", self.io.read(2))[0]
725 for i in range(size):
726 ik=IK(*struct.unpack("2H", self.io.read(4)))
727 ik.length = struct.unpack("B", self.io.read(1))[0]
728 ik.iterations = struct.unpack("H", self.io.read(2))[0]
729 ik.weight = struct.unpack("f", self.io.read(4))[0]
730 for j in range(ik.length):
731 ik.children.append(struct.unpack("H", self.io.read(2))[0])
732 self.ik_list.append(ik)
736 size = struct.unpack("H", self.io.read(2))[0]
737 for i in range(size):
738 skin=Skin(truncate_zero(struct.unpack("20s", self.io.read(20))[0]))
739 skin_size = struct.unpack("I", self.io.read(4))[0]
740 skin.type = struct.unpack("B", self.io.read(1))[0]
741 for j in range(skin_size):
742 skin.indices.append(struct.unpack("I", self.io.read(4))[0])
743 skin.pos_list.append(
744 Vector3(*struct.unpack("3f", self.io.read(12))))
745 skin.english_name="skin%03d" % len(self.morph_list)
746 self.morph_list.append(skin)
749 def _loadSkinIndex(self):
750 size = struct.unpack("B", self.io.read(1))[0]
751 for i in range(size):
752 self.face_list.append(struct.unpack("H", self.io.read(2))[0])
755 def _loadBoneName(self):
756 size = struct.unpack("B", self.io.read(1))[0]
757 for i in range(size):
758 self.bone_group_list.append(BoneGroup(
759 truncate_zero(struct.unpack("50s", self.io.read(50))[0])))
762 def _loadBoneIndex(self):
763 size = struct.unpack("I", self.io.read(4))[0]
764 for i in range(size):
765 first=struct.unpack("H", self.io.read(2))[0]
766 second=struct.unpack("B", self.io.read(1))[0]
767 self.bone_display_list.append((first, second))
770 def loadToonTexture(self):
775 self.toon_textures[i]=truncate_zero(struct.unpack("100s", self.io.read(100))[0])
778 def loadEnglishName(self):
780 self.english_name=truncate_zero(
781 struct.unpack("20s", self.io.read(20))[0])
782 self.english_comment=truncate_zero(
783 struct.unpack("256s", self.io.read(256))[0])
784 self._check_position()
786 for bone in self.bones:
787 english_name=truncate_zero(
788 struct.unpack("20s", self.io.read(20))[0])
789 bone.english_name=english_name
790 self._check_position()
792 for skin in self.morph_list:
793 if skin.name=='base':
795 english_name=truncate_zero(
796 struct.unpack("20s", self.io.read(20))[0])
797 #skin=self.morph_list[index]
798 if english_name!=skin.name:
799 skin.english_name=english_name
800 self._check_position()
802 for i in range(0, len(self.bone_group_list)):
803 self.bone_group_list[i].english_name=truncate_zero(
804 struct.unpack("50s", self.io.read(50))[0])
805 self._check_position()
808 def loadPhysics(self):
810 count = struct.unpack("I", self.io.read(4))[0]
811 for i in range(count):
812 name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
813 rigidbody=RigidBody(name)
814 rigidbody.boneIndex=struct.unpack("H", self.io.read(2))[0]
815 rigidbody.group=struct.unpack("B", self.io.read(1))[0]
816 rigidbody.target=struct.unpack("H", self.io.read(2))[0]
817 rigidbody.shapeType=struct.unpack("B", self.io.read(1))[0]
818 rigidbody.w=struct.unpack("f", self.io.read(4))[0]
819 rigidbody.h=struct.unpack("f", self.io.read(4))[0]
820 rigidbody.d=struct.unpack("f", self.io.read(4))[0]
821 rigidbody.position.x=struct.unpack("f", self.io.read(4))[0]
822 rigidbody.position.y=struct.unpack("f", self.io.read(4))[0]
823 rigidbody.position.z=struct.unpack("f", self.io.read(4))[0]
824 rigidbody.rotation.x=struct.unpack("f", self.io.read(4))[0]
825 rigidbody.rotation.y=struct.unpack("f", self.io.read(4))[0]
826 rigidbody.rotation.z=struct.unpack("f", self.io.read(4))[0]
827 rigidbody.weight=struct.unpack("f", self.io.read(4))[0]
828 rigidbody.linearDamping=struct.unpack("f", self.io.read(4))[0]
829 rigidbody.angularDamping=struct.unpack("f", self.io.read(4))[0]
830 rigidbody.restitution=struct.unpack("f", self.io.read(4))[0]
831 rigidbody.friction=struct.unpack("f", self.io.read(4))[0]
832 rigidbody.processType=struct.unpack("B", self.io.read(1))[0]
833 self.rigidbodies.append(rigidbody)
834 self._check_position()
837 count = struct.unpack("I", self.io.read(4))[0]
838 for i in range(count):
839 name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
840 constraint=Constraint(name)
841 constraint.rigidA=struct.unpack("I", self.io.read(4))[0]
842 constraint.rigidB=struct.unpack("I", self.io.read(4))[0]
843 constraint.pos.x=struct.unpack("f", self.io.read(4))[0]
844 constraint.pos.y=struct.unpack("f", self.io.read(4))[0]
845 constraint.pos.z=struct.unpack("f", self.io.read(4))[0]
846 constraint.rot.x=struct.unpack("f", self.io.read(4))[0]
847 constraint.rot.y=struct.unpack("f", self.io.read(4))[0]
848 constraint.rot.z=struct.unpack("f", self.io.read(4))[0]
849 constraint.constraintPosMin.x=struct.unpack("f", self.io.read(4))[0]
850 constraint.constraintPosMin.y=struct.unpack("f", self.io.read(4))[0]
851 constraint.constraintPosMin.z=struct.unpack("f", self.io.read(4))[0]
852 constraint.constraintPosMax.x=struct.unpack("f", self.io.read(4))[0]
853 constraint.constraintPosMax.y=struct.unpack("f", self.io.read(4))[0]
854 constraint.constraintPosMax.z=struct.unpack("f", self.io.read(4))[0]
855 constraint.constraintRotMin.x=struct.unpack("f", self.io.read(4))[0]
856 constraint.constraintRotMin.y=struct.unpack("f", self.io.read(4))[0]
857 constraint.constraintRotMin.z=struct.unpack("f", self.io.read(4))[0]
858 constraint.constraintRotMax.x=struct.unpack("f", self.io.read(4))[0]
859 constraint.constraintRotMax.y=struct.unpack("f", self.io.read(4))[0]
860 constraint.constraintRotMax.z=struct.unpack("f", self.io.read(4))[0]
861 constraint.springPos.x=struct.unpack("f", self.io.read(4))[0]
862 constraint.springPos.y=struct.unpack("f", self.io.read(4))[0]
863 constraint.springPos.z=struct.unpack("f", self.io.read(4))[0]
864 constraint.springRot.x=struct.unpack("f", self.io.read(4))[0]
865 constraint.springRot.y=struct.unpack("f", self.io.read(4))[0]
866 constraint.springRot.z=struct.unpack("f", self.io.read(4))[0]
867 self.constraints.append(constraint)
868 self._check_position()