OSDN Git Service

implement pmd_export texture.
[meshio/meshio.git] / swig / blender / bl24.py
old mode 100644 (file)
new mode 100755 (executable)
index 1819ac2..5d4fceb
@@ -1,10 +1,13 @@
 # coding: utf-8
 import sys
 import os
-import Blender
-from Blender import Mathutils
-import bpy
 
+try:
+    import Blender
+    from Blender import Mathutils
+    import bpy
+except:
+    pass
 
 # ファイルシステムの文字コード
 # 改造版との共用のため
@@ -14,12 +17,50 @@ if os.path.exists(os.path.dirname(sys.argv[0])+"/utf8"):
 else:
     INTERNAL_ENCODING=FS_ENCODING
 
+SCENE=None
+def initialize(name, scene):
+    global SCENE
+    SCENE=scene
+    progress_start(name)
+    # set object mode
+    mode_edit = Blender.Window.EditMode() 
+    if mode_edit: 
+        Blender.Window.EditMode(0)
+
+def finalize():
+    scene.update(SCENE)
+    progress_finish()
+    # restore edit mode
+    #if mode_edit: 
+    #    Blender.Window.EditMode(1)
+
+def message(msg):
+    res=Blender.Draw.PupMenu(msg + "%t|OK")
+    print(res)
+
+def enterEditMode():
+    Blender.Window.EditMode(1)
+
+def exitEditMode():
+    Blender.Window.EditMode(0)
+
+def createVector(x, y, z):
+    return Mathutils.Vector(x, y, z)
+
 
-###############################################################################
-# Writer
-###############################################################################
 class Writer(object):
+    '''
+    io wrapper
+    '''
+    __slots__=[
+            'io', 'encoding',
+            ]
     def __init__(self, path, encoding):
+        '''
+        path: file path to open
+        encoding: text encoding to write
+
+        '''
         self.io=open(path, "wb")
         self.encoding=encoding
 
@@ -33,15 +74,17 @@ class Writer(object):
         self.io.close()
 
 
-###############################################################################
-# ProgressBar
-###############################################################################
 class ProgressBar(object):
+    '''
+    progress bar wrapper
+    '''
+    __slots__=['base', 'start', 'progress',]
     def __init__(self, base):
         print("#### %s ####" % base)
         self.base=base
         self.start=Blender.sys.time() 
         self.set('<start>', 0)
+        Blender.Window.WaitCursor(1) 
 
     def advance(self, message, progress):
         self.progress+=float(progress)
@@ -62,742 +105,428 @@ class ProgressBar(object):
         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:
+        Blender.Window.WaitCursor(0) 
+        Blender.Redraw()
+
+def progress_start(base):
+    global progressBar
+    progressBar=ProgressBar(base)
+
+def progress_finish():
+    global progressBar
+    progressBar.finish()
+
+def progress_print(message, progress=0.05):
+    global progressBar
+    progressBar.advance(message, progress)
+
+def progress_set(message, progress):
+    global progressBar
+    progressBar.set(message, progress)
+
+
+class scene:
+    @staticmethod
+    def update(scene):
+        scene.update(0)
+
+
+class object:
+    @staticmethod
+    def createEmpty(name):
+        global SCENE
+        empty=SCENE.objects.new("Empty")
+        empty.setName(name)
+        return empty
+
+    @staticmethod
+    def makeParent(parent, child):
+        parent.makeParent([child])
+
+    @staticmethod
+    def duplicate(o):
+        new_mesh, new_object=mesh.create(o.name.decode(INTERNAL_ENCODING))
+        # not apply modifiers
+        new_mesh.getFromObject(o.name, 1)
+        # apply matrix
+        #o.setMatrix(o.matrixWorld)
+        return new_mesh, new_object
+
+    @staticmethod
+    def delete(o):
+        global SCENE
+        SCENE.objects.unlink(o)
+
+    @staticmethod
+    def getData(o):
+        return o.getData(mesh=True)
+
+    @staticmethod
+    def select(o):
+        o.select(True)
+
+    @staticmethod
+    def activate(o):
+        global SCENE
+        o.select(True )
+        SCENE.objects.active=o
+
+    @staticmethod
+    def getActive():
+        global SCENE
+        return SCENE.objects.active
+
+    @staticmethod
+    def deselectAll():
+        for o in bpy.data.scenes.active.objects:
+            o.select(False)
+
+    @staticmethod
+    def setLayerMask(o, layers):
+        mask=0
+        for i, enable in enumerate(layers):
+            if enable!=0:
+                mask+=(1<<i)
+        o.Layers=mask
+
+    @staticmethod
+    def isVisible(o):
+        return o.restrictDisplay
+
+    @staticmethod
+    def getShapeKeys(o):
+        return o.getData(mesh=True).key.blocks
+
+    @staticmethod
+    def addShapeKey(o, name):
         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 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.alpha = m.color.a
