6 ###############################################################################
8 ###############################################################################
9 def encode_string(src):
12 return src.encode('cp932')
16 raise "INVALID str: %s" % t
20 __slots__=['pos', 'normal', 'uv', 'bone0', 'bone1', 'weight0', 'edge_flag']
21 def __init__(self, x=0, y=0, z=0, nx=0, ny=0, nz=0, u=0, v=0,
22 bone0=0, bone1=0, weight0=0, edge_flag=0):
23 self.pos=Vector3(x, y, z)
24 self.normal=Vector3(nx, ny, nz)
29 self.edge_flag=edge_flag
32 return "<%s %s %s, (%d, %d, %d)>" % (str(self.pos), str(self.normal), str(self.uv), self.bone0, self.bone1, self.weight0)
34 def __getitem__(self, key):
45 class Material(object):
47 'diffuse', 'shinness', 'specular',
48 'ambient', 'vertex_count', '_texture', 'toon_index', 'flag',
50 def getTexture(self): return self._texture
51 def setTexture(self, texture): self._texture=encode_string(texture)
52 texture=property(getTexture, setTexture)
54 def __init__(self, dr=0, dg=0, db=0, alpha=1,
55 specular=0, sr=0, sg=0, sb=0, ar=0, ag=0, ab=0):
56 self.diffuse=RGBA(dr, dg, db, alpha)
57 self.specular=RGBA(sr, sg, sb)
58 self.shinness=specular
59 self.ambient=RGBA(ar, ag, ab)
66 return "<Material [%f, %f, %f, %f]>" % (
67 self.diffuse[0], self.diffuse[1],
68 self.diffuse[2], self.diffuse[3],
72 # @return 各マテリアルについて、そのマテリアルが保持する面の回数だけ
74 def material_per_face(materials):
76 for x in range(int(m.vertex_count/3)):
92 __slots__=['_name', 'index', 'type', 'parent', 'ik', 'pos',
93 'children', '_english_name', 'ik_index',
94 'parent_index', 'tail_index', 'tail',
96 def getName(self): return self._name
97 def setName(self, name): self._name=encode_string(name)
98 name=property(getName, setName)
99 def getEnglishName(self): return self._english_name
100 def setEnglishName(self, english_name): self._english_name=encode_string(english_name)
101 english_name=property(getEnglishName, setEnglishName)
103 def __init__(self, name='bone', type=0):
107 self.parent_index=0xFFFF
109 self.tail=Vector3(0, 0, 0)
112 self.pos=Vector3(0, 0, 0)
117 return self.parent_index!=0xFFFF
120 return self.tail_index!=0
122 def display(self, indent=[]):
125 for i, is_end in enumerate(indent):
129 prefix+=' ' if is_end else ' |'
130 uni='%s +%s(%s)' % (prefix, unicode(self), self.english_name)
131 print(uni.encode(ENCODING))
133 uni='%s(%s)' % (unicode(self), self.english_name)
134 print(uni.encode(ENCODING))
136 child_count=len(self.children)
137 for i in range(child_count):
138 child=self.children[i]
140 child.display(indent+[False])
143 child.display(indent+[True])
146 class Bone_Rotate(Bone):
148 def __init__(self, name):
149 super(Bone_Rotate, self).__init__(name, 0)
151 return '<ROTATE %s>' % (self.name)
153 class Bone_RotateMove(Bone):
155 def __init__(self, name):
156 super(Bone_RotateMove, self).__init__(name, 1)
158 return '<ROTATE_MOVE %s>' % (self.name)
162 def __init__(self, name):
163 super(Bone_IK, self).__init__(name, 2)
165 return '<IK %s>' % (self.name)
167 class Bone_IKRotateInfl(Bone):
169 def __init__(self, name):
170 super(Bone_IKRotateInfl, self).__init__(name, 4)
172 return '<IK_ROTATE_INFL %s>' % (self.name)
174 class Bone_RotateInfl(Bone):
176 def __init__(self, name):
177 super(Bone_RotateInfl, self).__init__(name, 5)
179 return '<ROTATE_INFL %s>' % (self.name)
181 class Bone_IKTarget(Bone):
183 def __init__(self, name):
184 super(Bone_IKTarget, self).__init__(name, 6)
186 return '<IK_TARGET %s>' % (self.name)
188 class Bone_Unvisible(Bone):
190 def __init__(self, name):
191 super(Bone_Unvisible, self).__init__(name, 7)
193 return '<UNVISIBLE %s>' % (self.name)
195 class Bone_Rolling(Bone):
197 def __init__(self, name):
198 super(Bone_Rolling, self).__init__(name, 8)
200 return '<ROLLING %s>' % (self.name)
202 class Bone_Tweak(Bone):
204 def __init__(self, name):
205 super(Bone_Tweak, self).__init__(name, 9)
207 return '<TWEAK %s>' % (self.name)
210 def createBone(name, type):
212 return Bone_Rotate(name)
214 return Bone_RotateMove(name)
218 raise Exception("no used bone type: 3(%s)" % name)
220 return Bone_IKRotateInfl(name)
222 return Bone_RotateInfl(name)
224 return Bone_IKTarget(name)
226 return Bone_Unvisible(name)
228 return Bone_Rolling(name)
230 return Bone_Tweak(name)
232 raise Exception("unknown bone type: %d(%s)", type, name)
236 __slots__=['index', 'target', 'iterations', 'weight', 'length', 'children']
237 def __init__(self, index=0, target=0):
245 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))
249 __slots__=['_name', 'type', 'indices', 'pos_list', '_english_name',
251 def getName(self): return self._name
252 def setName(self, name): self._name=encode_string(name)
253 name=property(getName, setName)
254 def getEnglishName(self): return self._english_name
255 def setEnglishName(self, english_name): self._english_name=encode_string(english_name)
256 english_name=property(getEnglishName, setEnglishName)
258 def __init__(self, name='skin'):
266 def append(self, index, x, y, z):
267 self.indices.append(index)
268 self.pos_list.append(Vector3(x, y, z))
271 return '<Skin name: "%s", type: %d, vertex: %d>' % (
272 self.name, self.type, len(self.indices))
275 class BoneGroup(object):
276 __slots__=['_name', '_english_name']
277 def getName(self): return self._name
278 def setName(self, name): self._name=encode_string(name)
279 name=property(getName, setName)
280 def getEnglishName(self): return self._english_name
281 def setEnglishName(self, english_name): self._english_name=encode_string(english_name)
282 english_name=property(getEnglishName, setEnglishName)
284 def __init__(self, name='group'): self._name=name; self._english_name='center'
291 RIGIDBODY_KINEMATICS=0
293 RIGIDBODY_PHYSICS_WITH_BONE=2
296 class RigidBody(object):
297 __slots__=['_name', 'boneIndex', 'group', 'target', 'shapeType',
298 'w', 'h', 'd', 'position', 'rotation', 'weight',
299 'linearDamping', 'angularDamping', 'restitution', 'friction', 'processType'
301 def getName(self): return self._name
302 def setName(self, name): self._name=encode_string(name)
303 name=property(getName, setName)
305 def __init__(self, name):
307 self.position=Vector3()
308 self.rotation=Vector3()
311 class Constraint(object):
312 __slots__=[ '_name', 'rigidA', 'rigidB', 'pos', 'rot',
313 'constraintPosMin', 'constraintPosMax',
314 'constraintRotMin', 'constraintRotMax',
315 'springPos', 'springRot',
317 def getName(self): return self._name
318 def setName(self, name): self._name=encode_string(name)
319 name=property(getName, setName)
321 def __init__(self, name):
325 self.constraintPosMin=Vector3()
326 self.constraintPosMax=Vector3()
327 self.constraintRotMin=Vector3()
328 self.constraintRotMax=Vector3()
329 self.springPos=Vector3()
330 self.springRot=Vector3()
334 __slots__=['io', 'end', 'pos',
335 'version', '_name', '_comment',
336 '_english_name', '_english_comment',
337 'vertices', 'indices', 'materials', 'bones',
338 'ik_list', 'morph_list',
339 'face_list', 'bone_group_list', 'bone_display_list',
342 'rigidbodies', 'constraints',
344 def getName(self): return self._name
345 def setName(self, name): self._name=encode_string(name)
346 name=property(getName, setName)
347 def getEnglishName(self): return self._english_name
348 def setEnglishName(self, english_name): self._english_name=encode_string(english_name)
349 english_name=property(getEnglishName, setEnglishName)
350 def getComment(self): return self._comment
351 def setComment(self, comment): self._comment=encode_string(comment)
352 comment=property(getComment, setComment)
353 def getEnglishComment(self): return self._english_comment
354 def setEnglishComment(self, english_comment): self._english_comment=encode_string(english_comment)
355 english_comment=property(getEnglishComment, setEnglishComment)
360 self.comment="default"
361 self.english_name='default'
362 self.english_comment='default'
371 self.bone_group_list=[]
372 self.bone_display_list=[]
375 b'toon01.bmp', b'toon02.bmp',
376 b'toon03.bmp', b'toon04.bmp',
377 b'toon05.bmp', b'toon06.bmp',
378 b'toon07.bmp', b'toon08.bmp',
379 b'toon09.bmp', b'toon10.bmp',
382 self.no_parent_bones=[]
387 def each_vertex(self): return self.vertices
388 def getUV(self, i): return self.vertices[i].uv
391 self.vertices.append(v)
393 def addMaterial(self):
395 self.materials.append(m)
403 self.ik_list.append(ik)
407 self.morph_list.append(s)
409 def addBoneGroup(self):
411 self.bone_group_list.append(g)
413 def addBoneDisplay(self, b, g):
414 self.bone_display_list.append((b, g))
417 return '<PMDLoader version: %g, model: "%s", vertex: %d, face: %d, material: %d, bone: %d ik: %d, skin: %d>' % (
418 self.version, self.name, len(self.vertices), len(self.indices),
419 len(self.materials), len(self.bones), len(self.ik_list), len(self.morph_list))
421 def _check_position(self):
422 self.pos=self.io.tell()
424 def read(self, path):
425 size=os.path.getsize(path)
426 with open(path, "rb") as f:
427 return self.load(path, f, size)
429 def load(self, path, io, end):
431 self.pos=self.io.tell()
433 self._check_position()
435 if not self._loadHeader():
437 self._check_position()
439 if not self._loadVertex():
441 self._check_position()
443 if not self._loadFace():
445 self._check_position()
447 if not self._loadMaterial():
449 self._check_position()
451 if not self._loadBone():
453 self._check_position()
455 if not self._loadIK():
457 self._check_position()
459 if not self._loadSkin():
461 self._check_position()
463 if not self._loadSkinIndex():
465 self._check_position()
467 if not self._loadBoneName():
469 self._check_position()
471 if not self._loadBoneIndex():
473 self._check_position()
475 if not self._loadExtend():
476 print('fail to loadExtend')
480 if self.io.tell()!=self.end:
481 print("can not reach eof.")
482 print("current: %d, end: %d, remain: %d" % (
483 self.io.tell(), self.end, self.end-self.io.tell()))
486 for i, child in enumerate(self.bones):
487 if child.parent_index==0xFFFF:
489 self.no_parent_bones.append(child)
493 parent=self.bones[child.parent_index]
495 parent.children.append(child)
498 child.tail=self.bones[child.tail_index].pos
502 def write(self, path):
508 io.write(struct.pack("f", self.version))
509 io.write(struct.pack("20s", self.name))
510 io.write(struct.pack("256s", self.comment))
513 io.write(struct.pack("I", len(self.vertices)))
514 sVertex=struct.Struct("=8f2H2B") # 38byte
515 assert(sVertex.size==38)
516 for v in self.vertices:
518 v.pos[0], v.pos[1], v.pos[2],
519 v.normal[0], v.normal[1], v.normal[2],
521 v.bone0, v.bone1, v.weight0, v.edge_flag)
525 io.write(struct.pack("I", len(self.indices)))
526 io.write(struct.pack("=%dH" % len(self.indices), *self.indices))
529 io.write(struct.pack("I", len(self.materials)))
530 sMaterial=struct.Struct("=3fff3f3fBBI20s") # 70byte
531 assert(sMaterial.size==70)
532 for m in self.materials:
533 io.write(sMaterial.pack(
534 m.diffuse[0], m.diffuse[1], m.diffuse[2], m.diffuse[3],
536 m.specular[0], m.specular[1], m.specular[2],
537 m.ambient[0], m.ambient[1], m.ambient[2],
538 m.toon_index, m.flag,
544 io.write(struct.pack("H", len(self.bones)))
545 sBone=struct.Struct("=20sHHBH3f")
546 assert(sBone.size==39)
550 b.parent_index, b.tail_index, b.type, b.ik_index,
551 b.pos[0], b.pos[1], b.pos[2]))
554 io.write(struct.pack("H", len(self.ik_list)))
555 for ik in self.ik_list:
556 io.write(struct.pack("=2HBHf",
557 ik.index, ik.target, ik.length, ik.iterations, ik.weight
559 for c in ik.children:
560 io.write(struct.pack("H", c))
563 io.write(struct.pack("H", len(self.morph_list)))
564 for s in self.morph_list:
565 io.write(struct.pack("20sIB",
566 s.name, len(s.indices), s.type))
567 for i, v in zip(s.indices, s.pos_list):
568 io.write(struct.pack("I3f", i, v[0], v[1], v[2]))
571 io.write(struct.pack("B", len(self.face_list)))
572 for i in self.face_list:
573 io.write(struct.pack("H", i))
576 io.write(struct.pack("B", len(self.bone_group_list)))
577 for g in self.bone_group_list:
578 io.write(struct.pack("50s", g.name))
580 io.write(struct.pack("I", len(self.bone_display_list)))
581 for l in self.bone_display_list:
582 io.write(struct.pack("=HB", *l))
584 ############################################################
586 ############################################################
587 io.write(struct.pack("B", 1))
589 io.write(struct.pack("=20s", self.english_name))
590 io.write(struct.pack("=256s", self.english_comment))
592 for bone in self.bones:
593 io.write(struct.pack("=20s", bone.english_name))
595 for skin in self.morph_list:
597 if skin.name==b'base':
599 io.write(struct.pack("=20s", skin.english_name))
601 for bone_group in self.bone_group_list:
602 io.write(struct.pack("50s", bone_group.english_name))
605 io.write(struct.pack("=100s", self.toon_textures[i]))
607 io.write(struct.pack("I", len(self.rigidbodies)))
608 for r in self.rigidbodies:
609 io.write(struct.pack("=20sHBHB14fB",
610 r.name, r.boneIndex, r.group, r.target, r.shapeType,
612 r.position.x, r.position.y, r.position.z,
613 r.rotation.x, r.rotation.y, r.rotation.z,
615 r.linearDamping, r.angularDamping, r.restitution,
616 r.friction, r.processType))
619 io.write(struct.pack("I", len(self.constraints)))
620 for c in self.constraints:
621 io.write(struct.pack("=20sII24f",
622 c.name, c.rigidA, c.rigidB,
623 c.pos.x, c.pos.y, c.pos.z,
624 c.rot.x, c.rot.y, c.rot.z,
625 c.constraintPosMin.x, c.constraintPosMin.y, c.constraintPosMin.z,
626 c.constraintPosMax.x, c.constraintPosMax.y, c.constraintPosMax.z,
627 c.constraintRotMin.x, c.constraintRotMin.y, c.constraintRotMin.z,
628 c.constraintRotMax.x, c.constraintRotMax.y, c.constraintRotMax.z,
629 c.springPos.x, c.springPos.y, c.springPos.z,
630 c.springRot.x, c.springRot.y, c.springRot.z
636 def _loadExtend(self):
637 ############################################################
638 # extend1: english name
639 ############################################################
640 if self.io.tell()>=self.end:
642 if struct.unpack("B", self.io.read(1))[0]==1:
643 if not self.loadEnglishName():
645 self._check_position()
647 ############################################################
648 # extend2: toon texture list
649 ############################################################
650 if self.io.tell()>=self.end:
652 if not self.loadToonTexture():
654 self._check_position()
656 ############################################################
658 ############################################################
659 if self.io.tell()>=self.end:
661 if not self.loadPhysics():
663 self._check_position()
667 def _loadHeader(self):
668 signature=struct.unpack("3s", self.io.read(3))[0]
669 if signature!=b"Pmd":
670 print("invalid signature", signature)
672 self.version=struct.unpack("f", self.io.read(4))[0]
673 self.name = truncate_zero(struct.unpack("20s", self.io.read(20))[0])
674 self.comment = truncate_zero(
675 struct.unpack("256s", self.io.read(256))[0])
678 def _loadVertex(self):
679 count = struct.unpack("I", self.io.read(4))[0]
680 for i in range(count):
681 self.vertices.append(Vertex(*struct.unpack("8f2H2B", self.io.read(38))))
685 count = struct.unpack("I", self.io.read(4))[0]
686 for i in range(0, count, 3):
687 self.indices+=struct.unpack("HHH", self.io.read(6))
690 def _loadMaterial(self):
691 count = struct.unpack("I", self.io.read(4))[0]
692 for i in range(count):
693 material=Material(*struct.unpack("4ff3f3f", self.io.read(44)))
694 material.toon_index=struct.unpack("B", self.io.read(1))[0]
695 material.flag=struct.unpack("B", self.io.read(1))[0]
696 material.vertex_count=struct.unpack("I", self.io.read(4))[0]
697 texture=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
699 #material.texture=texture.split('*')[0]
700 material.texture=texture
701 self.materials.append(material)
705 size = struct.unpack("H", self.io.read(2))[0]
706 for i in range(size):
707 name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
708 parent_index, tail_index = struct.unpack("HH", self.io.read(4))
709 type = struct.unpack("B", self.io.read(1))[0]
710 bone=createBone(name, type)
711 bone.parent_index=parent_index
712 bone.tail_index=tail_index
713 bone.ik_index = struct.unpack("H", self.io.read(2))[0]
714 bone.pos = Vector3(*struct.unpack("3f", self.io.read(12)))
715 bone.english_name="bone%03d" % len(self.bones)
716 self.bones.append(bone)
720 size = struct.unpack("H", self.io.read(2))[0]
721 for i in range(size):
722 ik=IK(*struct.unpack("2H", self.io.read(4)))
723 ik.length = struct.unpack("B", self.io.read(1))[0]
724 ik.iterations = struct.unpack("H", self.io.read(2))[0]
725 ik.weight = struct.unpack("f", self.io.read(4))[0]
726 for j in range(ik.length):
727 ik.children.append(struct.unpack("H", self.io.read(2))[0])
728 self.ik_list.append(ik)
732 size = struct.unpack("H", self.io.read(2))[0]
733 for i in range(size):
734 skin=Skin(truncate_zero(struct.unpack("20s", self.io.read(20))[0]))
735 skin_size = struct.unpack("I", self.io.read(4))[0]
736 skin.type = struct.unpack("B", self.io.read(1))[0]
737 for j in range(skin_size):
738 skin.indices.append(struct.unpack("I", self.io.read(4))[0])
739 skin.pos_list.append(
740 Vector3(*struct.unpack("3f", self.io.read(12))))
741 skin.english_name="skin%03d" % len(self.morph_list)
742 self.morph_list.append(skin)
745 def _loadSkinIndex(self):
746 size = struct.unpack("B", self.io.read(1))[0]
747 for i in range(size):
748 self.face_list.append(struct.unpack("H", self.io.read(2))[0])
751 def _loadBoneName(self):
752 size = struct.unpack("B", self.io.read(1))[0]
753 for i in range(size):
754 self.bone_group_list.append(BoneGroup(
755 truncate_zero(struct.unpack("50s", self.io.read(50))[0])))
758 def _loadBoneIndex(self):
759 size = struct.unpack("I", self.io.read(4))[0]
760 for i in range(size):
761 first=struct.unpack("H", self.io.read(2))[0]
762 second=struct.unpack("B", self.io.read(1))[0]
763 self.bone_display_list.append((first, second))
766 def loadToonTexture(self):
771 self.toon_textures.append(
772 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=='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()