import sys
import os
import Blender
+from Blender import Mathutils
+import bpy
-# \e$B%U%!%$%k%7%9%F%`$NJ8;z%3!<%I\e(B
-# \e$B2~B$HG$H$N6&MQ$N$?$a\e(B
+
+# ファイルシステムの文字コード
+# 改造版との共用のため
FS_ENCODING=sys.getfilesystemencoding()
if os.path.exists(os.path.dirname(sys.argv[0])+"/utf8"):
INTERNAL_ENCODING='utf-8'
else:
INTERNAL_ENCODING=FS_ENCODING
+
+###############################################################################
+# Writer
+###############################################################################
+class Writer(object):
+ def __init__(self, path, encoding):
+ self.io=open(path, "wb")
+ self.encoding=encoding
+
+ def write(self, s):
+ self.io.write(s)
+
+ def flush(self):
+ self.io.flush()
+
+ def close(self):
+ self.io.close()
+
+
+###############################################################################
+# ProgressBar
+###############################################################################
+class ProgressBar(object):
+ def __init__(self, base):
+ print("#### %s ####" % base)
+ self.base=base
+ self.start=Blender.sys.time()
+ self.set('<start>', 0)
+
+ def advance(self, message, progress):
+ self.progress+=float(progress)
+ self._print(message)
+
+ def set(self, message, progress):
+ self.progress=float(progress)
+ self._print(message)
+
+ def _print(self, message):
+ print(message)
+ message="%s: %s" % (self.base, message)
+ if message.__class__ is unicode:
+ message=message.encode(FS_ENCODING)
+ Blender.Window.DrawProgressBar(self.progress, message)
+
+ def finish(self):
+ self.progress=1.0
+ message='finished in %.2f sec' % (Blender.sys.time()-self.start)
+ self.set(message, 1.0)
+
+
+###############################################################################
+# for mqo mikoto bone.
+###############################################################################
+class MikotoBone(object):
+ __slots__=[
+ 'name',
+ 'iHead', 'iTail', 'iUp',
+ 'vHead', 'vTail', 'vUp',
+ 'parent', 'isFloating',
+ 'children',
+ ]
+ def __init__(self, face=None, vertices=None, materials=None):
+ self.parent=None
+ self.isFloating=False
+ self.children=[]
+ if not face:
+ self.name='root'
+ return
+
+ self.name=materials[face.material_index].name.encode('utf-8')
+
+ i0=face.indices[0]
+ i1=face.indices[1]
+ i2=face.indices[2]
+ v0=vertices[i0]
+ v1=vertices[i1]
+ v2=vertices[i2]
+ e01=v1-v0
+ e12=v2-v1
+ e20=v0-v2
+ sqNorm0=e01.getSqNorm()
+ sqNorm1=e12.getSqNorm()
+ sqNorm2=e20.getSqNorm()
+ if sqNorm0>sqNorm1:
+ if sqNorm1>sqNorm2:
+ # e01 > e12 > e20
+ self.iHead=i2
+ self.iTail=i1
+ self.iUp=i0
+ else:
+ if sqNorm0>sqNorm2:
+ # e01 > e20 > e12
+ self.iHead=i2
+ self.iTail=i0
+ self.iUp=i1
+ else:
+ # e20 > e01 > e12
+ self.iHead=i1
+ self.iTail=i0
+ self.iUp=i2
+ else:
+ # 0 < 1
+ if sqNorm1<sqNorm2:
+ # e20 > e12 > e01
+ self.iHead=i1
+ self.iTail=i2
+ self.iUp=i0
+ else:
+ if sqNorm0<sqNorm2:
+ # e12 > e20 > e01
+ self.iHead=i0
+ self.iTail=i2
+ self.iUp=i1
+ else:
+ # e12 > e01 > e20
+ self.iHead=i0
+ self.iTail=i1
+ self.iUp=i2
+ self.vHead=vertices[self.iHead]
+ self.vTail=vertices[self.iTail]
+ self.vUp=vertices[self.iUp]
+
+ if self.name.endswith('[]'):
+ basename=self.name[0:-2]
+ # expand LR name
+ if self.vTail.x>0:
+ self.name="%s_L" % basename
+ else:
+ self.name="%s_R" % basename
+
+
+ def setParent(self, parent, floating=False):
+ if floating:
+ self.isFloating=True
+ self.parent=parent
+ parent.children.append(self)
+
+ def printTree(self, indent=''):
+ print("%s%s" % (indent, self.name))
+ for child in self.children:
+ child.printTree(indent+' ')
+
+
+def build_armature(armature, mikotoBone, parent=None):
+ """
+ create a armature bone.
+ """
+ bone = Armature.Editbone()
+ bone.name = mikotoBone.name.encode('utf-8')
+ armature.bones[bone.name] = bone
+
+ bone.head = Mathutils.Vector(*mikotoBone.vHead.to_a())
+ bone.tail = Mathutils.Vector(*mikotoBone.vTail.to_a())
+ if parent:
+ bone.parent=parent
+ if mikotoBone.isFloating:
+ pass
+ else:
+ bone.options=[Armature.CONNECTED]
+
+ for child in mikotoBone.children:
+ build_armature(armature, child, bone)
+
+
+def create_armature(scene, mqo):
+ """
+ create armature
+ """
+ boneObject=None
+ for o in mqo.objects:
+ if o.name.startswith('bone'):
+ boneObject=o
+ break
+ if not boneObject:
+ return
+
+ tailMap={}
+ for f in boneObject.faces:
+ if f.index_count!=3:
+ print("invalid index_count: %d" % f.index_count)
+ continue
+ b=MikotoBone(f, boneObject.vertices, mqo.materials)
+ tailMap[b.iTail]=b
+
+ ####################
+ # build mikoto bone tree
+ ####################
+ mikotoRoot=MikotoBone()
+
+ for b in tailMap.values():
+ # each bone has unique parent or is root bone.
+ if b.iHead in tailMap:
+ b.setParent(tailMap[b.iHead])
+ else:
+ isFloating=False
+ for e in boneObject.edges:
+ if b.iHead==e.indices[0]:
+ # floating bone
+ if e.indices[1] in tailMap:
+ b.setParent(tailMap[e.indices[1]], True)
+ isFloating=True
+ break
+ elif b.iHead==e.indices[1]:
+ # floating bone
+ if e.indices[0] in tailMap:
+ b.setParent(tailMap[e.indices[0]], True)
+ isFloating=True
+ break
+ if isFloating:
+ continue
+
+ # no parent bone
+ b.setParent(mikotoRoot, True)
+
+ if len(mikotoRoot.children)==0:
+ print("no root bone")
+ return
+
+ if len(mikotoRoot.children)==1:
+ # single root
+ mikotoRoot=mikotoRoot.children[0]
+ mikotoRoot.parent=None
+ else:
+ mikotoRoot.vHead=Vector3(0, 10, 0)
+ mikotoRoot.vTail=Vector3(0, 0, 0)
+
+ ####################
+ # create armature
+ ####################
+ armature = Armature.New()
+ # link to object
+ armature_object = scene.objects.new(armature)
+ # create action
+ act = Armature.NLA.NewAction()
+ act.setActive(armature_object)
+ # set XRAY
+ armature_object.drawMode |= Object.DrawModes.XRAY
+ # armature settings
+ armature.drawType = Armature.OCTAHEDRON
+ armature.envelopes = False
+ armature.vertexGroups = True
+ armature.mirrorEdit = True
+ armature.drawNames=True
+
+ # edit bones
+ armature.makeEditable()
+ build_armature(armature, mikotoRoot)
+ armature.update()
+
+ return armature_object
+
+
+class TrianglePlane(object):
+ """
+ mikoto方式ボーンのアンカーウェイト計算用。
+ (不完全)
+ """
+ __slots__=['normal',
+ 'v0', 'v1', 'v2',
+ ]
+ def __init__(self, v0, v1, v2):
+ self.v0=v0
+ self.v1=v1
+ self.v2=v2
+
+ def isInsideXY(self, p):
+ v0=Vector2(self.v0.x, self.v0.y)
+ v1=Vector2(self.v1.x, self.v1.y)
+ v2=Vector2(self.v2.x, self.v2.y)
+ e01=v1-v0
+ e12=v2-v1
+ e20=v0-v2
+ c0=Vector2.cross(e01, p-v0)
+ c1=Vector2.cross(e12, p-v1)
+ c2=Vector2.cross(e20, p-v2)
+ if c0>=0 and c1>=0 and c2>=0:
+ return True
+ if c0<=0 and c1<=0 and c2<=0:
+ return True
+
+ def isInsideYZ(self, p):
+ v0=Vector2(self.v0.y, self.v0.z)
+ v1=Vector2(self.v1.y, self.v1.z)
+ v2=Vector2(self.v2.y, self.v2.z)
+ e01=v1-v0
+ e12=v2-v1
+ e20=v0-v2
+ c0=Vector2.cross(e01, p-v0)
+ c1=Vector2.cross(e12, p-v1)
+ c2=Vector2.cross(e20, p-v2)
+ if c0>=0 and c1>=0 and c2>=0:
+ return True
+ if c0<=0 and c1<=0 and c2<=0:
+ return True
+
+ def isInsideZX(self, p):
+ v0=Vector2(self.v0.z, self.v0.x)
+ v1=Vector2(self.v1.z, self.v1.x)
+ v2=Vector2(self.v2.z, self.v2.x)
+ e01=v1-v0
+ e12=v2-v1
+ e20=v0-v2
+ c0=Vector2.cross(e01, p-v0)
+ c1=Vector2.cross(e12, p-v1)
+ c2=Vector2.cross(e20, p-v2)
+ if c0>=0 and c1>=0 and c2>=0:
+ return True
+ if c0<=0 and c1<=0 and c2<=0:
+ return True
+
+
+class MikotoAnchor(object):
+ """
+ mikoto方式スケルトンのアンカー。
+ """
+ __slots__=[
+ "triangles", "bbox",
+ ]
+ def __init__(self):
+ self.triangles=[]
+ self.bbox=None
+
+ def push(self, face, vertices):
+ if face.index_count==3:
+ self.triangles.append(TrianglePlane(
+ vertices[face.indices[0]],
+ vertices[face.indices[1]],
+ vertices[face.indices[2]]
+ ))
+ elif face.index_count==4:
+ self.triangles.append(TrianglePlane(
+ vertices[face.indices[0]],
+ vertices[face.indices[1]],
+ vertices[face.indices[2]]
+ ))
+ self.triangles.append(TrianglePlane(
+ vertices[face.indices[2]],
+ vertices[face.indices[3]],
+ vertices[face.indices[0]]
+ ))
+ # bounding box
+ if not self.bbox:
+ self.bbox=BoundingBox(vertices[face.indices[0]])
+ for i in face.indices:
+ self.bbox.expand(vertices[i])
+
+
+ def calcWeight(self, v):
+ if not self.bbox.isInside(v):
+ return 0
+
+ if self.anyXY(v.x, v.y) and self.anyYZ(v.y, v.z) and self.anyZX(v.z, v.x):
+ return 1.0
+ else:
+ return 0
+
+ def anyXY(self, x, y):
+ for t in self.triangles:
+ if t.isInsideXY(Vector2(x, y)):
+ return True
+ return False
+
+ def anyYZ(self, y, z):
+ for t in self.triangles:
+ if t.isInsideYZ(Vector2(y, z)):
+ return True
+ return False
+
+ def anyZX(self, z, x):
+ for t in self.triangles:
+ if t.isInsideZX(Vector2(z, x)):
+ return True
+ return False
+
+
+def create_bone_weight(scene, mqo, armature_object, objects):
+ """
+ create mikoto bone weight.
+ """
+ anchorMap={}
+ # setup mikoto anchors
+ for o in mqo.objects:
+ if o.name.startswith("anchor"):
+ for f in o.faces:
+ name=mqo.materials[f.material_index].name
+ if name.endswith('[]'):
+ basename=name[0:-2]
+ v=o.vertices[f.indices[0]]
+ if(v.x>0):
+ # L
+ name_L=basename+'_L'
+ if not name_L in anchorMap:
+ anchorMap[name_L]=MikotoAnchor()
+ anchorMap[name_L].push(f, o.vertices)
+ elif(v.x<0):
+ # R
+ name_R=basename+'_R'
+ if not name_R in anchorMap:
+ anchorMap[name_R]=MikotoAnchor()
+ anchorMap[name_R].push(f, o.vertices)
+ else:
+ print("no side", v)
+ else:
+ if not name in anchorMap:
+ anchorMap[name]=MikotoAnchor()
+ anchorMap[name].push(f, o.vertices)
+
+ for o in objects:
+ # add armature modifier
+ mod=o.modifiers.append(Modifier.Types.ARMATURE)
+ mod[Modifier.Settings.OBJECT] = armature_object
+ mod[Modifier.Settings.ENVELOPES] = False
+ o.makeDisplayList()
+ # create vertex group
+ mesh=o.getData(mesh=True)
+ for name in anchorMap.keys():
+ mesh.addVertGroup(name)
+ mesh.update()
+
+ # assing vertices to vertex group
+ for o in objects:
+ mesh=o.getData(mesh=True)
+ for i, mvert in enumerate(mesh.verts):
+ hasWeight=False
+ for name, anchor in anchorMap.items():
+ weight=anchor.calcWeight(mvert.co)
+ if weight>0:
+ mesh.assignVertsToGroup(
+ name, [i], weight, Mesh.AssignModes.ADD)
+ hasWeight=True
+ if not hasWeight:
+ # debug orphan vertex
+ print('orphan', mvert)
+ mesh.update()
+
+###############################################################################
def createEmptyObject(scene, name):
empty=scene.objects.new("Empty")
empty.setName(name)
return empty
-def createMaterial(m):
+
+def createMqoMaterial(m):
material = Blender.Material.New(m.getName().encode(INTERNAL_ENCODING))
material.mode |= Blender.Material.Modes.SHADELESS
material.rgbCol = [m.color.r, m.color.g, m.color.b]
material.hard = int(255 * m.power)
return material
+def createPmdMaterial(m):
+ material=Blender.Material.New()
+ material.setDiffuseShader(Blender.Material.Shaders.DIFFUSE_TOON)
+ material.setRef(1)
+ material.diffuseSize = 3.14/2
+ material.setDiffuseSmooth(0)
+ material.setSpecShader(Blender.Material.Shaders.SPEC_TOON)
+ material.setSpecSize(0)
+ material.setSpec(0)
+ material.setRGBCol([m.diffuse.r, m.diffuse.g, m.diffuse.b])
+ material.setAlpha(m.diffuse.a)
+ material.setSpec(m.shinness*0.1)
+ material.setSpecCol([m.specular.r, m.specular.g, m.specular.b])
+ material.setMirCol([m.ambient.r, m.ambient.g, m.ambient.b])
+ material.enableSSS=True if m.flag==1 else False
+ return material
+
def createTexture(path):
image = Blender.Image.Load(path.encode(INTERNAL_ENCODING))
texture = Blender.Texture.New(path.encode(INTERNAL_ENCODING))
material.mode = material.mode | Blender.Material.Modes.TEXFACE
material.setTexture(0, texture, Blender.Texture.TexCo.UV)
+
+def createMesh(scene, name):
+ mesh = Blender.Mesh.New()
+ mesh_object=scene.objects.new(mesh, name.encode(INTERNAL_ENCODING))
+ return mesh, mesh_object
+
+
+def objectMakeParent(parent, child):
+ parent.makeParent([child])
+
+
+def meshAddMaterial(mesh, material):
+ mesh.materials+=[material]
+
+
+def meshAddMqoGeometry(mesh, o, materials, imageMap, scale):
+ # add vertices
+ mesh.verts.extend(Mathutils.Vector(0, 0, 0)) # dummy
+ mesh.verts.extend([(v.x, -v.z, v.y) for v in o.vertices])
+ # add faces
+ mesh_faces=[]
+ for face in o.faces:
+ face_indices=[]
+ for i in xrange(face.index_count):
+ face_indices.append(face.getIndex(i)+1)
+ mesh_faces.append(face_indices)
+ #new_faces=mesh.faces.extend([face.indices for face in o.faces],
+ new_faces=mesh.faces.extend(mesh_faces,
+ #ignoreDups=True,
+ indexList=True)
+ mesh.update()
+
+ # gather used materials
+ materialMap = {}
+ if new_faces:
+ for i in new_faces:
+ if type(i) is int:
+ materialMap[o.faces[i].material_index]=True
+
+ # blender limits 16 materials per mesh
+ # separate mesh ?
+ for i, material_index in enumerate(materialMap.keys()):
+ if i>=16:
+ print("over 16 materials!")
+ break
+ mesh.materials+=[materials[material_index]]
+ materialMap[material_index]=i
+
+ # set face params
+ for i, f in enumerate(o.faces):
+ if not type(new_faces[i]) is int:
+ continue
+
+ face=mesh.faces[new_faces[i]]
+
+ uv_array=[]
+ for i in xrange(f.index_count):
+ uv_array.append(Blender.Mathutils.Vector(
+ f.getUV(i).x,
+ 1.0-f.getUV(i).y)
+ )
+ try:
+ face.uv=uv_array
+ except Exception as msg:
+ #print msg
+ #print face.index, uv_array
+ pass
+
+ if f.material_index in materialMap:
+ face.mat = materialMap[f.material_index]
+
+ face.smooth = 1
+
+ # rmeove dummy 0 vertex
+ mesh.verts.delete(0)
+
+ mesh.mode |= Blender.Mesh.Modes.AUTOSMOOTH
+ mesh.maxSmoothAngle = int(o.smoothing)
+ mesh.smooth()
+ mesh.calcNormals()
+ mesh.flipNormals()
+ mesh.update()
+
+ # mirror modifier
+ if o.mirror:
+ mod=mesh_object.modifiers.append(Blender.Modifier.Types.MIRROR)
+
+def getTexture(m, dirname):
+ tex=""
+ aplane=""
+ # texture
+ for texture in m.getTextures():
+ if texture and texture.tex and texture.tex.getImage():
+ image=texture.tex.getImage()
+ if not image:
+ continue
+ imagePath=Blender.sys.expandpath(image.getFilename())
+ if len(dirname)>0 and imagePath.startswith(dirname):
+ # 相対パスに変換する
+ imagePath=imagePath[len(dirname)+1:len(imagePath)]
+ if texture.mtCol>0:
+ tex=" tex(\"%s\")" % imagePath
+ elif texture.mtAlpha>0:
+ aplane=" aplane(\"%s\")" % imagePath
+ return tex, aplane
+
+def objectDuplicate(scene, obj):
+ mesh, dumy=createMesh(scene, obj.name.decode(INTERNAL_ENCODING))
+ # not apply modifiers
+ mesh.getFromObject(obj.name, 1)
+ # apply matrix
+ dumy.setMatrix(obj.matrixWorld)
+ return mesh, dumy
+
+def objectDelete(scene, obj):
+ scene.objects.unlink(obj)
+
+def faceVertexCount(face):
+ return len(face.v)
+
+def faceVertices(face):
+ # flip
+ return [v.index for v in reversed(face.v)]
+
+def meshHasUV(mesh):
+ return mesh.faceUV
+
+def faceHasUV(mesh, i, face):
+ return len(face.uv)>0
+
+def faceGetUV(mesh, i, face, count):
+ # flip
+ return reversed(face.uv)
+
+def materialToMqo(m):
+ return "\"%s\" shader(3) col(%f %f %f %f)" % (
+ m.name, m.rgbCol[0], m.rgbCol[1], m.rgbCol[2], m.alpha)
+
+def faceMaterialIndex(face):
+ return face.mat
+
+def objectGetData(o):
+ return o.getData(mesh=True)
+
+def objectAddArmatureModifier(o, armature_object):
+ mod=o.modifiers.append(Blender.Modifier.Types.ARMATURE)
+ mod[Blender.Modifier.Settings.OBJECT] = armature_object
+ mod[Blender.Modifier.Settings.ENVELOPES] = False
+
+def objectSelect(o):
+ o.select(True)
+
+def objectGetPose(o):
+ return o.getPose()
+
+def poseBoneLimit(n, b):
+ if n.endswith("_t"):
+ return
+ if n.startswith("knee_"):
+ b.lockYRot=True
+ b.lockZRot=True
+ b.limitX=True
+ b.limitMin=[0, 0, 0]
+ b.limitMax=[180, 0, 0]
+ elif n.startswith("ankle_"):
+ b.lockYRot=True
+
+def enterEditMode():
+ Blender.Window.EditMode(1)
+
+def exitEditMode():
+ Blender.Window.EditMode(0)
+
+def objectDeselectAll():
+ for o in bpy.data.scenes.active.objects:
+ o.select(False)
+
+def objectActivate(scene, o):
+ o.select(True )
+ scene.objects.active=o
+
+def meshAddVertexGroup(meshObject, name):
+ meshObject.getData(mesh=True).addVertGroup(name)
+
+def meshUseVertexUv(mesh):
+ mesh.vertexUV = 1
+
+def vertexSetNormal(mvert, normal):
+ mvert.no=Mathutils.Vector(*normal)
+
+def vertexSetUv(mvert, uv):
+ mvert.uvco=uv
+
+def meshAssignVertexGroup(meshObject, name, index, weight):
+ meshObject.getData(mesh=True).assignVertsToGroup(name,
+ [index], weight, Blender.Mesh.AssignModes.ADD)
+
+def meshCreateVerteicesAndFaces(mesh, vertices, faces):
+ mesh.verts.extend(vertices)
+ mesh.faces.extend(faces, ignoreDups=True)
+
+def meshAddUV(mesh):
+ mesh.addUVLayer('NewUV')
+
+def meshVertsDelete(mesh, remove_vertices):
+ mesh.verts.delete(remove_vertices)
+
+def createArmature(scene):
+ armature = Blender.Armature.New()
+ armature_object = scene.objects.new(armature)
+
+ # set XRAY
+ armature_object.drawMode = (
+ armature_object.drawMode | Blender.Object.DrawModes.XRAY)
+ # armature settings
+ armature.drawType = Blender.Armature.OCTAHEDRON
+ armature.drawNames=True
+ armature.envelopes = False
+ armature.vertexGroups = True
+ armature.mirrorEdit = True
+
+ return armature, armature_object
+
+def armatureMakeEditable(scene, armature_object):
+ # create armature
+ armature_object.getData().makeEditable()
+
+def createIkConstraint(armature_object, p_bone, effector_name, ik):
+ cSetting = Blender.Constraint.Settings
+ # IK solver
+ constraint = p_bone.constraints.append(Blender.Constraint.Type.IKSOLVER)
+ constraint[cSetting.CHAINLEN]=len(ik.children)
+ constraint[cSetting.TARGET]=armature_object
+ constraint[cSetting.USETIP]=False
+ constraint[cSetting.BONE]=effector_name
+ # not used. place folder when export.
+ constraint[cSetting.ROTWEIGHT]=ik.weight
+ constraint[cSetting.ITERATIONS]=ik.iterations * 10
+ return constraint
+
+def createArmatureBone(armature, name):
+ bone=Blender.Armature.Editbone()
+ bone.name=name.encode(INTERNAL_ENCODING)
+ armature.bones[name]=bone
+ return bone
+
+def boneSetConnected(bone):
+ bone.options+=[Blender.Armature.CONNECTED]
+
+def createVector(x, y, z):
+ return Mathutils.Vector(x, y, z)
+
+def armatureUpdate(armature):
+ armature.update()
+
+def boneLayerMask(bone, layers):
+ mask=0
+ for i, enable in enumerate(layers):
+ if enable!=0:
+ mask+=(1<<i)
+ bone.layerMask=mask
+
+def objectPinShape(o):
+ o.pinShape=True
+
+def objectAddShapeKey(o, name):
+ mesh=o.getData(mesh=True)
+ mesh.insertKey()
+ block=mesh.key.blocks[-1]
+ block.name=name.encode(INTERNAL_ENCODING)
+ return block
+
+def objectActivateShapeKey(o, index):
+ o.activeShape=index
+
+def shapeKeyAssign(shapeKey, index, pos):
+ shapeKey.data[index]=pos
+
+def objectIsVisible(obj):
+ return obj.restrictDisplay
+
+def meshVertexGroupNames(meshObject):
+ return meshObject.getData(mesh=True).getVertGroupNames()
+
+def faceNormal(face):
+ return face.no
+
+def meshFaceUv(mesh, i, face):
+ return face.uv
+
+def armatureModifierGetObject(m):
+ return m[Blender.Modifier.Settings.OBJECT]
+
+def objectHasShapeKey(o):
+ return o.getData(mesh=True).key
+
+def objectShapeKeys(o):
+ return o.getData(mesh=True).key.blocks
+
+def meshVertexGroup(meshObject, name):
+ indices=[]
+ for index in meshObject.getData(mesh=True).getVertsFromGroup(name):
+ indices.append(index)
+ return indices
+
+def materialGet(scene, material_name):
+ return Blender.Material.Get(material_name)
+
+def modifierIsArmature(m):
+ return m.name=="Armature"
+
+def boneHeadLocal(b):
+ return b.head['ARMATURESPACE'][0:3]
+
+def boneTailLocal(b):
+ return b.tail['ARMATURESPACE'][0:3]
+
+def boneIsConnected(b):
+ return Blender.Armature.CONNECTED in b.options
+
+def constraintIsIKSolver(c):
+ return c.type==Blender.Constraint.Type.IKSOLVER
+
+def ikChainLen(c):
+ return c[Blender.Constraint.Settings.CHAINLEN]
+
+def ikTarget(c):
+ return c[Blender.Constraint.Settings.BONE]
+
+def ikItration(c):
+ return c[Blender.Constraint.Settings.ITERATIONS]
+
+def ikRotationWeight(c):
+ return c[Blender.Constraint.Settings.ROTWEIGHT]
+
+def shapeKeyGet(b, index):
+ return b.data[index]
+
+def shapeKeys(b):
+ return b.data
+