4 http://blog.goo.ne.jp/torisu_tetosuki/e/209ad341d3ece2b1b4df24abf619d6e4
21 weight0: bone0 influence
24 __slots__=['pos', 'normal', 'uv', 'bone0', 'bone1', 'weight0', 'edge_flag']
25 def __init__(self, x=0, y=0, z=0, nx=0, ny=0, nz=0, u=0, v=0,
26 bone0=0, bone1=0, weight0=0, edge_flag=0):
27 self.pos=Vector3(x, y, z)
28 self.normal=Vector3(nx, ny, nz)
33 self.edge_flag=edge_flag
36 return "<%s %s %s, (%d, %d, %d)>" % (
40 self.bone0, self.bone1, self.weight0)
42 def __getitem__(self, key):
53 class Material(object):
54 """pmd material struct.
61 vertex_count: indices length
62 _texture: texture file path
67 'diffuse', 'shinness', 'specular',
68 'ambient', 'vertex_count', '_texture', 'toon_index', 'flag',
70 def getTexture(self): return from_str(self._texture)
71 def setTexture(self, texture): self._texture=to_str(texture)
72 texture=property(getTexture, setTexture)
74 def __init__(self, dr=0, dg=0, db=0, alpha=1,
75 specular=0, sr=0, sg=0, sb=0, ar=0, ag=0, ab=0):
76 self.diffuse=RGBA(dr, dg, db, alpha)
77 self.specular=RGBA(sr, sg, sb)
78 self.shinness=specular
79 self.ambient=RGBA(ar, ag, ab)
86 return "<Material [%f, %f, %f, %f]>" % (
87 self.diffuse[0], self.diffuse[1],
88 self.diffuse[2], self.diffuse[3],
93 """pmd material struct.
121 __slots__=['_name', 'index', 'type', 'parent', 'ik', 'pos',
122 'children', '_english_name', 'ik_index',
123 'parent_index', 'tail_index', 'tail',
127 return str(multibyte) in python2
128 return bytes in python3
130 return from_str(self._name)
131 def setName(self, name): self._name=to_str(name)
132 name=property(getName, setName)
133 def getEnglishName(self): return from_str(self._english_name)
134 def setEnglishName(self, english_name): self._english_name=to_str(english_name)
135 english_name=property(getEnglishName, setEnglishName)
137 def __init__(self, name='bone', type=0):
141 self.parent_index=0xFFFF
143 self.tail=Vector3(0, 0, 0)
146 self.pos=Vector3(0, 0, 0)
151 return self.parent_index!=0xFFFF
154 return self.tail_index!=0
156 def display(self, indent=[]):
159 for i, is_end in enumerate(indent):
163 prefix+=' ' if is_end else ' |'
164 uni='%s +%s(%s)' % (prefix, unicode(self), self.english_name)
165 print(uni.encode(ENCODING))
167 uni='%s(%s)' % (unicode(self), self.english_name)
168 print(uni.encode(ENCODING))
170 child_count=len(self.children)
171 for i in range(child_count):
172 child=self.children[i]
174 child.display(indent+[False])
177 child.display(indent+[True])
180 class Bone_Rotate(Bone):
182 def __init__(self, name):
183 super(Bone_Rotate, self).__init__(name, 0)
185 return '<ROTATE %s>' % (self.name)
187 class Bone_RotateMove(Bone):
189 def __init__(self, name):
190 super(Bone_RotateMove, self).__init__(name, 1)
192 return '<ROTATE_MOVE %s>' % (self.name)
196 def __init__(self, name):
197 super(Bone_IK, self).__init__(name, 2)
199 return '<IK %s>' % (self.name)
201 class Bone_IKRotateInfl(Bone):
203 def __init__(self, name):
204 super(Bone_IKRotateInfl, self).__init__(name, 4)
206 return '<IK_ROTATE_INFL %s>' % (self.name)
208 class Bone_RotateInfl(Bone):
210 def __init__(self, name):
211 super(Bone_RotateInfl, self).__init__(name, 5)
213 return '<ROTATE_INFL %s>' % (self.name)
215 class Bone_IKTarget(Bone):
217 def __init__(self, name):
218 super(Bone_IKTarget, self).__init__(name, 6)
220 return '<IK_TARGET %s>' % (self.name)
222 class Bone_Unvisible(Bone):
224 def __init__(self, name):
225 super(Bone_Unvisible, self).__init__(name, 7)
227 return '<UNVISIBLE %s>' % (self.name)
229 class Bone_Rolling(Bone):
231 def __init__(self, name):
232 super(Bone_Rolling, self).__init__(name, 8)
234 return '<ROLLING %s>' % (self.name)
236 class Bone_Tweak(Bone):
238 def __init__(self, name):
239 super(Bone_Tweak, self).__init__(name, 9)
241 return '<TWEAK %s>' % (self.name)
244 def createBone(name, type):
246 return Bone_Rotate(name)
248 return Bone_RotateMove(name)
252 raise Exception("no used bone type: 3(%s)" % name)
254 return Bone_IKRotateInfl(name)
256 return Bone_RotateInfl(name)
258 return Bone_IKTarget(name)
260 return Bone_Unvisible(name)
262 return Bone_Rolling(name)
264 return Bone_Tweak(name)
266 raise Exception("unknown bone type: %d(%s)", type, name)
270 __slots__=['index', 'target', 'iterations', 'weight', 'length', 'children']
271 def __init__(self, index=0, target=0):
279 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))
283 __slots__=['_name', 'type', 'indices', 'pos_list', '_english_name',
285 def getName(self): return from_str(self._name)
286 def setName(self, name): self._name=to_str(name)
287 name=property(getName, setName)
288 def getEnglishName(self): return from_str(self._english_name)
289 def setEnglishName(self, english_name): self._english_name=to_str(english_name)
290 english_name=property(getEnglishName, setEnglishName)
292 def __init__(self, name='skin'):
300 def append(self, index, x, y, z):
301 self.indices.append(index)
302 self.pos_list.append(Vector3(x, y, z))
305 return '<Skin name: "%s", type: %d, vertex: %d>' % (
306 self.name, self.type, len(self.indices))
309 class BoneGroup(object):
310 __slots__=['_name', '_english_name']
311 def getName(self): return from_str(self._name)
312 def setName(self, name): self._name=to_str(name)
313 name=property(getName, setName)
314 def getEnglishName(self): return from_str(self._english_name)
315 def setEnglishName(self, english_name): self._english_name=to_str(english_name)
316 english_name=property(getEnglishName, setEnglishName)
318 def __init__(self, name='group'): self._name=name; self._english_name='center'
325 RIGIDBODY_KINEMATICS=0
327 RIGIDBODY_PHYSICS_WITH_BONE=2
330 class RigidBody(object):
331 __slots__=['_name', 'boneIndex', 'group', 'target', 'shapeType',
332 'w', 'h', 'd', 'position', 'rotation', 'weight',
333 'linearDamping', 'angularDamping', 'restitution', 'friction', 'processType'
335 def getName(self): return from_str(self._name)
336 def setName(self, name): self._name=to_str(name)
337 name=property(getName, setName)
339 def __init__(self, name):
341 self.position=Vector3()
342 self.rotation=Vector3()
345 class Constraint(object):
346 __slots__=[ '_name', 'rigidA', 'rigidB', 'pos', 'rot',
347 'constraintPosMin', 'constraintPosMax',
348 'constraintRotMin', 'constraintRotMax',
349 'springPos', 'springRot',
351 def getName(self): return from_str(self._name)
352 def setName(self, name): self._name=to_str(name)
353 name=property(getName, setName)
355 def __init__(self, name):
359 self.constraintPosMin=Vector3()
360 self.constraintPosMax=Vector3()
361 self.constraintRotMin=Vector3()
362 self.constraintRotMax=Vector3()
363 self.springPos=Vector3()
364 self.springRot=Vector3()
367 class ToonTextures(object):
368 __slots__=['_toon_textures']
370 self._toon_textures=[]
372 self._toon_textures.append('toon%02d.bmp' % (i+1))
374 def __getitem__(self, key):
375 return from_str(self._toon_textures[key])
377 def __setitem__(self, key, value):
378 self._toon_textures[key]=to_str(value)
381 for toon_texture in self._toon_textures:
382 yield from_str(toon_texture)
393 version: pmd version number
396 __slots__=['io', 'end', 'pos',
397 'version', '_name', '_comment',
398 '_english_name', '_english_comment',
399 'vertices', 'indices', 'materials', 'bones',
400 'ik_list', 'morph_list',
401 'face_list', 'bone_group_list', 'bone_display_list',
404 'rigidbodies', 'constraints',
406 def getName(self): return from_str(self._name)
407 def setName(self, name): self._name=to_str(name)
408 name=property(getName, setName)
409 def getEnglishName(self): return from_str(self._english_name)
410 def setEnglishName(self, english_name): self._english_name=to_str(english_name)
411 english_name=property(getEnglishName, setEnglishName)
412 def getComment(self): return from_str(self._comment)
413 def setComment(self, comment): self._comment=to_str(comment)
414 comment=property(getComment, setComment)
415 def getEnglishComment(self): return from_str(self._english_comment)
416 def setEnglishComment(self, english_comment): self._english_comment=to_str(english_comment)
417 english_comment=property(getEnglishComment, setEnglishComment)
424 self.english_comment=''
432 self.bone_group_list=[]
433 self.bone_display_list=[]
435 self.toon_textures=ToonTextures()
439 self.no_parent_bones=[]
441 def each_vertex(self): return self.vertices
442 def getUV(self, i): return self.vertices[i].uv
445 self.vertices.append(v)
447 def addMaterial(self):
449 self.materials.append(m)
457 self.ik_list.append(ik)
461 self.morph_list.append(s)
463 def addBoneGroup(self):
465 self.bone_group_list.append(g)
467 def addBoneDisplay(self, b, g):
468 self.bone_display_list.append((b, g))
471 return '<PMDLoader version: %g, model: "%s", vertex: %d, face: %d, material: %d, bone: %d ik: %d, skin: %d>' % (
472 self.version, self.name, len(self.vertices), len(self.indices),
473 len(self.materials), len(self.bones), len(self.ik_list), len(self.morph_list))
475 def _check_position(self):
476 self.pos=self.io.tell()
478 def read(self, path):
479 size=os.path.getsize(path)
480 with open(path, "rb") as f:
481 return self.load(path, f, size)
483 def load(self, path, io, end):
485 self.pos=self.io.tell()
487 self._check_position()
489 if not self._loadHeader():
491 self._check_position()
493 if not self._loadVertex():
495 self._check_position()
497 if not self._loadFace():
499 self._check_position()
501 if not self._loadMaterial():
503 self._check_position()
505 if not self._loadBone():
507 self._check_position()
509 if not self._loadIK():
511 self._check_position()
513 if not self._loadSkin():
515 self._check_position()
517 if not self._loadSkinIndex():
519 self._check_position()
521 if not self._loadBoneName():
523 self._check_position()
525 if not self._loadBoneIndex():
527 self._check_position()
529 if not self._loadExtend():
530 print('fail to loadExtend')
534 if self.io.tell()!=self.end:
535 print("can not reach eof.")
536 print("current: %d, end: %d, remain: %d" % (
537 self.io.tell(), self.end, self.end-self.io.tell()))
540 for i, child in enumerate(self.bones):
541 if child.parent_index==0xFFFF:
543 self.no_parent_bones.append(child)
547 parent=self.bones[child.parent_index]
549 parent.children.append(child)
552 child.tail=self.bones[child.tail_index].pos
556 def write(self, path):
562 io.write(struct.pack("f", self.version))
563 io.write(struct.pack("20s", self.name))
564 io.write(struct.pack("256s", self.comment))
567 io.write(struct.pack("I", len(self.vertices)))
568 sVertex=struct.Struct("=8f2H2B") # 38byte
569 assert(sVertex.size==38)
570 for v in self.vertices:
572 v.pos[0], v.pos[1], v.pos[2],
573 v.normal[0], v.normal[1], v.normal[2],
575 v.bone0, v.bone1, v.weight0, v.edge_flag)
579 io.write(struct.pack("I", len(self.indices)))
580 io.write(struct.pack("=%dH" % len(self.indices), *self.indices))
583 io.write(struct.pack("I", len(self.materials)))
584 sMaterial=struct.Struct("=3fff3f3fBBI20s") # 70byte
585 assert(sMaterial.size==70)
586 for m in self.materials:
587 io.write(sMaterial.pack(
588 m.diffuse[0], m.diffuse[1], m.diffuse[2], m.diffuse[3],
590 m.specular[0], m.specular[1], m.specular[2],
591 m.ambient[0], m.ambient[1], m.ambient[2],
592 m.toon_index, m.flag,
598 io.write(struct.pack("H", len(self.bones)))
599 sBone=struct.Struct("=20sHHBH3f")
600 assert(sBone.size==39)
604 b.parent_index, b.tail_index, b.type, b.ik_index,
605 b.pos[0], b.pos[1], b.pos[2]))
608 io.write(struct.pack("H", len(self.ik_list)))
609 for ik in self.ik_list:
610 io.write(struct.pack("=2HBHf",
611 ik.index, ik.target, ik.length, ik.iterations, ik.weight
613 for c in ik.children:
614 io.write(struct.pack("H", c))
617 io.write(struct.pack("H", len(self.morph_list)))
618 for s in self.morph_list:
619 io.write(struct.pack("20sIB",
620 s.name, len(s.indices), s.type))
621 for i, v in zip(s.indices, s.pos_list):
622 io.write(struct.pack("I3f", i, v[0], v[1], v[2]))
625 io.write(struct.pack("B", len(self.face_list)))
626 for i in self.face_list:
627 io.write(struct.pack("H", i))
630 io.write(struct.pack("B", len(self.bone_group_list)))
631 for g in self.bone_group_list:
632 io.write(struct.pack("50s", g.name))
634 io.write(struct.pack("I", len(self.bone_display_list)))
635 for l in self.bone_display_list:
636 io.write(struct.pack("=HB", *l))
638 ############################################################
640 ############################################################
641 io.write(struct.pack("B", 1))
643 io.write(struct.pack("=20s", self.english_name))
644 io.write(struct.pack("=256s", self.english_comment))
646 for bone in self.bones:
647 io.write(struct.pack("=20s", bone.english_name))
649 for skin in self.morph_list:
651 if skin.name==b'base':
653 io.write(struct.pack("=20s", skin.english_name))
655 for bone_group in self.bone_group_list:
656 io.write(struct.pack("50s", bone_group.english_name))
658 for toon_texture in self.toon_textures:
659 io.write(struct.pack("=100s", toon_texture))
661 io.write(struct.pack("I", len(self.rigidbodies)))
662 for r in self.rigidbodies:
663 io.write(struct.pack("=20sHBHB14fB",
664 r.name, r.boneIndex, r.group, r.target, r.shapeType,
666 r.position.x, r.position.y, r.position.z,
667 r.rotation.x, r.rotation.y, r.rotation.z,
669 r.linearDamping, r.angularDamping, r.restitution,
670 r.friction, r.processType))
673 io.write(struct.pack("I", len(self.constraints)))
674 for c in self.constraints:
675 io.write(struct.pack("=20sII24f",
676 c.name, c.rigidA, c.rigidB,
677 c.pos.x, c.pos.y, c.pos.z,
678 c.rot.x, c.rot.y, c.rot.z,
679 c.constraintPosMin.x, c.constraintPosMin.y, c.constraintPosMin.z,
680 c.constraintPosMax.x, c.constraintPosMax.y, c.constraintPosMax.z,
681 c.constraintRotMin.x, c.constraintRotMin.y, c.constraintRotMin.z,
682 c.constraintRotMax.x, c.constraintRotMax.y, c.constraintRotMax.z,
683 c.springPos.x, c.springPos.y, c.springPos.z,
684 c.springRot.x, c.springRot.y, c.springRot.z
690 def _loadExtend(self):
691 ############################################################
692 # extend1: english name
693 ############################################################
694 if self.io.tell()>=self.end:
696 if struct.unpack("B", self.io.read(1))[0]==1:
697 if not self.loadEnglishName():
699 self._check_position()
701 ############################################################
702 # extend2: toon texture list
703 ############################################################
704 if self.io.tell()>=self.end:
706 if not self.loadToonTexture():
708 self._check_position()
710 ############################################################
712 ############################################################
713 if self.io.tell()>=self.end:
715 if not self.loadPhysics():
717 self._check_position()
721 def _loadHeader(self):
722 signature=struct.unpack("3s", self.io.read(3))[0]
723 if signature!=b"Pmd":
724 print("invalid signature", signature)
726 self.version=struct.unpack("f", self.io.read(4))[0]
727 self.name = truncate_zero(struct.unpack("20s", self.io.read(20))[0])
728 self.comment = truncate_zero(
729 struct.unpack("256s", self.io.read(256))[0])
732 def _loadVertex(self):
733 count = struct.unpack("I", self.io.read(4))[0]
734 for i in range(count):
735 self.vertices.append(Vertex(*struct.unpack("8f2H2B", self.io.read(38))))
739 count = struct.unpack("I", self.io.read(4))[0]
740 for i in range(0, count, 3):
741 self.indices+=struct.unpack("HHH", self.io.read(6))
744 def _loadMaterial(self):
745 count = struct.unpack("I", self.io.read(4))[0]
746 for i in range(count):
747 material=Material(*struct.unpack("4ff3f3f", self.io.read(44)))
748 material.toon_index=struct.unpack("B", self.io.read(1))[0]
749 material.flag=struct.unpack("B", self.io.read(1))[0]
750 material.vertex_count=struct.unpack("I", self.io.read(4))[0]
751 texture=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
753 #material.texture=texture.split('*')[0]
754 material.texture=texture
755 self.materials.append(material)
759 size = struct.unpack("H", self.io.read(2))[0]
760 for i in range(size):
761 name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
762 parent_index, tail_index = struct.unpack("HH", self.io.read(4))
763 type = struct.unpack("B", self.io.read(1))[0]
764 bone=createBone(name, type)
765 bone.parent_index=parent_index
766 bone.tail_index=tail_index
767 bone.ik_index = struct.unpack("H", self.io.read(2))[0]
768 bone.pos = Vector3(*struct.unpack("3f", self.io.read(12)))
769 bone.english_name="bone%03d" % len(self.bones)
770 self.bones.append(bone)
774 size = struct.unpack("H", self.io.read(2))[0]
775 for i in range(size):
776 ik=IK(*struct.unpack("2H", self.io.read(4)))
777 ik.length = struct.unpack("B", self.io.read(1))[0]
778 ik.iterations = struct.unpack("H", self.io.read(2))[0]
779 ik.weight = struct.unpack("f", self.io.read(4))[0]
780 for j in range(ik.length):
781 ik.children.append(struct.unpack("H", self.io.read(2))[0])
782 self.ik_list.append(ik)
786 size = struct.unpack("H", self.io.read(2))[0]
787 for i in range(size):
788 skin=Skin(truncate_zero(struct.unpack("20s", self.io.read(20))[0]))
789 skin_size = struct.unpack("I", self.io.read(4))[0]
790 skin.type = struct.unpack("B", self.io.read(1))[0]
791 for j in range(skin_size):
792 skin.indices.append(struct.unpack("I", self.io.read(4))[0])
793 skin.pos_list.append(
794 Vector3(*struct.unpack("3f", self.io.read(12))))
795 skin.english_name="skin%03d" % len(self.morph_list)
796 self.morph_list.append(skin)
799 def _loadSkinIndex(self):
800 size = struct.unpack("B", self.io.read(1))[0]
801 for i in range(size):
802 self.face_list.append(struct.unpack("H", self.io.read(2))[0])
805 def _loadBoneName(self):
806 size = struct.unpack("B", self.io.read(1))[0]
807 for i in range(size):
808 self.bone_group_list.append(BoneGroup(
809 truncate_zero(struct.unpack("50s", self.io.read(50))[0])))
812 def _loadBoneIndex(self):
813 size = struct.unpack("I", self.io.read(4))[0]
814 for i in range(size):
815 first=struct.unpack("H", self.io.read(2))[0]
816 second=struct.unpack("B", self.io.read(1))[0]
817 self.bone_display_list.append((first, second))
820 def loadToonTexture(self):
825 self.toon_textures[i]=truncate_zero(struct.unpack("100s", self.io.read(100))[0])
828 def loadEnglishName(self):
830 self.english_name=truncate_zero(
831 struct.unpack("20s", self.io.read(20))[0])
832 self.english_comment=truncate_zero(
833 struct.unpack("256s", self.io.read(256))[0])
834 self._check_position()
836 for bone in self.bones:
837 english_name=truncate_zero(
838 struct.unpack("20s", self.io.read(20))[0])
839 bone.english_name=english_name
840 self._check_position()
842 for skin in self.morph_list:
843 if skin.name==b'base':
845 english_name=truncate_zero(
846 struct.unpack("20s", self.io.read(20))[0])
847 #skin=self.morph_list[index]
848 if english_name!=skin.name:
849 skin.english_name=english_name
850 self._check_position()
852 for i in range(0, len(self.bone_group_list)):
853 self.bone_group_list[i].english_name=truncate_zero(
854 struct.unpack("50s", self.io.read(50))[0])
855 self._check_position()
858 def loadPhysics(self):
860 count = struct.unpack("I", self.io.read(4))[0]
861 for i in range(count):
862 name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
863 rigidbody=RigidBody(name)
864 rigidbody.boneIndex=struct.unpack("H", self.io.read(2))[0]
865 rigidbody.group=struct.unpack("B", self.io.read(1))[0]
866 rigidbody.target=struct.unpack("H", self.io.read(2))[0]
867 rigidbody.shapeType=struct.unpack("B", self.io.read(1))[0]
868 rigidbody.w=struct.unpack("f", self.io.read(4))[0]
869 rigidbody.h=struct.unpack("f", self.io.read(4))[0]
870 rigidbody.d=struct.unpack("f", self.io.read(4))[0]
871 rigidbody.position.x=struct.unpack("f", self.io.read(4))[0]
872 rigidbody.position.y=struct.unpack("f", self.io.read(4))[0]
873 rigidbody.position.z=struct.unpack("f", self.io.read(4))[0]
874 rigidbody.rotation.x=struct.unpack("f", self.io.read(4))[0]
875 rigidbody.rotation.y=struct.unpack("f", self.io.read(4))[0]
876 rigidbody.rotation.z=struct.unpack("f", self.io.read(4))[0]
877 rigidbody.weight=struct.unpack("f", self.io.read(4))[0]
878 rigidbody.linearDamping=struct.unpack("f", self.io.read(4))[0]
879 rigidbody.angularDamping=struct.unpack("f", self.io.read(4))[0]
880 rigidbody.restitution=struct.unpack("f", self.io.read(4))[0]
881 rigidbody.friction=struct.unpack("f", self.io.read(4))[0]
882 rigidbody.processType=struct.unpack("B", self.io.read(1))[0]
883 self.rigidbodies.append(rigidbody)
884 self._check_position()
887 count = struct.unpack("I", self.io.read(4))[0]
888 for i in range(count):
889 name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
890 constraint=Constraint(name)
891 constraint.rigidA=struct.unpack("I", self.io.read(4))[0]
892 constraint.rigidB=struct.unpack("I", self.io.read(4))[0]
893 constraint.pos.x=struct.unpack("f", self.io.read(4))[0]
894 constraint.pos.y=struct.unpack("f", self.io.read(4))[0]
895 constraint.pos.z=struct.unpack("f", self.io.read(4))[0]
896 constraint.rot.x=struct.unpack("f", self.io.read(4))[0]
897 constraint.rot.y=struct.unpack("f", self.io.read(4))[0]
898 constraint.rot.z=struct.unpack("f", self.io.read(4))[0]
899 constraint.constraintPosMin.x=struct.unpack("f", self.io.read(4))[0]
900 constraint.constraintPosMin.y=struct.unpack("f", self.io.read(4))[0]
901 constraint.constraintPosMin.z=struct.unpack("f", self.io.read(4))[0]
902 constraint.constraintPosMax.x=struct.unpack("f", self.io.read(4))[0]
903 constraint.constraintPosMax.y=struct.unpack("f", self.io.read(4))[0]
904 constraint.constraintPosMax.z=struct.unpack("f", self.io.read(4))[0]
905 constraint.constraintRotMin.x=struct.unpack("f", self.io.read(4))[0]
906 constraint.constraintRotMin.y=struct.unpack("f", self.io.read(4))[0]
907 constraint.constraintRotMin.z=struct.unpack("f", self.io.read(4))[0]
908 constraint.constraintRotMax.x=struct.unpack("f", self.io.read(4))[0]
909 constraint.constraintRotMax.y=struct.unpack("f", self.io.read(4))[0]
910 constraint.constraintRotMax.z=struct.unpack("f", self.io.read(4))[0]
911 constraint.springPos.x=struct.unpack("f", self.io.read(4))[0]
912 constraint.springPos.y=struct.unpack("f", self.io.read(4))[0]
913 constraint.springPos.z=struct.unpack("f", self.io.read(4))[0]
914 constraint.springRot.x=struct.unpack("f", self.io.read(4))[0]
915 constraint.springRot.y=struct.unpack("f", self.io.read(4))[0]
916 constraint.springRot.z=struct.unpack("f", self.io.read(4))[0]
917 self.constraints.append(constraint)
918 self._check_position()