Skip to content
Snippets Groups Projects
io_import_scene_mhx.py 73.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • Luca Bonavita's avatar
    Luca Bonavita committed
        global todo
        if verbosity > 2:
            print( "Parsing RenderSettings %s" % args )
        for (key, val, sub) in tokens:
            if key == 'Layer':
                pass
                #parseDefault(scn.layers, sub, [])
            else:
                defaultKey(key, val, sub, "render", [], globals(), locals())
        return
    
    #    parseDefineProperty(args, tokens):
    
    def parseDefineProperty(args, tokens):
        expr = "bpy.types.Object.%s = %sProperty" % (args[0], args[1])
        c = '('
        for option in args[2:]:
            expr += "%s %s" % (c, option)
            c = ','
        expr += ')'
        #print(expr)
        exec(expr)
        #print("Done")
        return
    
    #
    #    correctRig(args):
    #
    
    def correctRig(args):
        human = args[0]
        print("CorrectRig %s" % human)    
        try:
            ob = loadedData['Object'][human]
        except:
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            return
    
        bpy.context.scene.objects.active = ob
        bpy.ops.object.mode_set(mode='POSE')
        amt = ob.data
        cnslist = []
        for pb in ob.pose.bones:
            for cns in pb.constraints:
                if cns.type == 'CHILD_OF':
                    cnslist.append((pb, cns, cns.influence))
                    cns.influence = 0
    
        for (pb, cns, inf) in cnslist:
            amt.bones.active = pb.bone
            cns.influence = 1
            #print("Childof %s %s %s %.2f" % (amt.name, pb.name, cns.name, inf))
            bpy.ops.constraint.childof_clear_inverse(constraint=cns.name, owner='BONE')
            bpy.ops.constraint.childof_set_inverse(constraint=cns.name, owner='BONE')
            cns.influence = 0
    
        for (pb, cns, inf) in cnslist:
            cns.influence = inf
        return
            
    
    #
    #    postProcess(args)
    #
    
    def postProcess(args):
        human = args[0]
        print("Postprocess %s" % human)    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        try:
    
            ob = loadedData['Object'][human]
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        except:
            ob = None
        if toggle & T_Diamond == 0 and ob:
            deleteDiamonds(ob)
        if toggle & T_Rigify and False:
            for rig in loadedData['Rigify'].values():
                bpy.context.scene.objects.active = rig
                print("Rigify", rig)
                bpy.ops.pose.metarig_generate()
                print("Metarig generated")
                #bpy.context.scene.objects.unlink(rig)
    
                rig = bpy.context.scene.objects.active
                print("Rigged", rig, bpy.context.object)
    
                ob = loadedData['Object'][human]
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                mod = ob.modifiers[0]
                print(ob, mod, mod.object)
                mod.object = rig
                print("Rig changed", mod.object)
        return            
    
    #
    #    deleteDiamonds(ob)
    #    Delete joint diamonds in main mesh
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        bpy.context.scene.objects.active = ob
        if not bpy.context.object:
            return
        print("Delete diamonds in %s" % bpy.context.object)
        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.mesh.select_all(action='DESELECT')
        bpy.ops.object.mode_set(mode='OBJECT')
        me = ob.data
        for f in me.faces:        
            if len(f.vertices) < 4:
                for vn in f.vertices:
                    me.vertices[vn].select = True
        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.mesh.delete(type='VERT')
        bpy.ops.object.mode_set(mode='OBJECT')
        return
    
        
    #
    #    parseProcess(args, tokens):
    #    applyTransform(objects, rig, parents):
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    def parseProcess(args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        if toggle & T_Bend == 0:
            return
        try:
            rig = loadedData['Object'][args[0]]
        except:
            rig = None
        if not rig:
            return
    
        parents = {}
        objects = []
    
        for (key, val, sub) in tokens:
            #print(key, val)
            if key == 'Reparent':
                bname = val[0]
                try:
                    eb = ebones[bname]
                    parents[bname] = eb.parent.name
                    eb.parent = ebones[val[1]]
                except:
                    pass
            elif key == 'Bend':
                axis = val[1]
                angle = float(val[2])
                mat = mathutils.Matrix.Rotation(angle, 4, axis)
                try:
                    pb = pbones[val[0]]
                    prod = pb.matrix_local * mat
                    for i in range(4):
                        for j in range(4):
                            pb.matrix_local[i][j] = prod[i][j]
                except:
                    print("No bone "+val[0])
                    pass
            elif key == 'Snap':
                try:
                    eb = ebones[val[0]]
                except:
                    eb = None
                tb = ebones[val[1]]
                typ = val[2]
                if eb == None:
                    pass
                elif typ == 'Inv':
                    eb.head = tb.tail
                    eb.tail = tb.head
                elif typ == 'Head':
                    eb.head = tb.head
                elif typ == 'Tail':
                    eb.tail = tb.tail
                elif typ == 'Both':
                    eb.head = tb.head
                    eb.tail = tb.tail
                    eb.roll = tb.roll
                else:
                    raise NameError("Snap type %s" % typ)
            elif key == 'PoseMode':
                bpy.context.scene.objects.active = rig
                bpy.ops.object.mode_set(mode='POSE')
                pbones = rig.pose.bones    
            elif key == 'ObjectMode':
                bpy.context.scene.objects.active = rig
                bpy.ops.object.mode_set(mode='POSE')
                pbones = rig.pose.bones    
            elif key == 'EditMode':
                bpy.context.scene.objects.active = rig
                bpy.ops.object.mode_set(mode='EDIT')
                ebones = rig.data.edit_bones    
                bpy.ops.armature.select_all(action='DESELECT')
            elif key == 'Roll':
                try:
                    eb = ebones[val[0]]
                except:
                    eb = None
                if eb:
                    eb.roll = float(val[1])
            elif key == 'Select':
                pass
            elif key == 'RollUp':
                pass
            elif key == 'Apply':
                applyTransform(objects, rig, parents)
            elif key == 'ApplyArmature':
                try:
                    ob = loadedData['Object'][val[0]]
                    objects.append((ob,sub))
                except:
                    ob = None
            elif key == 'Object':
                try:
                    ob = loadedData['Object'][val[0]]
                except:
                    ob = None
                if ob:
                    bpy.context.scene.objects.active = ob
                    #mod = ob.modifiers[0]
                    #ob.modifiers.remove(mod)
                    for (key1, val1, sub1) in sub:
                        if key1 == 'Modifier':
                            parseModifier(ob, val1, sub1)
        return
    
    
    def applyTransform(objects, rig, parents):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        for (ob,tokens) in objects:
            print("Applying transform to %s" % ob)
            bpy.context.scene.objects.active = ob        
            bpy.ops.object.visual_transform_apply()
            bpy.ops.object.modifier_apply(apply_as='DATA', modifier='Armature')
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        bpy.context.scene.objects.active = rig
        bpy.ops.object.mode_set(mode='POSE')
        bpy.ops.pose.armature_apply()
        bpy.ops.object.mode_set(mode='OBJECT')
        bpy.ops.object.mode_set(mode='EDIT')
        ebones = rig.data.edit_bones
        for (bname, pname) in parents.items():
            eb = ebones[bname]
            par = ebones[pname]
            if eb.use_connect:
                par.tail = eb.head
            eb.parent = par
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        bpy.ops.object.mode_set(mode='OBJECT')
        return            
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    defaultKey(ext, args, tokens, var, exclude, glbals, lcals):
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    def defaultKey(ext, args, tokens, var, exclude, glbals, lcals):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        global todo
    
        if ext == 'Property':
            try:
                expr = "%s['%s'] = %s" % (var, args[0], args[1])
            except:
                expr = None
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            if expr:
                exec(expr, glbals, lcals)
            return
    
    
        if ext == 'bpyops':
            expr = "bpy.ops.%s" % args[0]
            print(expr)
            exec(expr)
            return
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            
        nvar = "%s.%s" % (var, ext)
        #print(ext)
        if ext in exclude:
            return
        #print("D", nvar)
    
        if len(args) == 0:
            raise NameError("Key length 0: %s" % ext)
            
        rnaType = args[0]
        if rnaType == 'Add':
            print("*** Cannot Add yet ***")
            return
    
        elif rnaType == 'Refer':
            typ = args[1]
            name = args[2]
            data = "loadedData['%s']['%s']" % (typ, name)
    
        elif rnaType == 'Struct' or rnaType == 'Define':
            typ = args[1]
            name = args[2]
            try:
                data = eval(nvar, glbals, lcals)
            except:
                data = None            
            # print("Old structrna", nvar, data)
    
            if data == None:
                try:
                    creator = args[3]
                except:
                    creator = None
                # print("Creator", creator, eval(var,glbals,lcals))
    
                try:
                    rna = eval(var,glbals,lcals)
                    data = eval(creator)
                except:
                    data = None    
                # print("New struct", nvar, typ, data)
    
            if rnaType == 'Define':
                loadedData[typ][name] = data
    
            if data:
                for (key, val, sub) in tokens:
                    defaultKey(key, val, sub, "data", [], globals(), locals())
    
            print("Struct done", nvar)
            return
    
        elif rnaType == 'PropertyRNA':
            raise NameError("PropertyRNA!")
            #print("PropertyRNA ", ext, var)
            for (key, val, sub) in tokens:
                defaultKey(ext, val, sub, nvar, [], glbals, lcals)
            return
    
        elif rnaType == 'Array':
            for n in range(1, len(args)):
                expr = "%s[%d] = %s" % (nvar, n-1, args[n])
                exec(expr, glbals, lcals)
            if len(args) > 0:
                expr = "%s[0] = %s" % (nvar, args[1])
                exec(expr, glbals, lcals)            
            return
            
        elif rnaType == 'List':
            data = []
            for (key, val, sub) in tokens:
                elt = eval(val[1], glbals, lcals)
                data.append(elt)
    
        elif rnaType == 'Matrix':
            return
            i = 0
            n = len(tokens)
            for (key, val, sub) in tokens:
                if key == 'row':    
                    for j in range(n):
                        expr = "%s[%d][%d] = %g" % (nvar, i, j, float(val[j]))
                        exec(expr, glbals, lcals)
                    i += 1
            return
    
        else:
            try:
                data = loadedData[rnaType][args[1]]
                #print("From loaded", rnaType, args[1], data)
                return data
            except:
                data = rnaType
    
        #print(var, ext, data)
        expr = "%s = %s" % (nvar, data)
        try:
            exec(expr, glbals, lcals)
        except:
            pushOnTodoList(var, expr, glbals, lcals)
        return
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        global todo
        print("Tdo", var)
        print(dir(eval(var, glbals, lcals)))
        raise NameError("Todo", expr)
        todo.append((expr, glbals, lcals))
        return
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    parseBoolArray(mask):
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    def parseBoolArray(mask):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        list = []
        for c in mask:
            if c == '0':            
                list.append(False)
            else:
                list.append(True)
        return list
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    parseMatrix(args, tokens)
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    def parseMatrix(args, tokens):
    
        matrix = Matrix()
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        i = 0
        for (key, val, sub) in tokens:
            if key == 'row':    
                matrix[i][0] = float(val[0])
                matrix[i][1] = float(val[1])
                matrix[i][2] = float(val[2])
                matrix[i][3] = float(val[3])
                i += 1
        return matrix
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    parseDefault(data, tokens, subkeys, exclude):
    
    def parseDefault(data, tokens, subkeys, exclude):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        for (key, val, sub) in tokens:    
            if key in subkeys.keys():
                for (key2, val2, sub2) in sub:
                    defaultKey(key2, val2, sub2, "data.%s" % subkeys[key], [], globals(), locals())
            else:
                defaultKey(key, val, sub, "data", exclude, globals(), locals())
    
    
    def parseCollection(data, tokens, exclude):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        return
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    Utilities    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    extractBpyType(data):
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    def extractBpyType(data):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        typeSplit = str(type(data)).split("'")
        if typeSplit[0] != '<class ':
            return None
        classSplit = typeSplit[1].split(".")
        if classSplit[0] == 'bpy' and classSplit[1] == 'types':
            return classSplit[2]
        elif classSplit[0] == 'bpy_types':
            return classSplit[1]
        else:
            return None
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    Bool(string):
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    def Bool(string):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        if string == 'True':
            return True
        elif string == 'False':
            return False
        else:
            raise NameError("Bool %s?" % string)
            
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    invalid(condition):
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    def invalid(condition):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        global rigLeg, rigArm, toggle
        res = eval(condition, globals())
        try:
            res = eval(condition, globals())
            #print("%s = %s" % (condition, res))
            return not res
        except:
            #print("%s invalid!" % condition)
            return True
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    clearScene(context):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    def clearScene():
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        global toggle
        scn = bpy.context.scene
        for n in range(len(scn.layers)):
            scn.layers[n] = True
        print("clearScene %s %s" % (toggle & T_Replace, scn))
        if not toggle & T_Replace:
            return scn
    
        for ob in scn.objects:
    
            if ob.type in ["MESH", "ARMATURE", 'EMPTY', 'CURVE', 'LATTICE']:
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                scn.objects.active = ob
    
                try:
                    bpy.ops.object.mode_set(mode='OBJECT')
                except:
                    pass
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                scn.objects.unlink(ob)
                del ob
        #print(scn.objects)
        return scn
    
    #
    #    hideLayers(args):
    #    args = sceneLayers sceneHideLayers boneLayers boneHideLayers or nothing
    #
    
    def hideLayers(args):
        if len(args) > 1:
            sceneLayers = int(args[2], 16)
            sceneHideLayers = int(args[3], 16)
            boneLayers = int(args[4], 16)
            boneHideLayers = int(args[5], 16)
        else:
            sceneLayers = 0x00ff
            sceneHideLayers = 0
            boneLayers = 0
            boneHideLayers = 0
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        scn = bpy.context.scene
    
        mask = 1
        hidelayers = []
        for n in range(20):
            scn.layers[n] = True if sceneLayers & mask else False
            if sceneHideLayers & mask:
                hidelayers.append(n)
            mask = mask << 1
    
        for ob in scn.objects:
            for n in hidelayers:
                if ob.layers[n]:
                    ob.hide = True
    
        if boneLayers:    
            human = args[1]
            try:
                ob = loadedData['Object'][human]
            except:
                return
    
            mask = 1
            hidelayers = []
            for n in range(32):
                ob.data.layers[n] = True if boneLayers & mask else False
                if boneHideLayers & mask:
                    hidelayers.append(n)
                mask = mask << 1
    
            for b in ob.data.bones:
                for n in hidelayers:
                    if b.layers[n]:
                        b.hide = True
    
        return
        
    
    #
    #    readDefaults():
    #    writeDefaults():
    #
    
    ConfigFile = '~/mhx_import.cfg'
    
    
    def readDefaults():
        global toggle, theScale, theBlenderVersion, BlenderVersions
        path = os.path.realpath(os.path.expanduser(ConfigFile))
        try:
            fp = open(path, 'rU')
            print('Storing defaults')
        except:
            print('Cannot open "%s" for reading' % path)
            return
        bver = ''
        for line in fp: 
            words = line.split()
            if len(words) >= 3:
                try:
                    toggle = int(words[0],16)
                    theScale = float(words[1])
                    theBlenderVersion = BlenderVersions.index(words[2])
                except:
                    print('Configuration file "%s" is corrupt' % path)                
        fp.close()
        return
    
    def writeDefaults():
        global toggle, theScale, theBlenderVersion, BlenderVersions
        path = os.path.realpath(os.path.expanduser(ConfigFile))
        try:
            fp = open(path, 'w')
            print('Storing defaults')
        except:
            print('Cannot open "%s" for writing' % path)
            return
        fp.write("%x %f %s" % (toggle, theScale, BlenderVersions[theBlenderVersion]))
        fp.close()
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        return
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    User interface
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    DEBUG= False
    from bpy.props import *
    
    from io_utils import ImportHelper
    
    
    MhxBoolProps = [
        ("enforce", "Enforce version", "Only accept MHX files of correct version", T_EnforceVersion),
        ("mesh", "Mesh", "Use main mesh", T_Mesh),
        ("proxy", "Proxies", "Use proxies", T_Proxy),
        ("armature", "Armature", "Use armature", T_Armature),
        ("replace", "Replace scene", "Replace scene", T_Replace),
        ("cage", "Cage", "Load mesh deform cage", T_Cage),
        ("clothes", "Clothes", "Include clothes", T_Clothes),
        ("stretch", "Stretchy limbs", "Stretchy limbs", T_Stretch),
        ("face", "Face shapes", "Include facial shapekeys", T_Face),
        ("shape", "Body shapes", "Include body shapekeys", T_Shape),
        ("symm", "Symmetric shapes", "Keep shapekeys symmetric", T_Symm),
        ("diamond", "Diamonds", "Keep joint diamonds", T_Diamond),
        ("bend", "Bend joints", "Bend joints for better IK", T_Bend),
        #("opcns", "Operator constraints", "Only for Aligorith", T_Opcns),
    ]
    
    class ImportMhx(bpy.types.Operator, ImportHelper):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        '''Import from MHX file format (.mhx)'''
        bl_idname = "import_scene.makehuman_mhx"
        bl_description = 'Import from MHX file format (.mhx)'
        bl_label = "Import MHX"
        bl_space_type = "PROPERTIES"
        bl_region_type = "WINDOW"
    
        scale = FloatProperty(name="Scale", description="Default meter, decimeter = 1.0", default = theScale)
    
        enums = []
        for enum in BlenderVersions:
            enums.append((enum,enum,enum))
        bver = EnumProperty(name="Blender version", items=enums, default = BlenderVersions[0])
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
        filename_ext = ".mhx"
        filter_glob = StringProperty(default="*.mhx", options={'HIDDEN'})
        filepath = StringProperty(name="File Path", description="File path used for importing the MHX file", maxlen= 1024, default= "")
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
        for (prop, name, desc, flag) in MhxBoolProps:
            expr = '%s = BoolProperty(name="%s", description="%s", default=toggle&%s)' % (prop, name, desc, flag)
            exec(expr)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            
        def execute(self, context):
    
            global toggle, theScale, MhxBoolProps, theBlenderVersion, BlenderVersions
            toggle = 0
            for (prop, name, desc, flag) in MhxBoolProps:
                expr = '(%s if self.properties.%s else 0)' % (flag, prop)
                toggle |=  eval(expr)
            print("execute flags %x" % toggle)
            theScale = self.properties.scale
            theBlenderVersion = BlenderVersions.index(self.properties.bver)
    
            readMhxFile(self.properties.filepath)
            writeDefaults()
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            return {'FINISHED'}
    
        def invoke(self, context, event):
    
            global toggle, theScale, MhxBoolProps, theBlenderVersion, BlenderVersions
            readDefaults()
            self.properties.scale = theScale
            self.properties.bver = BlenderVersions[theBlenderVersion]
            for (prop, name, desc, flag) in MhxBoolProps:
                expr = 'self.properties.%s = toggle&%s' % (prop, flag)
                exec(expr)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            context.window_manager.fileselect_add(self)
            return {'RUNNING_MODAL'}
    
        self.layout.operator(ImportMhx.bl_idname, text="MakeHuman (.mhx)...")
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    def register():
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        bpy.types.INFO_MT_file_import.append(menu_func)
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    def unregister():
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        bpy.types.INFO_MT_file_import.remove(menu_func)
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    if __name__ == "__main__":
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        try:
            unregister()
        except:
            pass
        register()
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    Testing
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    """
    
    #readMhxFile("C:/Documents and Settings/xxxxxxxxxxxxxxxxxxxx/Mina dokument/makehuman/exports/foo-25.mhx", 'Classic')
    readMhxFile("/home/thomas/makehuman/exports/foo-25.mhx", 1.0)
    
    #toggle = T_Replace + T_Mesh + T_Armature + T_MHX
    #readMhxFile("/home/thomas/myblends/test.mhx", 1.0)
    """