OSDN Git Service

fix.
[meshio/meshio.git] / swig / blender / bl24.py
index a9ee110..a1a5133 100644 (file)
 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]
@@ -26,6 +466,23 @@ def createMaterial(m):
     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))
@@ -37,3 +494,344 @@ def materialAddTexture(material, texture):
     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
+