7 ###############################################################################
9 ###############################################################################
10 if sys.version_info[0]<3:
11 def encode_string(src):
14 return src.encode('cp932')
18 raise "INVALID str: %s" % t
22 def encode_string(src):
25 return src.encode('cp932')
29 raise "INVALID str: %s" % t
33 __slots__=['pos', 'normal', 'uv', 'bone0', 'bone1', 'weight0', 'edge_flag']
34 def __init__(self, x=0, y=0, z=0, nx=0, ny=0, nz=0, u=0, v=0,
35 bone0=0, bone1=0, weight0=0, edge_flag=0):
36 self.pos=Vector3(x, y, z)
37 self.normal=Vector3(nx, ny, nz)
42 self.edge_flag=edge_flag
45 return "<%s %s %s, (%d, %d, %d)>" % (str(self.pos), str(self.normal), str(self.uv), self.bone0, self.bone1, self.weight0)
47 def __getitem__(self, key):
58 class Material(object):
60 'diffuse', 'shinness', 'specular',
61 'ambient', 'vertex_count', '_texture', 'toon_index', 'flag',
63 def getTexture(self): return self._texture
64 def setTexture(self, texture): self._texture=encode_string(texture)
65 texture=property(getTexture, setTexture)
67 def __init__(self, dr=0, dg=0, db=0, alpha=1,
68 specular=0, sr=0, sg=0, sb=0, ar=0, ag=0, ab=0):
69 self.diffuse=RGBA(dr, dg, db, alpha)
70 self.specular=RGBA(sr, sg, sb)
71 self.shinness=specular
72 self.ambient=RGBA(ar, ag, ab)
79 return "<Material [%f, %f, %f, %f]>" % (
80 self.diffuse[0], self.diffuse[1],
81 self.diffuse[2], self.diffuse[3],
85 # @return 各マテリアルについて、そのマテリアルが保持する面の回数だけ
87 def material_per_face(materials):
89 for x in range(int(m.vertex_count/3)):
105 __slots__=['_name', 'index', 'type', 'parent', 'ik', 'pos',
106 'children', '_english_name', 'ik_index',
107 'parent_index', 'tail_index', 'tail',
109 def getName(self): return self._name
110 def setName(self, name): self._name=encode_string(name)
111 name=property(getName, setName)
112 def getEnglishName(self): return self._english_name
113 def setEnglishName(self, english_name): self._english_name=encode_string(english_name)
114 english_name=property(getEnglishName, setEnglishName)
116 def __init__(self, name='bone', type=0):
120 self.parent_index=0xFFFF
122 self.tail=Vector3(0, 0, 0)
125 self.pos=Vector3(0, 0, 0)
130 return self.parent_index!=0xFFFF
133 return self.tail_index!=0
135 def display(self, indent=[]):
138 for i, is_end in enumerate(indent):
142 prefix+=' ' if is_end else ' |'
143 uni='%s +%s(%s)' % (prefix, unicode(self), self.english_name)
144 print(uni.encode(ENCODING))
146 uni='%s(%s)' % (unicode(self), self.english_name)
147 print(uni.encode(ENCODING))
149 child_count=len(self.children)
150 for i in range(child_count):
151 child=self.children[i]
153 child.display(indent+[False])
156 child.display(indent+[True])
159 class Bone_Rotate(Bone):
161 def __init__(self, name):
162 super(Bone_Rotate, self).__init__(name, 0)
164 return '<ROTATE %s>' % (self.name)
166 class Bone_RotateMove(Bone):
168 def __init__(self, name):
169 super(Bone_RotateMove, self).__init__(name, 1)
171 return '<ROTATE_MOVE %s>' % (self.name)
175 def __init__(self, name):
176 super(Bone_IK, self).__init__(name, 2)
178 return '<IK %s>' % (self.name)
180 class Bone_IKRotateInfl(Bone):
182 def __init__(self, name):
183 super(Bone_IKRotateInfl, self).__init__(name, 4)
185 return '<IK_ROTATE_INFL %s>' % (self.name)
187 class Bone_RotateInfl(Bone):
189 def __init__(self, name):
190 super(Bone_RotateInfl, self).__init__(name, 5)
192 return '<ROTATE_INFL %s>' % (self.name)
194 class Bone_IKTarget(Bone):
196 def __init__(self, name):
197 super(Bone_IKTarget, self).__init__(name, 6)
199 return '<IK_TARGET %s>' % (self.name)
201 class Bone_Unvisible(Bone):
203 def __init__(self, name):
204 super(Bone_Unvisible, self).__init__(name, 7)
206 return '<UNVISIBLE %s>' % (self.name)
208 class Bone_Rolling(Bone):
210 def __init__(self, name):
211 super(Bone_Rolling, self).__init__(name, 8)
213 return '<ROLLING %s>' % (self.name)
215 class Bone_Tweak(Bone):
217 def __init__(self, name):
218 super(Bone_Tweak, self).__init__(name, 9)
220 return '<TWEAK %s>' % (self.name)
223 def createBone(name, type):
225 return Bone_Rotate(name)
227 return Bone_RotateMove(name)
231 raise Exception("no used bone type: 3(%s)" % name)
233 return Bone_IKRotateInfl(name)
235 return Bone_RotateInfl(name)
237 return Bone_IKTarget(name)
239 return Bone_Unvisible(name)
241 return Bone_Rolling(name)
243 return Bone_Tweak(name)
245 raise Exception("unknown bone type: %d(%s)", type, name)
249 __slots__=['index', 'target', 'iterations', 'weight', 'length', 'children']
250 def __init__(self, index=0, target=0):
258 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))
262 __slots__=['_name', 'type', 'indices', 'pos_list', '_english_name',
264 def getName(self): return self._name
265 def setName(self, name): self._name=encode_string(name)
266 name=property(getName, setName)
267 def getEnglishName(self): return self._english_name
268 def setEnglishName(self, english_name): self._english_name=encode_string(english_name)
269 english_name=property(getEnglishName, setEnglishName)
271 def __init__(self, name='skin'):
279 def append(self, index, x, y, z):
280 self.indices.append(index)
281 self.pos_list.append(Vector3(x, y, z))
284 return '<Skin name: "%s", type: %d, vertex: %d>' % (
285 self.name, self.type, len(self.indices))
288 class BoneGroup(object):
289 __slots__=['_name', '_english_name']
290 def getName(self): return self._name
291 def setName(self, name): self._name=encode_string(name)
292 name=property(getName, setName)
293 def getEnglishName(self): return self._english_name
294 def setEnglishName(self, english_name): self._english_name=encode_string(english_name)
295 english_name=property(getEnglishName, setEnglishName)
297 def __init__(self, name='group'): self._name=name; self._english_name='center'
304 RIGIDBODY_KINEMATICS=0
306 RIGIDBODY_PHYSICS_WITH_BONE=2
309 class RigidBody(object):
310 __slots__=['_name', 'boneIndex', 'group', 'target', 'shapeType',
311 'w', 'h', 'd', 'position', 'rotation', 'weight',
312 'linearDamping', 'angularDamping', 'restitution', 'friction', 'processType'
314 def getName(self): return self._name
315 def setName(self, name): self._name=encode_string(name)
316 name=property(getName, setName)
318 def __init__(self, name):
320 self.position=Vector3()
321 self.rotation=Vector3()
324 class Constraint(object):
325 __slots__=[ '_name', 'rigidA', 'rigidB', 'pos', 'rot',
326 'constraintPosMin', 'constraintPosMax',
327 'constraintRotMin', 'constraintRotMax',
328 'springPos', 'springRot',
330 def getName(self): return self._name
331 def setName(self, name): self._name=encode_string(name)
332 name=property(getName, setName)
334 def __init__(self, name):
338 self.constraintPosMin=Vector3()
339 self.constraintPosMax=Vector3()
340 self.constraintRotMin=Vector3()
341 self.constraintRotMax=Vector3()
342 self.springPos=Vector3()
343 self.springRot=Vector3()
347 __slots__=['io', 'end', 'pos',
348 'version', '_name', '_comment',
349 '_english_name', '_english_comment',
350 'vertices', 'indices', 'materials', 'bones',
351 'ik_list', 'morph_list',
352 'face_list', 'bone_group_list', 'bone_display_list',
355 'rigidbodies', 'constraints',
357 def getName(self): return self._name
358 def setName(self, name): self._name=encode_string(name)
359 name=property(getName, setName)
360 def getEnglishName(self): return self._english_name
361 def setEnglishName(self, english_name): self._english_name=encode_string(english_name)
362 english_name=property(getEnglishName, setEnglishName)
363 def getComment(self): return self._comment
364 def setComment(self, comment): self._comment=encode_string(comment)
365 comment=property(getComment, setComment)
366 def getEnglishComment(self): return self._english_comment
367 def setEnglishComment(self, english_comment): self._english_comment=encode_string(english_comment)
368 english_comment=property(getEnglishComment, setEnglishComment)
373 self.comment="default"
374 self.english_name='default'
375 self.english_comment='default'
384 self.bone_group_list=[]
385 self.bone_display_list=[]
388 b'toon01.bmp', b'toon02.bmp',
389 b'toon03.bmp', b'toon04.bmp',
390 b'toon05.bmp', b'toon06.bmp',
391 b'toon07.bmp', b'toon08.bmp',
392 b'toon09.bmp', b'toon10.bmp',
395 self.no_parent_bones=[]
400 def each_vertex(self): return self.vertices
401 def getUV(self, i): return self.vertices[i].uv
404 self.vertices.append(v)
406 def addMaterial(self):
408 self.materials.append(m)
416 self.ik_list.append(ik)
420 self.morph_list.append(s)
422 def addBoneGroup(self):
424 self.bone_group_list.append(g)
426 def addBoneDisplay(self, b, g):
427 self.bone_display_list.append((b, g))
430 return '<PMDLoader version: %g, model: "%s", vertex: %d, face: %d, material: %d, bone: %d ik: %d, skin: %d>' % (
431 self.version, self.name, len(self.vertices), len(self.indices),
432 len(self.materials), len(self.bones), len(self.ik_list), len(self.morph_list))
434 def _check_position(self):
435 self.pos=self.io.tell()
437 def read(self, path):
438 size=os.path.getsize(path)
439 with open(path, "rb") as f:
440 return self.load(path, f, size)
442 def load(self, path, io, end):
444 self.pos=self.io.tell()
446 self._check_position()
448 if not self._loadHeader():
450 self._check_position()
452 if not self._loadVertex():
454 self._check_position()
456 if not self._loadFace():
458 self._check_position()
460 if not self._loadMaterial():
462 self._check_position()
464 if not self._loadBone():
466 self._check_position()
468 if not self._loadIK():
470 self._check_position()
472 if not self._loadSkin():
474 self._check_position()
476 if not self._loadSkinIndex():
478 self._check_position()
480 if not self._loadBoneName():
482 self._check_position()
484 if not self._loadBoneIndex():
486 self._check_position()
488 if not self._loadExtend():
489 print('fail to loadExtend')
493 if self.io.tell()!=self.end:
494 print("can not reach eof.")
495 print("current: %d, end: %d, remain: %d" % (
496 self.io.tell(), self.end, self.end-self.io.tell()))
499 for i, child in enumerate(self.bones):
500 if child.parent_index==0xFFFF:
502 self.no_parent_bones.append(child)
506 parent=self.bones[child.parent_index]
508 parent.children.append(child)
511 child.tail=self.bones[child.tail_index].pos
515 def write(self, path):
521 io.write(struct.pack("f", self.version))
522 io.write(struct.pack("20s", self.name))
523 io.write(struct.pack("256s", self.comment))
526 io.write(struct.pack("I", len(self.vertices)))
527 sVertex=struct.Struct("=8f2H2B") # 38byte
528 assert(sVertex.size==38)
529 for v in self.vertices:
531 v.pos[0], v.pos[1], v.pos[2],
532 v.normal[0], v.normal[1], v.normal[2],
534 v.bone0, v.bone1, v.weight0, v.edge_flag)
538 io.write(struct.pack("I", len(self.indices)))
539 io.write(struct.pack("=%dH" % len(self.indices), *self.indices))
542 io.write(struct.pack("I", len(self.materials)))
543 sMaterial=struct.Struct("=3fff3f3fBBI20s") # 70byte
544 assert(sMaterial.size==70)
545 for m in self.materials:
546 io.write(sMaterial.pack(
547 m.diffuse[0], m.diffuse[1], m.diffuse[2], m.diffuse[3],
549 m.specular[0], m.specular[1], m.specular[2],
550 m.ambient[0], m.ambient[1], m.ambient[2],
551 m.toon_index, m.flag,
557 io.write(struct.pack("H", len(self.bones)))
558 sBone=struct.Struct("=20sHHBH3f")
559 assert(sBone.size==39)
563 b.parent_index, b.tail_index, b.type, b.ik_index,
564 b.pos[0], b.pos[1], b.pos[2]))
567 io.write(struct.pack("H", len(self.ik_list)))
568 for ik in self.ik_list:
569 io.write(struct.pack("=2HBHf",
570 ik.index, ik.target, ik.length, ik.iterations, ik.weight
572 for c in ik.children:
573 io.write(struct.pack("H", c))
576 io.write(struct.pack("H", len(self.morph_list)))
577 for s in self.morph_list:
578 io.write(struct.pack("20sIB",
579 s.name, len(s.indices), s.type))
580 for i, v in zip(s.indices, s.pos_list):
581 io.write(struct.pack("I3f", i, v[0], v[1], v[2]))
584 io.write(struct.pack("B", len(self.face_list)))
585 for i in self.face_list:
586 io.write(struct.pack("H", i))
589 io.write(struct.pack("B", len(self.bone_group_list)))
590 for g in self.bone_group_list:
591 io.write(struct.pack("50s", g.name))
593 io.write(struct.pack("I", len(self.bone_display_list)))
594 for l in self.bone_display_list:
595 io.write(struct.pack("=HB", *l))
597 ############################################################
599 ############################################################
600 io.write(struct.pack("B", 1))
602 io.write(struct.pack("=20s", self.english_name))
603 io.write(struct.pack("=256s", self.english_comment))
605 for bone in self.bones:
606 io.write(struct.pack("=20s", bone.english_name))
608 for skin in self.morph_list:
610 if skin.name==b'base':
612 io.write(struct.pack("=20s", skin.english_name))
614 for bone_group in self.bone_group_list:
615 io.write(struct.pack("50s", bone_group.english_name))
618 io.write(struct.pack("=100s", self.toon_textures[i]))
620 io.write(struct.pack("I", len(self.rigidbodies)))
621 for r in self.rigidbodies:
622 io.write(struct.pack("=20sHBHB14fB",
623 r.name, r.boneIndex, r.group, r.target, r.shapeType,
625 r.position.x, r.position.y, r.position.z,
626 r.rotation.x, r.rotation.y, r.rotation.z,
628 r.linearDamping, r.angularDamping, r.restitution,
629 r.friction, r.processType))
632 io.write(struct.pack("I", len(self.constraints)))
633 for c in self.constraints:
634 io.write(struct.pack("=20sII24f",
635 c.name, c.rigidA, c.rigidB,
636 c.pos.x, c.pos.y, c.pos.z,
637 c.rot.x, c.rot.y, c.rot.z,
638 c.constraintPosMin.x, c.constraintPosMin.y, c.constraintPosMin.z,
639 c.constraintPosMax.x, c.constraintPosMax.y, c.constraintPosMax.z,
640 c.constraintRotMin.x, c.constraintRotMin.y, c.constraintRotMin.z,
641 c.constraintRotMax.x, c.constraintRotMax.y, c.constraintRotMax.z,
642 c.springPos.x, c.springPos.y, c.springPos.z,
643 c.springRot.x, c.springRot.y, c.springRot.z
649 def _loadExtend(self):
650 ############################################################
651 # extend1: english name
652 ############################################################
653 if self.io.tell()>=self.end:
655 if struct.unpack("B", self.io.read(1))[0]==1:
656 if not self.loadEnglishName():
658 self._check_position()
660 ############################################################
661 # extend2: toon texture list
662 ############################################################
663 if self.io.tell()>=self.end:
665 if not self.loadToonTexture():
667 self._check_position()
669 ############################################################
671 ############################################################
672 if self.io.tell()>=self.end:
674 if not self.loadPhysics():
676 self._check_position()
680 def _loadHeader(self):
681 signature=struct.unpack("3s", self.io.read(3))[0]
682 if signature!=b"Pmd":
683 print("invalid signature", signature)
685 self.version=struct.unpack("f", self.io.read(4))[0]
686 self.name = truncate_zero(struct.unpack("20s", self.io.read(20))[0])
687 self.comment = truncate_zero(
688 struct.unpack("256s", self.io.read(256))[0])
691 def _loadVertex(self):
692 count = struct.unpack("I", self.io.read(4))[0]
693 for i in range(count):
694 self.vertices.append(Vertex(*struct.unpack("8f2H2B", self.io.read(38))))
698 count = struct.unpack("I", self.io.read(4))[0]
699 for i in range(0, count, 3):
700 self.indices+=struct.unpack("HHH", self.io.read(6))
703 def _loadMaterial(self):
704 count = struct.unpack("I", self.io.read(4))[0]
705 for i in range(count):
706 material=Material(*struct.unpack("4ff3f3f", self.io.read(44)))
707 material.toon_index=struct.unpack("B", self.io.read(1))[0]
708 material.flag=struct.unpack("B", self.io.read(1))[0]
709 material.vertex_count=struct.unpack("I", self.io.read(4))[0]
710 texture=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
712 #material.texture=texture.split('*')[0]
713 material.texture=texture
714 self.materials.append(material)
718 size = struct.unpack("H", self.io.read(2))[0]
719 for i in range(size):
720 name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
721 parent_index, tail_index = struct.unpack("HH", self.io.read(4))
722 type = struct.unpack("B", self.io.read(1))[0]
723 bone=createBone(name, type)
724 bone.parent_index=parent_index
725 bone.tail_index=tail_index
726 bone.ik_index = struct.unpack("H", self.io.read(2))[0]
727 bone.pos = Vector3(*struct.unpack("3f", self.io.read(12)))
728 bone.english_name="bone%03d" % len(self.bones)
729 self.bones.append(bone)
733 size = struct.unpack("H", self.io.read(2))[0]
734 for i in range(size):
735 ik=IK(*struct.unpack("2H", self.io.read(4)))
736 ik.length = struct.unpack("B", self.io.read(1))[0]
737 ik.iterations = struct.unpack("H", self.io.read(2))[0]
738 ik.weight = struct.unpack("f", self.io.read(4))[0]
739 for j in range(ik.length):
740 ik.children.append(struct.unpack("H", self.io.read(2))[0])
741 self.ik_list.append(ik)
745 size = struct.unpack("H", self.io.read(2))[0]
746 for i in range(size):
747 skin=Skin(truncate_zero(struct.unpack("20s", self.io.read(20))[0]))
748 skin_size = struct.unpack("I", self.io.read(4))[0]
749 skin.type = struct.unpack("B", self.io.read(1))[0]
750 for j in range(skin_size):
751 skin.indices.append(struct.unpack("I", self.io.read(4))[0])
752 skin.pos_list.append(
753 Vector3(*struct.unpack("3f", self.io.read(12))))
754 skin.english_name="skin%03d" % len(self.morph_list)
755 self.morph_list.append(skin)
758 def _loadSkinIndex(self):
759 size = struct.unpack("B", self.io.read(1))[0]
760 for i in range(size):
761 self.face_list.append(struct.unpack("H", self.io.read(2))[0])
764 def _loadBoneName(self):
765 size = struct.unpack("B", self.io.read(1))[0]
766 for i in range(size):
767 self.bone_group_list.append(BoneGroup(
768 truncate_zero(struct.unpack("50s", self.io.read(50))[0])))
771 def _loadBoneIndex(self):
772 size = struct.unpack("I", self.io.read(4))[0]
773 for i in range(size):
774 first=struct.unpack("H", self.io.read(2))[0]
775 second=struct.unpack("B", self.io.read(1))[0]
776 self.bone_display_list.append((first, second))
779 def loadToonTexture(self):
784 self.toon_textures.append(
785 truncate_zero(struct.unpack("100s", self.io.read(100))[0]))
788 def loadEnglishName(self):
790 self.english_name=truncate_zero(
791 struct.unpack("20s", self.io.read(20))[0])
792 self.english_comment=truncate_zero(
793 struct.unpack("256s", self.io.read(256))[0])
794 self._check_position()
796 for bone in self.bones:
797 english_name=truncate_zero(
798 struct.unpack("20s", self.io.read(20))[0])
799 bone.english_name=english_name
800 self._check_position()
802 for skin in self.morph_list:
803 if skin.name=='base':
805 english_name=truncate_zero(
806 struct.unpack("20s", self.io.read(20))[0])
807 #skin=self.morph_list[index]
808 if english_name!=skin.name:
809 skin.english_name=english_name
810 self._check_position()
812 for i in range(0, len(self.bone_group_list)):
813 self.bone_group_list[i].english_name=truncate_zero(
814 struct.unpack("50s", self.io.read(50))[0])
815 self._check_position()
818 def loadPhysics(self):
820 count = struct.unpack("I", self.io.read(4))[0]
821 for i in range(count):
822 name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
823 rigidbody=RigidBody(name)
824 rigidbody.boneIndex=struct.unpack("H", self.io.read(2))[0]
825 rigidbody.group=struct.unpack("B", self.io.read(1))[0]
826 rigidbody.target=struct.unpack("H", self.io.read(2))[0]
827 rigidbody.shapeType=struct.unpack("B", self.io.read(1))[0]
828 rigidbody.w=struct.unpack("f", self.io.read(4))[0]
829 rigidbody.h=struct.unpack("f", self.io.read(4))[0]
830 rigidbody.d=struct.unpack("f", self.io.read(4))[0]
831 rigidbody.position.x=struct.unpack("f", self.io.read(4))[0]
832 rigidbody.position.y=struct.unpack("f", self.io.read(4))[0]
833 rigidbody.position.z=struct.unpack("f", self.io.read(4))[0]
834 rigidbody.rotation.x=struct.unpack("f", self.io.read(4))[0]
835 rigidbody.rotation.y=struct.unpack("f", self.io.read(4))[0]
836 rigidbody.rotation.z=struct.unpack("f", self.io.read(4))[0]
837 rigidbody.weight=struct.unpack("f", self.io.read(4))[0]
838 rigidbody.linearDamping=struct.unpack("f", self.io.read(4))[0]
839 rigidbody.angularDamping=struct.unpack("f", self.io.read(4))[0]
840 rigidbody.restitution=struct.unpack("f", self.io.read(4))[0]
841 rigidbody.friction=struct.unpack("f", self.io.read(4))[0]
842 rigidbody.processType=struct.unpack("B", self.io.read(1))[0]
843 self.rigidbodies.append(rigidbody)
844 self._check_position()
847 count = struct.unpack("I", self.io.read(4))[0]
848 for i in range(count):
849 name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
850 constraint=Constraint(name)
851 constraint.rigidA=struct.unpack("I", self.io.read(4))[0]
852 constraint.rigidB=struct.unpack("I", self.io.read(4))[0]
853 constraint.pos.x=struct.unpack("f", self.io.read(4))[0]
854 constraint.pos.y=struct.unpack("f", self.io.read(4))[0]
855 constraint.pos.z=struct.unpack("f", self.io.read(4))[0]
856 constraint.rot.x=struct.unpack("f", self.io.read(4))[0]
857 constraint.rot.y=struct.unpack("f", self.io.read(4))[0]
858 constraint.rot.z=struct.unpack("f", self.io.read(4))[0]
859 constraint.constraintPosMin.x=struct.unpack("f", self.io.read(4))[0]
860 constraint.constraintPosMin.y=struct.unpack("f", self.io.read(4))[0]
861 constraint.constraintPosMin.z=struct.unpack("f", self.io.read(4))[0]
862 constraint.constraintPosMax.x=struct.unpack("f", self.io.read(4))[0]
863 constraint.constraintPosMax.y=struct.unpack("f", self.io.read(4))[0]
864 constraint.constraintPosMax.z=struct.unpack("f", self.io.read(4))[0]
865 constraint.constraintRotMin.x=struct.unpack("f", self.io.read(4))[0]
866 constraint.constraintRotMin.y=struct.unpack("f", self.io.read(4))[0]
867 constraint.constraintRotMin.z=struct.unpack("f", self.io.read(4))[0]
868 constraint.constraintRotMax.x=struct.unpack("f", self.io.read(4))[0]
869 constraint.constraintRotMax.y=struct.unpack("f", self.io.read(4))[0]
870 constraint.constraintRotMax.z=struct.unpack("f", self.io.read(4))[0]
871 constraint.springPos.x=struct.unpack("f", self.io.read(4))[0]
872 constraint.springPos.y=struct.unpack("f", self.io.read(4))[0]
873 constraint.springPos.z=struct.unpack("f", self.io.read(4))[0]
874 constraint.springRot.x=struct.unpack("f", self.io.read(4))[0]
875 constraint.springRot.y=struct.unpack("f", self.io.read(4))[0]
876 constraint.springRot.z=struct.unpack("f", self.io.read(4))[0]
877 self.constraints.append(constraint)
878 self._check_position()