OSDN Git Service

implement mqo_import.py.
authorousttrue <ousttrue@gmail.com>
Sun, 6 Jun 2010 06:33:50 +0000 (15:33 +0900)
committerousttrue <ousttrue@gmail.com>
Sun, 6 Jun 2010 06:33:50 +0000 (15:33 +0900)
swig/blender/bl24.py
swig/blender/bl25.py
swig/blender/mqo_import.py

index a9ee110..fb180c1 100644 (file)
@@ -2,6 +2,8 @@
 import sys
 import os
 import Blender
+from Blender import Mathutils
+
 
 # \e$B%U%!%$%k%7%9%F%`$NJ8;z%3!<%I\e(B
 # \e$B2~B$HG$H$N6&MQ$N$?$a\e(B
@@ -11,12 +13,14 @@ if os.path.exists(os.path.dirname(sys.argv[0])+"/utf8"):
 else:
     INTERNAL_ENCODING=FS_ENCODING
 
+
 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 +30,7 @@ def createMaterial(m):
     material.hard = int(255 * m.power)
     return material
 
+
 def createTexture(path):
     image = Blender.Image.Load(path.encode(INTERNAL_ENCODING))
     texture = Blender.Texture.New(path.encode(INTERNAL_ENCODING))
@@ -33,7 +38,476 @@ def createTexture(path):
     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 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)
