Skip to content
Snippets Groups Projects
io_import_scene_mhx.py 84.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • #    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
    
                elif ((toggle & T_Limit == 0) and 
                      (cns.type in ['LIMIT_DISTANCE', 'LIMIT_ROTATION'])):                
                    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)
        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 = Matrix.Rotation(angle, 4, axis)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                try:
                    pb = pbones[val[0]]
                except:
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    print("No bone "+val[0])
    
                if pb:
                    prod = pb.matrix_basis * mat
                    for i in range(4):
                        for j in range(4):
                            pb.matrix_basis[i][j] = prod[i][j]
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            elif key == 'Snap':
                try:
                    eb = ebones[val[0]]
                except:
                    eb = None
                tb = ebones[val[1]]
                typ = val[2]
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    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:
    
                    MyError("Snap type %s" % typ)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            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:
    
            MyError("Key length 0: %s" % ext)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            
        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)
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                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':
    
            MyError("PropertyRNA!")
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            #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)))
    
        MyError("Todo", expr)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        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:
    
            MyError("Bool %s?" % string)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            
    
    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
    
    
        for grp in bpy.data.groups:
            grp.name = "#" + grp.name
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        #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
    
    ###################################################################################
    #
    #   Postprocessing of rigify rig
    #
    
    #
    ###################################################################################
    
    
        print("Modifying MHX rig to Rigify")
        scn = context.scene 
    
        mhx = loadedData['Object'][name]
        mhx['MhxRigify'] = True
        bpy.context.scene.objects.active = mhx
    
        # Delete old widgets
        """
    
        for ob in scn.objects:
            if ob.type == 'MESH' and ob.name[0:3] == "WGT":
                scn.objects.unlink(ob)
    
    
        # Save mhx bone locations    
        heads = {}
        tails = {}
        rolls = {}
        parents = {}
        extras = {}
        bpy.ops.object.mode_set(mode='EDIT')
    
        newParents = {
            'head' : 'DEF-head',
            'ribs' : 'DEF-ribs',
            'upper_arm.L' : 'DEF-upper_arm.L.02',
            'thigh.L' : 'DEF-thigh.L.02',
            'upper_arm.R' : 'DEF-upper_arm.R.02',
            'thigh.R' : 'DEF-thigh.R.02',
        }
    
        for eb in mhx.data.edit_bones:
            heads[eb.name] = eb.head.copy()
            tails[eb.name] = eb.tail.copy()
            rolls[eb.name] = eb.roll
            if eb.parent:            
                par = eb.parent.name
    
                # print(eb.name, par)
    
                try:
                    parents[eb.name] = newParents[par]
                except:
                    parents[eb.name] = par
            else:
                parents[eb.name] = None
            extras[eb.name] = not eb.layers[16]
        bpy.ops.object.mode_set(mode='OBJECT')
       
        # Find corresponding meshes. Can be several (clothes etc.)   
        meshes = []
        for ob in scn.objects:
            for mod in ob.modifiers:
                if (mod.type == 'ARMATURE' and mod.object == mhx):
                    meshes.append((ob, mod))
        if meshes == []:
    
            MyError("Did not find matching mesh")
    
            
        # Rename Head vertex group    
        for (mesh, mod) in meshes:
            try:
                vg = mesh.vertex_groups['DfmHead']
                vg.name = 'DEF-head'
            except:
                pass
    
    
        scn.objects.active = None 
        try:
            bpy.ops.object.armature_human_advanced_add()
            success = True
        except:
            success = False
        if not success:
    
            MyError(
    "Unable to create advanced human. \n" +
    "Make sure that the Rigify add-on is enabled. \n" +
    "It is found under Rigging.")
    
        bpy.ops.object.mode_set(mode='EDIT')
    
            eb.head = heads[eb.name]
            eb.tail = tails[eb.name]
            eb.roll = rolls[eb.name]
            extras[eb.name] = False
    
        fingerPlanes = [
            ('UP-thumb.L', 'thumb.01.L', 'thumb.03.L', ['thumb.02.L']),
            ('UP-index.L', 'finger_index.01.L', 'finger_index.03.L', ['finger_index.02.L']),
            ('UP-middle.L', 'finger_middle.01.L', 'finger_middle.03.L', ['finger_middle.02.L']),
            ('UP-ring.L', 'finger_ring.01.L', 'finger_ring.03.L', ['finger_ring.02.L']),
            ('UP-pinky.L', 'finger_pinky.01.L', 'finger_pinky.03.L', ['finger_pinky.02.L']),
            ('UP-thumb.R', 'thumb.01.R', 'thumb.03.R', ['thumb.02.R']),
            ('UP-index.R', 'finger_index.01.R', 'finger_index.03.R', ['finger_index.02.R']),
            ('UP-middle.R', 'finger_middle.01.R', 'finger_middle.03.R', ['finger_middle.02.R']),
            ('UP-ring.R', 'finger_ring.01.R', 'finger_ring.03.R', ['finger_ring.02.R']),
            ('UP-pinky.R', 'finger_pinky.01.R', 'finger_pinky.03.R', ['finger_pinky.02.R']),
        ]
    
        for (upbone, first, last, middles) in fingerPlanes:
            extras[upbone] = False
    
            #lineateChain(upbone, first, last, middles, 0.01, meta, heads, tails)
    
    
        ikPlanes = [
            ('UP-leg.L', 'thigh.L', 'shin.L'),
            ('UP-arm.L', 'upper_arm.L', 'forearm.L'),
            ('UP-leg.R', 'thigh.R', 'shin.R'),
            ('UP-arm.R', 'upper_arm.R', 'forearm.R'),
        ]
    
        for (upbone, first, last) in ikPlanes:
            extras[upbone] = False
    
            lineateChain(upbone, first, last, [], 0.1, meta, heads, tails)
    
    
        bpy.ops.object.mode_set(mode='OBJECT')
    
    
        bpy.ops.pose.rigify_generate()
    
        scn.objects.unlink(meta)
        rigify = context.object
        rigify.name = name+"Rig"
    
        layers = 20*[False]
        layers[1] = True        
        rigify.layers = layers
    
        for (mesh, mod) in meshes:
    
            mod.object = rigify
    
        grp = loadedData['Group'][name]
        grp.objects.link(rigify)
    
    
        # Parent widgets under empty
        empty = bpy.data.objects.new("Widgets", None)
        scn.objects.link(empty)
        empty.layers = 20*[False]
        empty.layers[19] = True
    
        for ob in scn.objects:
            if ob.type == 'MESH' and ob.name[0:4] == "WGT-" and not ob.parent:
                ob.parent = empty
    
                grp.objects.link(ob)
            elif ob.parent == mhx:
                ob.parent = rigify
    
        bpy.ops.object.mode_set(mode='EDIT')
        for name in heads.keys():
            if extras[name]:
    
                eb.head = heads[name]
                eb.tail = tails[name]
                eb.roll = rolls[name]            
        for name in heads.keys():
            if extras[name] and parents[name]:
    
                eb = rigify.data.edit_bones[name]
                eb.parent = rigify.data.edit_bones[parents[name]]
    
    
        # Copy constraints etc.
        bpy.ops.object.mode_set(mode='POSE')
        for name in heads.keys():
            if extras[name]:
                pb1 = mhx.pose.bones[name]
    
                pb2.custom_shape = pb1.custom_shape
                pb2.lock_location = pb1.lock_location
                pb2.lock_rotation = pb1.lock_rotation
                pb2.lock_scale = pb1.lock_scale
                b1 = pb1.bone
                b2 = pb2.bone
                b2.use_deform = b1.use_deform
                b2.hide_select = b1.hide_select
                b2.show_wire = b1.show_wire
                layers = 32*[False]
                if b1.layers[8]:
                    layers[28] = True
                else:
                    layers[29] = True
                if b1.layers[10]:
                    layers[2] = True
                b2.layers = layers
                for cns1 in pb1.constraints:
    
                    cns2 = copyConstraint(cns1, pb1, pb2, mhx, rigify)    
    
                    if cns2.type == 'CHILD_OF':
    
                        bpy.ops.constraint.childof_set_inverse(constraint=cns2.name, owner='BONE')    
        
        # Create animation data
        if mhx.animation_data:
            for fcu in mhx.animation_data.drivers:
    
                rigify.animation_data.drivers.from_existing(src_driver=fcu)
    
        fixDrivers(rigify.animation_data, mhx, rigify)
    
        for (mesh, mod) in meshes:
    
            skeys = mesh.data.shape_keys
            if skeys:
    
                fixDrivers(skeys.animation_data, mhx, rigify)
    
    
        scn.objects.unlink(mhx)
        print("Rigify rig complete")    
        return
    
    #
    
    #   lineateChain(upbone, first, last, middles, minDist, rig, heads, tails):
    
    #   lineate(pt, start, minDist, normal, offVector):
    #
    
    
    def lineateChain(upbone, first, last, middles, minDist, rig, heads, tails):
        fb = rig.data.edit_bones[first]
        lb = rig.data.edit_bones[last]
    
        uhead = heads[upbone]
        utail = tails[upbone]
        tang = lb.tail - fb.head
        tangent = tang/tang.length
        up = (uhead+utail)/2 - fb.head
        norm = up - tangent*tangent.dot(up)
        normal = norm/norm.length
        offVector = tangent.cross(normal)
        vec = utail - uhead
        fb.tail = lineate(fb.tail, fb.head, minDist, normal, offVector)
        lb.head = lineate(lb.head, fb.head, minDist, normal, offVector)
        for bone in middles:
    
            mb.head = lineate(mb.head, fb.head, minDist, normal, offVector)
            mb.tail = lineate(mb.tail, fb.head, minDist, normal, offVector)
        return
    
    def lineate(pt, start, minDist, normal, offVector):
        diff = pt - start
        diff = diff - offVector*offVector.dot(diff) 
        dist = diff.dot(normal)
        if dist < minDist:
            diff += (minDist - dist)*normal
        return start + diff
    
    #
    
        if not adata:
            return
        for fcu in adata.drivers:
            for var in fcu.driver.variables:
                for targ in var.targets:
                    if targ.id == mhx:
    
    #   copyConstraint(cns1, pb1, pb2, mhx, rigify):
    
    def copyConstraint(cns1, pb1, pb2, mhx, rigify):
    
        substitute = {
            'Head' : 'DEF-head',
            'MasterFloor' : 'root',
            'upper_arm.L' : 'DEF-upper_arm.L.01',
            'upper_arm.R' : 'DEF-upper_arm.R.01',
            'thigh.L' : 'DEF-thigh.L.01',
            'thigh.R' : 'DEF-thigh.R.01',
            'shin.L' : 'DEF-shin.L.01',
            'shin.R' : 'DEF-shin.R.01'
        }
    
        cns2 = pb2.constraints.new(cns1.type)
        for prop in dir(cns1):
            if prop == 'target':
                if cns1.target == mhx:
    
                else:
                    cns2.target = cns1.target
            elif prop == 'subtarget':
                try:
                    cns2.subtarget = substitute[cns1.subtarget]
                except:
                    cns2.subtarget = cns1.subtarget
            elif prop[0] != '_':
                try:
                    expr = "cns2.%s = cns1.%s" % (prop, prop)
                    #print(pb1.name, expr)
                    exec(expr)
                except:
                    pass
        return cns2
    
    #
    #   class OBJECT_OT_RigifyMhxButton(bpy.types.Operator):
    #
    
    class OBJECT_OT_RigifyMhxButton(bpy.types.Operator):
        bl_idname = "mhxrig.rigify_mhx"
        bl_label = "Rigify MHX rig"
    
    
        def execute(self, context):
    
            return{'FINISHED'}    
        
    #
    #   class RigifyMhxPanel(bpy.types.Panel):
    #
    
    class RigifyMhxPanel(bpy.types.Panel):
        bl_label = "Rigify MHX"
        bl_space_type = "VIEW_3D"
        bl_region_type = "UI"
        
        @classmethod
        def poll(cls, context):
            if context.object:
                try:
                    return context.object['MhxRigify']
                except:
                    return False
            return False
    
        def draw(self, context):
    
    Thomas Dinges's avatar
    Thomas Dinges committed
            self.layout.operator("mhxrig.rigify_mhx")
    
            return
    
    ###################################################################################
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    #    Error popup
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    ###################################################################################
    
    from bpy.props import StringProperty, FloatProperty, EnumProperty, BoolProperty
    
    
    class ErrorOperator(bpy.types.Operator):
        bl_idname = "mhx.error"
        bl_label = "Error when loading MHX file"
    
        def execute(self, context):
            return {'RUNNING_MODAL'}
    
        def invoke(self, context, event):
            global theErrorLines
            maxlen = 0
            for line in theErrorLines:
                if len(line) > maxlen:
                    maxlen = len(line)
            width = 20+5*maxlen
            height = 20+5*len(theErrorLines)
            #self.report({'INFO'}, theMessage)
            wm = context.window_manager
            return wm.invoke_props_dialog(self, width=width, height=height)
    
        def draw(self, context):
            global theErrorLines
            for line in theErrorLines:        
                self.layout.label(line)
    
    def MyError(message):
        global theMessage, theErrorLines, theErrorStatus
        theMessage = message
        theErrorLines = message.split('\n')
        theErrorStatus = True
        bpy.ops.mhx.error('INVOKE_DEFAULT')
        raise NameError(theMessage)
    
    class SuccessOperator(bpy.types.Operator):
        bl_idname = "mhx.success"
        bl_label = "MHX file successfully loaded:"
        message = StringProperty()
    
        def execute(self, context):
            return {'RUNNING_MODAL'}
    
        def invoke(self, context, event):
            wm = context.window_manager
            return wm.invoke_props_dialog(self)
    
        def draw(self, context):
            self.layout.label(self.message)
    
    ###################################################################################
    #
    #    User interface
    #
    ###################################################################################
    
    
    
    
    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),
    
        ("rigify", "Rigify", "Create rigify control rig", T_Rigify),
    
        ("limit", "Limit constraints", "Keep limit constraints", T_Limit),
    
    ]
    
    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"