Skip to content
Snippets Groups Projects
io_import_scene_mhx.py 84.7 KiB
Newer Older
#    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"