+
+###############################################################################
+# 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\e$BJ}<0%\!<%s$N%"%s%+!<%&%'%$%H7W;;MQ!#\e(B
+    (\e$BIT40A4\e(B)
+    """
+    __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\e$BJ}<0%9%1%k%H%s$N%"%s%+!<!#\e(B
+    """
+    __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()
+
index b8a1a50..e344c8e 100644 (file)
@@ -1,12 +1,14 @@
 import bpy
 import os
 
+
 def createEmptyObject(scene, name):
     empty=bpy.data.objects.new(name, None)
     scene.objects.link(empty)
     return empty
 
-def createMaterial(m):
+
+def createMqoMaterial(m):
     material = bpy.data.materials.new(m.getName())
     material.diffuse_color=[m.color.r, m.color.g, m.color.b]
     material.alpha=m.color.a
@@ -15,6 +17,7 @@ def createMaterial(m):
     material.emit=1.0
     return material
 
+
 def createTexture(path):
     texture=bpy.data.textures.new(os.path.basename(path))
     texture.type='IMAGE'
@@ -26,7 +29,101 @@ def createTexture(path):
     texture.use_alpha = True
     return texture, image
 
+
 def materialAddTexture(material, texture):
     #material.add_texture(texture, "UV", {"COLOR", "ALPHA"})
     material.add_texture(texture, "UV", "COLOR")
 
+
+def createMesh(scene, name):
+    mesh=bpy.data.meshes.new("Mesh")
+    mesh_object= bpy.data.objects.new(name, mesh)
+    scene.objects.link(mesh_object)
+    return mesh, mesh_object
+
+
+def objectMakeParent(parent, child):
+    child.parent=parent
+
+
+def meshAddMqoGeometry(mesh, o, materials, imageMap, scale):
+    # count triangle and quadrangle
+    faceCount=0
+    for f in o.faces:
+        if f.index_count==3 or f.index_count==4:
+            faceCount+=1
+    mesh.add_geometry(len(o.vertices), 0, faceCount)
+
+    # add vertex
+    unpackedVertices=[]
+    for v in o.vertices:
+        # convert right-handed y-up to right-handed z-up
+        unpackedVertices.extend(
+                (scale*v.x, scale*-v.z, scale*v.y))
+    mesh.verts.foreach_set("co", unpackedVertices)
+
+    # add face
+    unpackedFaces = []
+    usedMaterial=set()
+
+    def getFace(f):
+        face = []
+        for i in range(f.index_count):
+            face.append(f.getIndex(i))
+        return face
+
+    for f in o.faces:
+        face=getFace(f)
+        if len(face) != 3 and len(face) != 4:
+            print("{0} vertices in face.".format(len(face)))
+            continue
+
+        if len(face) == 4:
+            if face[3] == 0:
+                # rotate indices if the 4th is 0
+                face = [face[3], face[0], face[1], face[2]]
+        elif len(face) == 3:
+            if face[2] == 0:
+                # rotate indices if the 3rd is 0
+                face = [face[2], face[0], face[1], 0]
+            else:
+                face.append(0)
+
+        unpackedFaces.extend(face)
+        usedMaterial.add(f.material_index)
+    try:
+        mesh.faces.foreach_set("verts_raw", unpackedFaces)
+    except:
+        #print([getFace(f) for f in o.faces])
+        print("fail to mesh.faces.foreach_set")
+        return
+
+    # add material
+    meshMaterialMap={}
+    materialIndex=0
+    for i in usedMaterial:
+        mesh.add_material(materials[i])
+        meshMaterialMap[i]=materialIndex
+        materialIndex+=1
+
+    # each face
+    mesh.add_uv_texture()
+    for mqo_face, blender_face, uv_face in zip(
+            o.faces, mesh.faces, mesh.uv_textures[0].data):
+        if mqo_face.index_count<3:
+            continue
+        blender_face.material_index=meshMaterialMap[mqo_face.material_index]
+        if mqo_face.index_count>=3:
+            uv_face.uv1=[mqo_face.getUV(0).x, 1.0-mqo_face.getUV(0).y]
+            uv_face.uv2=[mqo_face.getUV(1).x, 1.0-mqo_face.getUV(1).y]
+            uv_face.uv3=[mqo_face.getUV(2).x, 1.0-mqo_face.getUV(2).y]
+            if mqo_face.index_count==4:
+                uv_face.uv4=[
+                        mqo_face.getUV(3).x, 1.0-mqo_face.getUV(3).y]
+        if materials[mqo_face.material_index] in imageMap:
+            uv_face.image=imageMap[mqo_face.material_index]
+            uv_face.tex=True
+
+    mesh.update()
+
+
index 038ddf0..34334bd 100644 (file)
@@ -54,593 +54,9 @@ else:
     import bl25 as bl\r
 \r
 \r
-###############################################################################\r
-# implement\r
-###############################################################################\r
 def has_mikoto(mqo):\r
     return False\r
 \r
-if isBlender24():\r
-    def create_objects(scene, mqo, root, materials, imageMap=None, scale=None):\r
-        """\r
-        create blender mesh objects.\r
-        """\r
-        # store hierarchy\r
-        stack=[root]    \r
-\r
-        objects=[]\r
-        for o in mqo.objects:\r
-            #print "%s:v(%d),f(%d)" % (o.name, len(o.vertices), len(o.faces))\r
-            # create mesh\r
-            mesh = Blender.Mesh.New()\r
-            mesh_object=scene.objects.new(mesh, o.name.encode('utf-8'))\r
-\r
-            # add hierarchy\r
-            stack_depth=len(stack)-1\r
-            print(o.depth, stack_depth)\r
-            if o.depth<stack_depth:\r
-                for i in range(stack_depth-o.depth):\r
-                    stack.pop()\r
-            stack[-1].makeParent([mesh_object])\r
-            stack.append(mesh_object)\r
-\r
-            if o.name.startswith('sdef'):\r
-                # add sdef object\r
-                objects.append(mesh_object)\r
-            elif o.name.startswith('anchor'):\r
-                #print("hide %s" % o.name)\r
-                #mesh_object.restrictDisplay=False\r
-                mesh_object.layers=[2]\r
-            elif o.name.startswith('bone'):\r
-                mesh_object.layers=[2]\r
-\r
-            # add vertices\r
-            mesh.verts.extend(Mathutils.Vector(0, 0, 0)) # dummy\r
-            mesh.verts.extend([(v.x, -v.z, v.y) for v in o.vertices])\r
-            # add faces\r
-            mesh_faces=[]\r
-            for face in o.faces:\r
-                face_indices=[]\r
-                for i in xrange(face.index_count):\r
-                    face_indices.append(face.getIndex(i)+1)\r
-                mesh_faces.append(face_indices)\r
-            #new_faces=mesh.faces.extend([face.indices for face in o.faces], \r
-            new_faces=mesh.faces.extend(mesh_faces,\r
-                    #ignoreDups=True, \r
-                    indexList=True)\r
-            mesh.update()\r
-            \r
-            # gather used materials\r
-            usedMaterials = {}\r
-            if new_faces:\r
-                for i in new_faces:\r
-                    if type(i) is int:\r
-                        usedMaterials[o.faces[i].material_index]=True\r
-\r
-            # blender limits 16 materials per mesh\r
-            # separate mesh ?\r
-            for i, material_index in enumerate(usedMaterials.keys()):\r
-                if i>=16:\r
-                    print("over 16 materials!")\r
-                    break\r
-                mesh.materials+=[materials[material_index]]\r
-                usedMaterials[material_index]=i\r
-            \r
-            # set face params\r
-            for i, f in enumerate(o.faces):       \r
-                if not type(new_faces[i]) is int:\r
-                    continue\r
-\r
-                face=mesh.faces[new_faces[i]]\r
-\r
-                uv_array=[]\r
-                for i in xrange(f.index_count):\r
-                    uv_array.append(Blender.Mathutils.Vector(\r
-                        f.getUV(i).x, \r
-                        1.0-f.getUV(i).y)\r
-                        )\r
-                try:\r
-                    face.uv=uv_array\r
-                except Exception as msg:\r
-                    #print msg\r
-                    #print face.index, uv_array\r
-                    pass\r
-            \r
-                if f.material_index in usedMaterials:\r
-                    face.mat = usedMaterials[f.material_index]\r
-\r
-                face.smooth = 1\r
-\r
-            # rmeove dummy 0 vertex\r
-            mesh.verts.delete(0)\r
-                \r
-            mesh.mode |= Blender.Mesh.Modes.AUTOSMOOTH\r
-            mesh.maxSmoothAngle = int(o.smoothing)\r
-            mesh.smooth()\r
-            mesh.calcNormals()\r
-            mesh.flipNormals()\r
-            mesh.update()\r
-\r
-            # mirror modifier\r
-            if o.mirror:\r
-                mod=mesh_object.modifiers.append(Blender.Modifier.Types.MIRROR)\r
-\r
-        return objects\r
-\r
-\r
-    class MikotoBone(object):\r
-        __slots__=[\r
-                'name',\r
-                'iHead', 'iTail', 'iUp',\r
-                'vHead', 'vTail', 'vUp',\r
-                'parent', 'isFloating',\r
-                'children',\r
-                ]\r
-        def __init__(self, face=None, vertices=None, materials=None):\r
-            self.parent=None\r
-            self.isFloating=False\r
-            self.children=[]\r
-            if not face:\r
-                self.name='root'\r
-                return\r
-\r
-            self.name=materials[face.material_index].name.encode('utf-8')\r
-\r
-            i0=face.indices[0]\r
-            i1=face.indices[1]\r
-            i2=face.indices[2]\r
-            v0=vertices[i0]\r
-            v1=vertices[i1]\r
-            v2=vertices[i2]\r
-            e01=v1-v0\r
-            e12=v2-v1\r
-            e20=v0-v2\r
-            sqNorm0=e01.getSqNorm()\r
-            sqNorm1=e12.getSqNorm()\r
-            sqNorm2=e20.getSqNorm()\r
-            if sqNorm0>sqNorm1:\r
-                if sqNorm1>sqNorm2:\r
-                    # e01 > e12 > e20\r
-                    self.iHead=i2\r
-                    self.iTail=i1\r
-                    self.iUp=i0\r
-                else:\r
-                    if sqNorm0>sqNorm2:\r
-                        # e01 > e20 > e12\r
-                        self.iHead=i2\r
-                        self.iTail=i0\r
-                        self.iUp=i1\r
-                    else:\r
-                        # e20 > e01 > e12\r
-                        self.iHead=i1\r
-                        self.iTail=i0\r
-                        self.iUp=i2\r
-            else:\r
-                # 0 < 1\r
-                if sqNorm1<sqNorm2:\r
-                    # e20 > e12 > e01\r
-                    self.iHead=i1\r
-                    self.iTail=i2\r
-                    self.iUp=i0\r
-                else:\r
-                    if sqNorm0<sqNorm2:\r
-                        # e12 > e20 > e01\r
-                        self.iHead=i0\r
-                        self.iTail=i2\r
-                        self.iUp=i1\r
-                    else:\r
-                        # e12 > e01 > e20\r
-                        self.iHead=i0\r
-                        self.iTail=i1\r
-                        self.iUp=i2\r
-            self.vHead=vertices[self.iHead]\r
-            self.vTail=vertices[self.iTail]\r
-            self.vUp=vertices[self.iUp]\r
-\r
-            if self.name.endswith('[]'):\r
-                basename=self.name[0:-2]\r
-                # expand LR name\r
-                if self.vTail.x>0:\r
-                    self.name="%s_L" % basename\r
-                else:\r
-                    self.name="%s_R" % basename\r
-\r
-\r
-        def setParent(self, parent, floating=False):\r
-            if floating:\r
-                self.isFloating=True\r
-            self.parent=parent\r
-            parent.children.append(self)\r
-\r
-        def printTree(self, indent=''):\r
-            print("%s%s" % (indent, self.name))\r
-            for child in self.children:\r
-                child.printTree(indent+'  ')\r
-\r
-\r
-    def build_armature(armature, mikotoBone, parent=None):\r
-        """\r
-        create a armature bone.\r
-        """\r
-        bone = Armature.Editbone()\r
-        bone.name = mikotoBone.name.encode('utf-8')\r
-        armature.bones[bone.name] = bone\r
-\r
-        bone.head = Mathutils.Vector(*mikotoBone.vHead.to_a())\r
-        bone.tail = Mathutils.Vector(*mikotoBone.vTail.to_a())\r
-        if parent:\r
-            bone.parent=parent\r
-            if mikotoBone.isFloating:\r
-                pass\r
-            else:\r
-                bone.options=[Armature.CONNECTED]\r
-\r
-        for child in mikotoBone.children:\r
-            build_armature(armature, child, bone)\r
-\r
-\r
-    def create_armature(scene, mqo):\r
-        """\r
-        create armature\r
-        """\r
-        boneObject=None\r
-        for o in mqo.objects:\r
-            if o.name.startswith('bone'):\r
-                boneObject=o\r
-                break\r
-        if not boneObject:\r
-            return\r
-\r
-        tailMap={}\r
-        for f in boneObject.faces:\r
-            if f.index_count!=3:\r
-                print("invalid index_count: %d" % f.index_count)\r
-                continue\r
-            b=MikotoBone(f, boneObject.vertices, mqo.materials)\r
-            tailMap[b.iTail]=b\r
-\r
-        #################### \r
-        # build mikoto bone tree\r
-        #################### \r
-        mikotoRoot=MikotoBone()\r
-\r
-        for b in tailMap.values():\r
-            # each bone has unique parent or is root bone.\r
-            if b.iHead in tailMap:\r
-                b.setParent(tailMap[b.iHead])\r
-            else: \r
-                isFloating=False\r
-                for e in boneObject.edges:\r
-                    if  b.iHead==e.indices[0]:\r
-                        # floating bone\r
-                        if e.indices[1] in tailMap:\r
-                            b.setParent(tailMap[e.indices[1]], True)\r
-                            isFloating=True\r
-                            break\r
-                    elif b.iHead==e.indices[1]:\r
-                        # floating bone\r
-                        if e.indices[0] in tailMap:\r
-                            b.setParent(tailMap[e.indices[0]], True)\r
-                            isFloating=True\r
-                            break\r
-                if isFloating:\r
-                    continue\r
-\r
-                # no parent bone\r
-                b.setParent(mikotoRoot, True)\r
-\r
-        if len(mikotoRoot.children)==0:\r
-            print("no root bone")\r
-            return\r
-\r
-        if len(mikotoRoot.children)==1:\r
-            # single root\r
-            mikotoRoot=mikotoRoot.children[0]\r
-            mikotoRoot.parent=None\r
-        else:\r
-            mikotoRoot.vHead=Vector3(0, 10, 0)\r
-            mikotoRoot.vTail=Vector3(0, 0, 0)\r
-\r
-        #################### \r
-        # create armature\r
-        #################### \r
-        armature = Armature.New()\r
-        # link to object\r
-        armature_object = scene.objects.new(armature)\r
-        # create action\r
-        act = Armature.NLA.NewAction()\r
-        act.setActive(armature_object)\r
-        # set XRAY\r
-        armature_object.drawMode |= Object.DrawModes.XRAY\r
-        # armature settings\r
-        armature.drawType = Armature.OCTAHEDRON\r
-        armature.envelopes = False\r
-        armature.vertexGroups = True\r
-        armature.mirrorEdit = True\r
-        armature.drawNames=True\r
-\r
-        # edit bones\r
-        armature.makeEditable()\r
-        build_armature(armature, mikotoRoot)\r
-        armature.update()\r
-\r
-        return armature_object\r
-            \r
-\r
-    class TrianglePlane(object):\r
-        """\r
-        mikoto方式ボーンのアンカーウェイト計算用。\r
-        (不完全)\r
-        """\r
-        __slots__=['normal', \r
-                'v0', 'v1', 'v2',\r
-                ]\r
-        def __init__(self, v0, v1, v2):\r
-            self.v0=v0\r
-            self.v1=v1\r
-            self.v2=v2\r
-\r
-        def isInsideXY(self, p):\r
-            v0=Vector2(self.v0.x, self.v0.y)\r
-            v1=Vector2(self.v1.x, self.v1.y)\r
-            v2=Vector2(self.v2.x, self.v2.y)\r
-            e01=v1-v0\r
-            e12=v2-v1\r
-            e20=v0-v2\r
-            c0=Vector2.cross(e01, p-v0)\r
-            c1=Vector2.cross(e12, p-v1)\r
-            c2=Vector2.cross(e20, p-v2)\r
-            if c0>=0 and c1>=0 and c2>=0:\r
-                return True\r
-            if c0<=0 and c1<=0 and c2<=0:\r
-                return True\r
-\r
-        def isInsideYZ(self, p):\r
-            v0=Vector2(self.v0.y, self.v0.z)\r
-            v1=Vector2(self.v1.y, self.v1.z)\r
-            v2=Vector2(self.v2.y, self.v2.z)\r
-            e01=v1-v0\r
-            e12=v2-v1\r
-            e20=v0-v2\r
-            c0=Vector2.cross(e01, p-v0)\r
-            c1=Vector2.cross(e12, p-v1)\r
-            c2=Vector2.cross(e20, p-v2)\r
-            if c0>=0 and c1>=0 and c2>=0:\r
-                return True\r
-            if c0<=0 and c1<=0 and c2<=0:\r
-                return True\r
-\r
-        def isInsideZX(self, p):\r
-            v0=Vector2(self.v0.z, self.v0.x)\r
-            v1=Vector2(self.v1.z, self.v1.x)\r
-            v2=Vector2(self.v2.z, self.v2.x)\r
-            e01=v1-v0\r
-            e12=v2-v1\r
-            e20=v0-v2\r
-            c0=Vector2.cross(e01, p-v0)\r
-            c1=Vector2.cross(e12, p-v1)\r
-            c2=Vector2.cross(e20, p-v2)\r
-            if c0>=0 and c1>=0 and c2>=0:\r
-                return True\r
-            if c0<=0 and c1<=0 and c2<=0:\r
-                return True\r
-\r
-\r
-    class MikotoAnchor(object):\r
-        """\r
-        mikoto方式スケルトンのアンカー。\r
-        """\r
-        __slots__=[\r
-                "triangles", "bbox",\r
-                ]\r
-        def __init__(self):\r
-            self.triangles=[]\r
-            self.bbox=None\r
-\r
-        def push(self, face, vertices):\r
-            if face.index_count==3:\r
-                self.triangles.append(TrianglePlane(\r
-                    vertices[face.indices[0]],\r
-                    vertices[face.indices[1]],\r
-                    vertices[face.indices[2]]\r
-                    ))\r
-            elif face.index_count==4:\r
-                self.triangles.append(TrianglePlane(\r
-                    vertices[face.indices[0]],\r
-                    vertices[face.indices[1]],\r
-                    vertices[face.indices[2]]\r
-                    ))\r
-                self.triangles.append(TrianglePlane(\r
-                    vertices[face.indices[2]],\r
-                    vertices[face.indices[3]],\r
-                    vertices[face.indices[0]]\r
-                    ))\r
-            # bounding box\r
-            if not self.bbox:\r
-                self.bbox=BoundingBox(vertices[face.indices[0]])\r
-            for i in face.indices:\r
-                self.bbox.expand(vertices[i])\r
-\r
-\r
-        def calcWeight(self, v):\r
-            if not self.bbox.isInside(v):\r
-                return 0\r
-\r
-            if self.anyXY(v.x, v.y) and self.anyYZ(v.y, v.z) and self.anyZX(v.z, v.x):\r
-                return 1.0\r
-            else:\r
-                return 0\r
-            \r
-        def anyXY(self, x, y):\r
-            for t in self.triangles:\r
-                if t.isInsideXY(Vector2(x, y)):\r
-                    return True\r
-            return False\r
-\r
-        def anyYZ(self, y, z):\r
-            for t in self.triangles:\r
-                if t.isInsideYZ(Vector2(y, z)):\r
-                    return True\r
-            return False\r
-\r
-        def anyZX(self, z, x):\r
-            for t in self.triangles:\r
-                if t.isInsideZX(Vector2(z, x)):\r
-                    return True\r
-            return False\r
-\r
-\r
-    def create_bone_weight(scene, mqo, armature_object, objects):\r
-        """\r
-        create mikoto bone weight.\r
-        """\r
-        anchorMap={}\r
-        # setup mikoto anchors\r
-        for o in mqo.objects:\r
-            if o.name.startswith("anchor"):\r
-                for f in o.faces:\r
-                    name=mqo.materials[f.material_index].name\r
-                    if name.endswith('[]'):\r
-                        basename=name[0:-2]\r
-                        v=o.vertices[f.indices[0]]\r
-                        if(v.x>0):\r
-                            # L\r
-                            name_L=basename+'_L'\r
-                            if not name_L in anchorMap:\r
-                                anchorMap[name_L]=MikotoAnchor()\r
-                            anchorMap[name_L].push(f, o.vertices)\r
-                        elif(v.x<0):\r
-                            # R\r
-                            name_R=basename+'_R'\r
-                            if not name_R in anchorMap:\r
-                                anchorMap[name_R]=MikotoAnchor()\r
-                            anchorMap[name_R].push(f, o.vertices)\r
-                        else:\r
-                            print("no side", v)\r
-                    else:\r
-                        if not name in anchorMap:\r
-                            anchorMap[name]=MikotoAnchor()\r
-                        anchorMap[name].push(f, o.vertices)\r
-\r
-        for o in objects:\r
-            # add armature modifier\r
-            mod=o.modifiers.append(Modifier.Types.ARMATURE)\r
-            mod[Modifier.Settings.OBJECT] = armature_object\r
-            mod[Modifier.Settings.ENVELOPES] = False\r
-            o.makeDisplayList()\r
-            # create vertex group\r
-            mesh=o.getData(mesh=True)\r
-            for name in anchorMap.keys():\r
-                mesh.addVertGroup(name)\r
-            mesh.update()\r
-                     \r
-        # assing vertices to vertex group\r
-        for o in objects:\r
-            mesh=o.getData(mesh=True)\r
-            for i, mvert in enumerate(mesh.verts):\r
-                hasWeight=False\r
-                for name, anchor in anchorMap.items():\r
-                    weight=anchor.calcWeight(mvert.co)\r
-                    if weight>0:\r
-                        mesh.assignVertsToGroup(\r
-                                name, [i], weight, Mesh.AssignModes.ADD)\r
-                        hasWeight=True\r
-                if not hasWeight:\r
-                    # debug orphan vertex\r
-                    print('orphan', mvert)\r
-            mesh.update()\r
-        \r
-\r
-\r
-else:\r
-    def create_objects(scene, mqo, parent, materials, imageMap, scale):\r
-        for o in mqo.objects:\r
-\r
-            # create mesh\r
-            mesh=bpy.data.meshes.new("Mesh")\r
-            meshObject= bpy.data.objects.new(o.getName(), mesh)\r
-            scene.objects.link(meshObject)\r
-            meshObject.parent=parent\r
-\r
-            # count triangle and quadrangle\r
-            faceCount=0\r
-            for f in o.faces:\r
-                if f.index_count==3 or f.index_count==4:\r
-                    faceCount+=1\r
-            mesh.add_geometry(len(o.vertices), 0, faceCount)\r
-\r
-            # add vertex\r
-            unpackedVertices=[]\r
-            for v in o.vertices:\r
-                # convert right-handed y-up to right-handed z-up\r
-                unpackedVertices.extend(\r
-                        (scale*v.x, scale*-v.z, scale*v.y))\r
-            mesh.verts.foreach_set("co", unpackedVertices)\r
-\r
-            # add face\r
-            unpackedFaces = []\r
-            usedMaterial=set()\r
-\r
-            def getFace(f):\r
-                face = []\r
-                for i in range(f.index_count):\r
-                    face.append(f.getIndex(i))\r
-                return face\r
-\r
-            for f in o.faces:\r
-                face=getFace(f)\r
-                if len(face) != 3 and len(face) != 4:\r
-                    print("{0} vertices in face.".format(len(face)))\r
-                    continue\r
-\r
-                if len(face) == 4:\r
-                    if face[3] == 0:\r
-                        # rotate indices if the 4th is 0\r
-                        face = [face[3], face[0], face[1], face[2]]\r
-                elif len(face) == 3:\r
-                    if face[2] == 0:\r
-                        # rotate indices if the 3rd is 0\r
-                        face = [face[2], face[0], face[1], 0]\r
-                    else:\r
-                        face.append(0)\r
-\r
-                unpackedFaces.extend(face)\r
-                usedMaterial.add(f.material_index)\r
-            try:\r
-                mesh.faces.foreach_set("verts_raw", unpackedFaces)\r
-            except:\r
-                #print([getFace(f) for f in o.faces])\r
-                print("fail to mesh.faces.foreach_set")\r
-                return\r
-\r
-            # add material\r
-            meshMaterialMap={}\r
-            materialIndex=0\r
-            for i in usedMaterial:\r
-                mesh.add_material(materials[i])\r
-                meshMaterialMap[i]=materialIndex\r
-                materialIndex+=1\r
-\r
-            # each face\r
-            mesh.add_uv_texture()\r
-            for mqo_face, blender_face, uv_face in zip(\r
-                    o.faces, mesh.faces, mesh.uv_textures[0].data):\r
-                if mqo_face.index_count<3:\r
-                    continue\r
-                blender_face.material_index=meshMaterialMap[mqo_face.material_index]\r
-                if mqo_face.index_count>=3:\r
-                    uv_face.uv1=[mqo_face.getUV(0).x, 1.0-mqo_face.getUV(0).y]\r
-                    uv_face.uv2=[mqo_face.getUV(1).x, 1.0-mqo_face.getUV(1).y]\r
-                    uv_face.uv3=[mqo_face.getUV(2).x, 1.0-mqo_face.getUV(2).y]\r
-                    if mqo_face.index_count==4:\r
-                        uv_face.uv4=[\r
-                                mqo_face.getUV(3).x, 1.0-mqo_face.getUV(3).y]\r
-                if materials[mqo_face.material_index] in imageMap:\r
-                    uv_face.image=imageMap[mqo_face.material_index]\r
-                    uv_face.tex=True\r
-\r
-            mesh.update()\r
-\r
 \r
 def __createMaterials(scene, mqo, directory):\r
     """\r
@@ -652,7 +68,7 @@ def __createMaterials(scene, mqo, directory):
     if len(mqo.materials)>0:\r
         for material_index, m in enumerate(mqo.materials):\r
             # material\r
-            material=bl.createMaterial(m)\r
+            material=bl.createMqoMaterial(m)\r
             materials.append(material)\r
             # texture\r
             texture_name=m.getTexture()\r
@@ -683,6 +99,40 @@ def __createMaterials(scene, mqo, directory):
     return materials, imageMap\r
 \r
 \r
+def __createObjects(scene, mqo, root, materials, imageMap, scale=1.0):\r
+    """\r
+    create blender mesh objects.\r
+    """\r
+    # store hierarchy\r
+    stack=[root]    \r
+    objects=[]\r
+    for o in mqo.objects:\r
+        mesh, mesh_object=bl.createMesh(scene, o.getName())\r
+\r
+        # add hierarchy\r
+        stack_depth=len(stack)-1\r
+        print(o.depth, stack_depth)\r
+        if o.depth<stack_depth:\r
+            for i in range(stack_depth-o.depth):\r
+                stack.pop()\r
+        bl.objectMakeParent(stack[-1], mesh_object)\r
+        stack.append(mesh_object)\r
+\r
+        if o.name.startswith('sdef'):\r
+            # add sdef object\r
+            objects.append(mesh_object)\r
+        elif o.name.startswith('anchor'):\r
+            #print("hide %s" % o.name)\r
+            #mesh_object.restrictDisplay=False\r
+            mesh_object.layers=[2]\r
+        elif o.name.startswith('bone'):\r
+            mesh_object.layers=[2]\r
+\r
+        bl.meshAddMqoGeometry(mesh, o, materials, imageMap, scale)\r
+\r
+    return objects\r
+\r
+\r
 def __execute(filename, scene, scale=1.0):\r
     # parse file\r
     io=mqo.IO()\r
@@ -695,7 +145,7 @@ def __execute(filename, scene, scale=1.0):
 \r
     # create objects\r
     root=bl.createEmptyObject(scene, os.path.basename(filename))\r
-    objects=create_objects(scene, io, root, materials, imageMap, scale)\r
+    objects=__createObjects(scene, io, root, materials, imageMap, scale)\r
 \r
     if has_mikoto(io):\r
         # create mikoto bone\r