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 from_str(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 from_str(self._name)
88 def setName(self, name): self._name=to_str(name)
89 name=property(getName, setName)
90 def getEnglishName(self): return from_str(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 from_str(self._name)
243 def setName(self, name): self._name=to_str(name)
244 name=property(getName, setName)
245 def getEnglishName(self): return from_str(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 from_str(self._name)
269 def setName(self, name): self._name=to_str(name)
270 name=property(getName, setName)
271 def getEnglishName(self): return from_str(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 from_str(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 from_str(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 from_str(self._toon_textures[key])
334 def __setitem__(self, key, value):
335 self._toon_textures[key]=to_str(value)
338 for toon_texture in self._toon_textures:
339 yield from_str(toon_texture)
343 __slots__=['io', 'end', 'pos',
344 'version', '_name', '_comment',
345 '_english_name', '_english_comment',
346 'vertices', 'indices', 'materials', 'bones',
347 'ik_list', 'morph_list',
348 'face_list', 'bone_group_list', 'bone_display_list',
351 'rigidbodies', 'constraints',
353 def getName(self): return from_str(self._name)
354 def setName(self, name): self._name=to_str(name)
355 name=property(getName, setName)
356 def getEnglishName(self): return from_str(self._english_name)
357 def setEnglishName(self, english_name): self._english_name=to_str(english_name)
358 english_name=property(getEnglishName, setEnglishName)
359 def getComment(self): return from_str(self._comment)
360 def setComment(self, comment): self._comment=to_str(comment)
361 comment=property(getComment, setComment)
362 def getEnglishComment(self): return from_str(self._english_comment)
363 def setEnglishComment(self, english_comment): self._english_comment=to_str(english_comment)
364 english_comment=property(getEnglishComment, setEnglishComment)
369 self.comment='default'
370 self.english_name='default'
371 self.english_comment='default'
379 self.bone_group_list=[]
380 self.bone_display_list=[]
382 self.toon_textures=ToonTextures()
386 self.no_parent_bones=[]
388 def each_vertex(self): return self.vertices
389 def getUV(self, i): return self.vertices[i].uv
392 self.vertices.append(v)
394 def addMaterial(self):
396 self.materials.append(m)
404 self.ik_list.append(ik)
408 self.morph_list.append(s)
410 def addBoneGroup(self):
412 self.bone_group_list.append(g)
414 def addBoneDisplay(self, b, g):
415 self.bone_display_list.append((b, g))
418 return '<PMDLoader version: %g, model: "%s", vertex: %d, face: %d, material: %d, bone: %d ik: %d, skin: %d>' % (
419 self.version, self.name, len(self.vertices), len(self.indices),
420 len(self.materials), len(self.bones), len(self.ik_list), len(self.morph_list))
422 def _check_position(self):
423 self.pos=self.io.tell()
425 def read(self, path):
426 size=os.path.getsize(path)
427 with open(path, "rb") as f:
428 return self.load(path, f, size)
430 def load(self, path, io, end):
432 self.pos=self.io.tell()
434 self._check_position()
436 if not self._loadHeader():
438 self._check_position()
440 if not self._loadVertex():
442 self._check_position()
444 if not self._loadFace():
446 self._check_position()
448 if not self._loadMaterial():
450 self._check_position()
452 if not self._loadBone():
454 self._check_position()
456 if not self._loadIK():
458 self._check_position()
460 if not self._loadSkin():
462 self._check_position()
464 if not self._loadSkinIndex():
466 self._check_position()
468 if not self._loadBoneName():
470 self._check_position()
472 if not self._loadBoneIndex():
474 self._check_position()
476 if not self._loadExtend():
477 print('fail to loadExtend')
481 if self.io.tell()!=self.end:
482 print("can not reach eof.")
483 print("current: %d, end: %d, remain: %d" % (
484 self.io.tell(), self.end, self.end-self.io.tell()))
487 for i, child in enumerate(self.bones):
488 if child.parent_index==0xFFFF:
490 self.no_parent_bones.append(child)
494 parent=self.bones[child.parent_index]
496 parent.children.append(child)
499 child.tail=self.bones[child.tail_index].pos
503 def write(self, path):
509 io.write(struct.pack("f", self.version))
510 io.write(struct.pack("20s", self.name))
511 io.write(struct.pack("256s", self.comment))
514 io.write(struct.pack("I", len(self.vertices)))
515 sVertex=struct.Struct("=8f2H2B") # 38byte
516 assert(sVertex.size==38)
517 for v in self.vertices:
519 v.pos[0], v.pos[1], v.pos[2],
520 v.normal[0], v.normal[1], v.normal[2],
522 v.bone0, v.bone1, v.weight0, v.edge_flag)
526 io.write(struct.pack("I", len(self.indices)))
527 io.write(struct.pack("=%dH" % len(self.indices), *self.indices))
530 io.write(struct.pack("I", len(self.materials)))
531 sMaterial=struct.Struct("=3fff3f3fBBI20s") # 70byte
532 assert(sMaterial.size==70)
533 for m in self.materials:
534 io.write(sMaterial.pack(
535 m.diffuse[0], m.diffuse[1], m.diffuse[2], m.diffuse[3],
537 m.specular[0], m.specular[1], m.specular[2],
538 m.ambient[0], m.ambient[1], m.ambient[2],
539 m.toon_index, m.flag,
545 io.write(struct.pack("H", len(self.bones)))
546 sBone=struct.Struct("=20sHHBH3f")
547 assert(sBone.size==39)
551 b.parent_index, b.tail_index, b.type, b.ik_index,
552 b.pos[0], b.pos[1], b.pos[2]))
555 io.write(struct.pack("H", len(self.ik_list)))
556 for ik in self.ik_list:
557 io.write(struct.pack("=2HBHf",
558 ik.index, ik.target, ik.length, ik.iterations, ik.weight
560 for c in ik.children:
561 io.write(struct.pack("H", c))
564 io.write(struct.pack("H", len(self.morph_list)))
565 for s in self.morph_list:
566 io.write(struct.pack("20sIB",
567 s.name, len(s.indices), s.type))
568 for i, v in zip(s.indices, s.pos_list):
569 io.write(struct.pack("I3f", i, v[0], v[1], v[2]))
572 io.write(struct.pack("B", len(self.face_list)))
573 for i in self.face_list:
574 io.write(struct.pack("H", i))
577 io.write(struct.pack("B", len(self.bone_group_list)))
578 for g in self.bone_group_list:
579 io.write(struct.pack("50s", g.name))
581 io.write(struct.pack("I", len(self.bone_display_list)))
582 for l in self.bone_display_list:
583 io.write(struct.pack("=HB", *l))
585 ############################################################
587 ############################################################
588 io.write(struct.pack("B", 1))
590 io.write(struct.pack("=20s", self.english_name))
591 io.write(struct.pack("=256s", self.english_comment))
593 for bone in self.bones:
594 io.write(struct.pack("=20s", bone.english_name))
596 for skin in self.morph_list:
598 if skin.name==b'base':
600 io.write(struct.pack("=20s", skin.english_name))
602 for bone_group in self.bone_group_list:
603 io.write(struct.pack("50s", bone_group.english_name))
605 for toon_texture in self.toon_textures:
606 io.write(struct.pack("=100s", toon_texture))
608 io.write(struct.pack("I", len(self.rigidbodies)))
609 for r in self.rigidbodies:
610 io.write(struct.pack("=20sHBHB14fB",
611 r.name, r.boneIndex, r.group, r.target, r.shapeType,
613 r.position.x, r.position.y, r.position.z,
614 r.rotation.x, r.rotation.y, r.rotation.z,
616 r.linearDamping, r.angularDamping, r.restitution,
617 r.friction, r.processType))
620 io.write(struct.pack("I", len(self.constraints)))
621 for c in self.constraints:
622 io.write(struct.pack("=20sII24f",
623 c.name, c.rigidA, c.rigidB,
624 c.pos.x, c.pos.y, c.pos.z,
625 c.rot.x, c.rot.y, c.rot.z,
626 c.constraintPosMin.x, c.constraintPosMin.y, c.constraintPosMin.z,
627 c.constraintPosMax.x, c.constraintPosMax.y, c.constraintPosMax.z,
628 c.constraintRotMin.x, c.constraintRotMin.y, c.constraintRotMin.z,
629 c.constraintRotMax.x, c.constraintRotMax.y, c.constraintRotMax.z,
630 c.springPos.x, c.springPos.y, c.springPos.z,
631 c.springRot.x, c.springRot.y, c.springRot.z
637 def _loadExtend(self):
638 ############################################################
639 # extend1: english name
640 ############################################################
641 if self.io.tell()>=self.end:
643 if struct.unpack("B", self.io.read(1))[0]==1:
644 if not self.loadEnglishName():
646 self._check_position()
648 ############################################################
649 # extend2: toon texture list
650 ############################################################
651 if self.io.tell()>=self.end:
653 if not self.loadToonTexture():
655 self._check_position()
657 ############################################################
659 ############################################################
660 if self.io.tell()>=self.end:
662 if not self.loadPhysics():
664 self._check_position()
668 def _loadHeader(self):
669 signature=struct.unpack("3s", self.io.read(3))[0]
670 if signature!=b"Pmd":
671 print("invalid signature", signature)
673 self.version=struct.unpack("f", self.io.read(4))[0]
674 self.name = truncate_zero(struct.unpack("20s", self.io.read(20))[0])
675 self.comment = truncate_zero(
676 struct.unpack("256s", self.io.read(256))[0])
679 def _loadVertex(self):
680 count = struct.unpack("I", self.io.read(4))[0]
681 for i in range(count):
682 self.vertices.append(Vertex(*struct.unpack("8f2H2B", self.io.read(38))))
686 count = struct.unpack("I", self.io.read(4))[0]
687 for i in range(0, count, 3):
688 self.indices+=struct.unpack("HHH", self.io.read(6))
691 def _loadMaterial(self):
692 count = struct.unpack("I", self.io.read(4))[0]
693 for i in range(count):
694 material=Material(*struct.unpack("4ff3f3f", self.io.read(44)))
695 material.toon_index=struct.unpack("B", self.io.read(1))[0]
696 material.flag=struct.unpack("B", self.io.read(1))[0]
697 material.vertex_count=struct.unpack("I", self.io.read(4))[0]
698 texture=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
700 #material.texture=texture.split('*')[0]
701 material.texture=texture
702 self.materials.append(material)
706 size = struct.unpack("H", self.io.read(2))[0]
707 for i in range(size):
708 name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
709 parent_index, tail_index = struct.unpack("HH", self.io.read(4))
710 type = struct.unpack("B", self.io.read(1))[0]
711 bone=createBone(name, type)
712 bone.parent_index=parent_index
713 bone.tail_index=tail_index
714 bone.ik_index = struct.unpack("H", self.io.read(2))[0]
715 bone.pos = Vector3(*struct.unpack("3f", self.io.read(12)))
716 bone.english_name="bone%03d" % len(self.bones)
717 self.bones.append(bone)
721 size = struct.unpack("H", self.io.read(2))[0]
722 for i in range(size):
723 ik=IK(*struct.unpack("2H", self.io.read(4)))
724 ik.length = struct.unpack("B", self.io.read(1))[0]
725 ik.iterations = struct.unpack("H", self.io.read(2))[0]
726 ik.weight = struct.unpack("f", self.io.read(4))[0]
727 for j in range(ik.length):
728 ik.children.append(struct.unpack("H", self.io.read(2))[0])
729 self.ik_list.append(ik)
733 size = struct.unpack("H", self.io.read(2))[0]
734 for i in range(size):
735 skin=Skin(truncate_zero(struct.unpack("20s", self.io.read(20))[0]))
736 skin_size = struct.unpack("I", self.io.read(4))[0]
737 skin.type = struct.unpack("B", self.io.read(1))[0]
738 for j in range(skin_size):
739 skin.indices.append(struct.unpack("I", self.io.read(4))[0])
740 skin.pos_list.append(
741 Vector3(*struct.unpack("3f", self.io.read(12))))
742 skin.english_name="skin%03d" % len(self.morph_list)
743 self.morph_list.append(skin)
746 def _loadSkinIndex(self):
747 size = struct.unpack("B", self.io.read(1))[0]
748 for i in range(size):
749 self.face_list.append(struct.unpack("H", self.io.read(2))[0])
752 def _loadBoneName(self):
753 size = struct.unpack("B", self.io.read(1))[0]
754 for i in range(size):
755 self.bone_group_list.append(BoneGroup(
756 truncate_zero(struct.unpack("50s", self.io.read(50))[0])))
759 def _loadBoneIndex(self):
760 size = struct.unpack("I", self.io.read(4))[0]
761 for i in range(size):
762 first=struct.unpack("H", self.io.read(2))[0]
763 second=struct.unpack("B", self.io.read(1))[0]
764 self.bone_display_list.append((first, second))
767 def loadToonTexture(self):
772 self.toon_textures[i]=truncate_zero(struct.unpack("100s", self.io.read(100))[0])
775 def loadEnglishName(self):
777 self.english_name=truncate_zero(
778 struct.unpack("20s", self.io.read(20))[0])
779 self.english_comment=truncate_zero(
780 struct.unpack("256s", self.io.read(256))[0])
781 self._check_position()
783 for bone in self.bones:
784 english_name=truncate_zero(
785 struct.unpack("20s", self.io.read(20))[0])
786 bone.english_name=english_name
787 self._check_position()
789 for skin in self.morph_list:
790 if skin.name==b'base':
792 english_name=truncate_zero(
793 struct.unpack("20s", self.io.read(20))[0])
794 #skin=self.morph_list[index]
795 if english_name!=skin.name:
796 skin.english_name=english_name
797 self._check_position()
799 for i in range(0, len(self.bone_group_list)):
800 self.bone_group_list[i].english_name=truncate_zero(
801 struct.unpack("50s", self.io.read(50))[0])
802 self._check_position()
805 def loadPhysics(self):
807 count = struct.unpack("I", self.io.read(4))[0]
808 for i in range(count):
809 name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
810 rigidbody=RigidBody(name)
811 rigidbody.boneIndex=struct.unpack("H", self.io.read(2))[0]
812 rigidbody.group=struct.unpack("B", self.io.read(1))[0]
813 rigidbody.target=struct.unpack("H", self.io.read(2))[0]
814 rigidbody.shapeType=struct.unpack("B", self.io.read(1))[0]
815 rigidbody.w=struct.unpack("f", self.io.read(4))[0]
816 rigidbody.h=struct.unpack("f", self.io.read(4))[0]
817 rigidbody.d=struct.unpack("f", self.io.read(4))[0]
818 rigidbody.position.x=struct.unpack("f", self.io.read(4))[0]
819 rigidbody.position.y=struct.unpack("f", self.io.read(4))[0]
820 rigidbody.position.z=struct.unpack("f", self.io.read(4))[0]
821 rigidbody.rotation.x=struct.unpack("f", self.io.read(4))[0]
822 rigidbody.rotation.y=struct.unpack("f", self.io.read(4))[0]
823 rigidbody.rotation.z=struct.unpack("f", self.io.read(4))[0]
824 rigidbody.weight=struct.unpack("f", self.io.read(4))[0]
825 rigidbody.linearDamping=struct.unpack("f", self.io.read(4))[0]
826 rigidbody.angularDamping=struct.unpack("f", self.io.read(4))[0]
827 rigidbody.restitution=struct.unpack("f", self.io.read(4))[0]
828 rigidbody.friction=struct.unpack("f", self.io.read(4))[0]
829 rigidbody.processType=struct.unpack("B", self.io.read(1))[0]
830 self.rigidbodies.append(rigidbody)
831 self._check_position()
834 count = struct.unpack("I", self.io.read(4))[0]
835 for i in range(count):
836 name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
837 constraint=Constraint(name)
838 constraint.rigidA=struct.unpack("I", self.io.read(4))[0]
839 constraint.rigidB=struct.unpack("I", self.io.read(4))[0]
840 constraint.pos.x=struct.unpack("f", self.io.read(4))[0]
841 constraint.pos.y=struct.unpack("f", self.io.read(4))[0]
842 constraint.pos.z=struct.unpack("f", self.io.read(4))[0]
843 constraint.rot.x=struct.unpack("f", self.io.read(4))[0]
844 constraint.rot.y=struct.unpack("f", self.io.read(4))[0]
845 constraint.rot.z=struct.unpack("f", self.io.read(4))[0]
846 constraint.constraintPosMin.x=struct.unpack("f", self.io.read(4))[0]
847 constraint.constraintPosMin.y=struct.unpack("f", self.io.read(4))[0]
848 constraint.constraintPosMin.z=struct.unpack("f", self.io.read(4))[0]
849 constraint.constraintPosMax.x=struct.unpack("f", self.io.read(4))[0]
850 constraint.constraintPosMax.y=struct.unpack("f", self.io.read(4))[0]
851 constraint.constraintPosMax.z=struct.unpack("f", self.io.read(4))[0]
852 constraint.constraintRotMin.x=struct.unpack("f", self.io.read(4))[0]
853 constraint.constraintRotMin.y=struct.unpack("f", self.io.read(4))[0]
854 constraint.constraintRotMin.z=struct.unpack("f", self.io.read(4))[0]
855 constraint.constraintRotMax.x=struct.unpack("f", self.io.read(4))[0]
856 constraint.constraintRotMax.y=struct.unpack("f", self.io.read(4))[0]
857 constraint.constraintRotMax.z=struct.unpack("f", self.io.read(4))[0]
858 constraint.springPos.x=struct.unpack("f", self.io.read(4))[0]
859 constraint.springPos.y=struct.unpack("f", self.io.read(4))[0]
860 constraint.springPos.z=struct.unpack("f", self.io.read(4))[0]
861 constraint.springRot.x=struct.unpack("f", self.io.read(4))[0]
862 constraint.springRot.y=struct.unpack("f", self.io.read(4))[0]
863 constraint.springRot.z=struct.unpack("f", self.io.read(4))[0]
864 self.constraints.append(constraint)
865 self._check_position()