-    material.amb = m.ambient
-    material.spec = m.specular
-    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))
-    texture.type = Blender.Texture.Types.IMAGE
-    texture.image = image
-    return texture, image
-
-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
-    #ik_solver.influence=ik.weight
-    # 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):
-    for index in meshObject.getData(mesh=True).getVertsFromGroup(name):
-        yield index
+        mesh.insertKey()
+        block=mesh.key.blocks[-1]
+        block.name=name.encode(INTERNAL_ENCODING)
+        return block
+
+    @staticmethod
+    def hasShapeKey(o):
+        return o.getData(mesh=True).key
+
+    @staticmethod
+    def pinShape(o, enable):
+        o.pinShape=enable
+
+    @staticmethod
+    def setActivateShapeKey(o, index):
+        o.activeShape=index
+
+    @staticmethod
+    def getPose(o):
+        return o.getPose()
+
+    @staticmethod
+    def addVertexGroup(o, name):
+        o.getData(mesh=True).addVertGroup(name)
+
+    @staticmethod
+    def assignVertexGroup(o, name, index, weight):
+        o.getData(mesh=True).assignVertsToGroup(name, 
+                [index], weight, Blender.Mesh.AssignModes.ADD)
+
+    @staticmethod
+    def getVertexGroupNames(o):
+        return o.getData(mesh=True).getVertGroupNames()
+
+    @staticmethod
+    def getVertexGroup(o, name):
+        indices=[]
+        for index in o.getData(mesh=True).getVertsFromGroup(name):
+            indices.append(index)
+        return indices
+
+
+class modifier:
+    @staticmethod
+    def addMirror(mesh_object):
+        return mesh_object.modifiers.append(Blender.Modifier.Types.MIRROR)
+
+    @staticmethod
+    def addArmature(mesh_object, armature_object):
+        mod=mesh_object.modifiers.append(Blender.Modifier.Types.ARMATURE)
+        mod[Blender.Modifier.Settings.OBJECT] = armature_object
+        mod[Blender.Modifier.Settings.ENVELOPES] = False
+
+    @staticmethod
+    def hasType(mesh_object, type_name):
+        for mod in mesh_object.modifiers:
+                if mod.name.upper()==type_name.upper():
+                    return True
+
+    @staticmethod
+    def isType(m, type_name):
+        return m.name.upper()==type_name.upper()
+
+    @staticmethod
+    def getArmatureObject(m):
+        return m[Blender.Modifier.Settings.OBJECT]
+
+
+class shapekey:
+    @staticmethod
+    def assign(b, index, pos):
+        b.data[index]=pos
+
+    @staticmethod
+    def getByIndex(b, index):
+        return b.data[index]
+
+    @staticmethod
+    def get(b):
+        return b.data
+
+
+class texture:
+    @staticmethod
+    def create(path):
+        image = Blender.Image.Load(path.encode(INTERNAL_ENCODING))
+        texture = Blender.Texture.New(path.encode(INTERNAL_ENCODING))
+        texture.type = Blender.Texture.Types.IMAGE
+        texture.image = image
+        texture.imageFlags|=Blender.Texture.ImageFlags.USEALPHA
+        return texture, image
+
+
+class material:
+    @staticmethod
+    def create(name):
+        m = Blender.Material.New(name)
+        return m
+
+    @staticmethod
+    def get(material_name):
+        return Blender.Material.Get(material_name)
+
+    @staticmethod
+    def addTexture(material, texture):
+        material.mode = material.mode | Blender.Material.Modes.TEXFACE
+        material.setTexture(0, texture, Blender.Texture.TexCo.UV)
+
+    @staticmethod
+    def hasTexture(material):
+        return len(material.getTextures())>0
+
+    @staticmethod
+    def eachTexturePath(m, dirname):
+        for texture in m.getTextures():
+            if texture and texture.tex and texture.tex.getImage():
+                image=texture.tex.getImage()
+                if not image:
+                    continue
+                yield image.getFilename()
+
+
+class mesh:
+    @staticmethod
+    def create(name):
+        global SCENE
+        m=Blender.Mesh.New()
+        o=SCENE.objects.new(m, name.encode(INTERNAL_ENCODING))
+        return m, o
+
+    @staticmethod
+    def addGeometry(m, vertices, faces):
+        m.verts.extend(vertices)
+        new_faces=m.faces.extend(faces,
+                #ignoreDups=True, 
+                indexList=True)
+        m.update()
+
+    @staticmethod
+    def hasUV(m):
+        return m.faceUV
+
+    @staticmethod
+    def useVertexUV(m):
+        m.vertexUV = 1
+
+    @staticmethod
+    def addUV(m):
+        m.addUVLayer('NewUV')
+
+    @staticmethod
+    def hasFaceUV(m, i, face):
+        return len(face.uv)>0
+
+    @staticmethod
+    def getFaceUV(m, i, face, count=3):
+        return face.uv
+
+    @staticmethod
+    def setFaceUV(m, i, face, uv_array, image):
+        face.uv=[Mathutils.Vector(uv[0], uv[1]) for uv in  uv_array]
+        if image:
+            face.image=image
+
+    @staticmethod
+    def vertsDelete(m, remove_vertices):
+        m.verts.delete(remove_vertices)
+
+    @staticmethod
+    def setSmooth(m, smoothing):
+        m.mode |= Blender.Mesh.Modes.AUTOSMOOTH
+        m.degr=int(smoothing)
+        #m.smooth()
+
+    @staticmethod
+    def recalcNormals(mesh_object):
+        m=mesh_object.getData(mesh=True)
+        m.calcNormals() 
+
+    @staticmethod
+    def flipNormals(m):
+        m.flipNormals()
+
+    @staticmethod
+    def addMaterial(m, material):
+        m.materials+=[material]
+
+
+class vertex:
+    @staticmethod
+    def setNormal(mvert, normal):
+        mvert.no=Mathutils.Vector(*normal)
+
+    @staticmethod
+    def setUv(mvert, uv):
+        mvert.uvco=uv
+
+
+class face:
+    @staticmethod
+    def getVertexCount(face):
+        return len(face.v)
+
+    @staticmethod
+    def getVertices(face):
+        return [v.index for v in face.v]
+
+    @staticmethod
+    def getIndices(face):
+        return [face.verts[0].index, face.verts[1].index, face.verts[2].index]
+
+    @staticmethod
+    def setMaterial(face, material_index):
+        face.mat=material_index
+
+    @staticmethod
+    def getMaterialIndex(face):
+        return face.mat
+
+    @staticmethod
+    def setNormal(face, normal):
+        face.no=normal
+
+    @staticmethod
+    def getNormal(face):
+        return face.no
+
+    @staticmethod
+    def setSmooth(face, isSmooth):
+        face.smooth=1 if isSmooth else 0
+     
+
+class armature:
+    @staticmethod
+    def create():
+        global 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
+
+    @staticmethod
+    def makeEditable(armature_object):
+        # create armature
+        armature_object.getData().makeEditable()
+
+    @staticmethod
+    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
+
+    @staticmethod
+    def createBone(armature_object, name):
+        bone=Blender.Armature.Editbone()
+        bone.name=name.encode(INTERNAL_ENCODING)
+        armature_object.bones[name]=bone
+        return bone
+
+    @staticmethod
+    def update(armature):
+        armature.update()
+
+
+class bone:
+    @staticmethod
+    def setConnected(bone):
+        bone.options+=[Blender.Armature.CONNECTED]
+
+    @staticmethod
+    def isConnected(b):
+        return Blender.Armature.CONNECTED in b.options
+
+    @staticmethod
+    def setLayerMask(bone, layers):
+        mask=0
+        for i, enable in enumerate(layers):
+            if enable!=0:
+                mask+=(1<<i)
+        bone.layerMask=mask
+
+    @staticmethod
+    def getHeadLocal(b):
+        return b.head['ARMATURESPACE'][0:3]
+
+    @staticmethod
+    def getTailLocal(b):
+        return b.tail['ARMATURESPACE'][0:3]
+
+
+class constraint:
+    @staticmethod
+    def ikChainLen(c):
+        return c[Blender.Constraint.Settings.CHAINLEN]
+
+    @staticmethod
+    def ikTarget(c):
+        return c[Blender.Constraint.Settings.BONE]
+
+    @staticmethod
+    def ikItration(c):
+        return c[Blender.Constraint.Settings.ITERATIONS]
+
+    @staticmethod
+    def ikRotationWeight(c):
+        return c[Blender.Constraint.Settings.ROTWEIGHT]
+
+    @staticmethod
+    def isIKSolver(c):
+        return c.type==Blender.Constraint.Type.IKSOLVER
 
-def materialGet(scene, material_name):
-    return Blender.Material.Get(material_name)