Skip to content
Snippets Groups Projects
io_import_scene_mhx.py 136 KiB
Newer Older
        #filepathname = self.filepath.encode('utf-8', 'strict')
            if not context.user_preferences.system.use_scripts_auto_execute:
                MyError("Auto Run Python Scripts must be turned on.\nIt is found under\n File > User Preferences > File")
            readMhxFile(self.filepath)
            #bpy.ops.mhx.success('INVOKE_DEFAULT', message = self.filepath)
            print("Error when loading MHX file %s:\n" % self.filepath + theMessage)
        if self.advanced:
            writeDefaults()
            self.advanced = False
Luca Bonavita's avatar
Luca Bonavita committed
        return {'FINISHED'}

Luca Bonavita's avatar
Luca Bonavita committed
    def invoke(self, context, event):
        global toggle, theScale, MhxBoolProps
        self.scale = theScale
        for (prop, name, desc, flag) in MhxBoolProps:
            setattr(self, prop, mhxEval('(toggle&%s != 0)' % flag))
Luca Bonavita's avatar
Luca Bonavita committed
        context.window_manager.fileselect_add(self)
        return {'RUNNING_MODAL'}
###################################################################################
#
#    Main panel
#
###################################################################################

MhxLayers = [
    (( 0,    'Root', 'MhxRoot'),
     ( 1,    'Spine', 'MhxFKSpine')),
    ((10,    'Head', 'MhxHead'),
     ( 8,    'Face', 'MhxFace')),
    (( 9,    'Tweak', 'MhxTweak'),
     (16,    'Clothes', 'MhxClothes')),
    #((17,    'IK Spine', 'MhxIKSpine'),
     #((13,    'Inv FK Spine', 'MhxInvFKSpine')),
    ('Left', 'Right'),
    (( 2,    'IK Arm', 'MhxIKArm'),
     (18,    'IK Arm', 'MhxIKArm')),
    (( 3,    'FK Arm', 'MhxFKArm'),
     (19,    'FK Arm', 'MhxFKArm')),
    (( 4,    'IK Leg', 'MhxIKLeg'),
     (20,    'IK Leg', 'MhxIKLeg')),
    (( 5,    'FK Leg', 'MhxFKLeg'),
     (21,    'FK Leg', 'MhxFKLeg')),
    ((12,    'Extra', 'MhxExtra'),
     (28,    'Extra', 'MhxExtra')),
    (( 6,    'Fingers', 'MhxFingers'),
     (22,    'Fingers', 'MhxFingers')),
    (( 7,    'Links', 'MhxLinks'),
     (23,    'Links', 'MhxLinks')),
    ((11,    'Palm', 'MhxPalm'),
     (27,    'Palm', 'MhxPalm')),
]

OtherLayers = [
    (( 1,    'Spine', 'MhxFKSpine'),
     ( 10,    'Head', 'MhxHead')),
    (( 9,    'Tweak', 'MhxTweak'),
     ( 8,    'Face', 'MhxFace')),
    ('Left', 'Right'),
    (( 3,    'Arm', 'MhxFKArm'),
     (19,    'Arm', 'MhxFKArm')),
    (( 5,    'Leg', 'MhxFKLeg'),
     (21,    'Leg', 'MhxFKLeg')),
    (( 7,    'Fingers', 'MhxLinks'),
     (23,    'Fingers', 'MhxLinks')),
    ((11,    'Palm', 'MhxPalm'),
     (27,    'Palm', 'MhxPalm')),
]


#
#    class MhxMainPanel(bpy.types.Panel):
#

class MhxMainPanel(bpy.types.Panel):
    bl_label = "MHX Main v %s" % bl_info["version"]
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    #bl_options = {'DEFAULT_CLOSED'}

    @classmethod
    def poll(cls, context):
        return (context.object and context.object.MhxRig)

    def draw(self, context):
        layout = self.layout
        layout.label("Layers")
        layout.operator("mhx.pose_enable_all_layers")
        layout.operator("mhx.pose_disable_all_layers")

        rig = context.object
        if rig.MhxRig == 'MHX':
            layers = MhxLayers
        else:
            layers = OtherLayers

        for (left,right) in layers:
            row = layout.row()
            if type(left) == str:
                row.label(left)
                row.label(right)
            else:
                for (n, name, prop) in [left,right]:
                    row.prop(rig.data, "layers", index=n, toggle=True, text=name)

        layout.separator()
        layout.label("Export/Import MHP")
        layout.operator("mhx.saveas_mhp")
        layout.operator("mhx.load_mhp")


class VIEW3D_OT_MhxEnableAllLayersButton(bpy.types.Operator):
    bl_idname = "mhx.pose_enable_all_layers"
    bl_label = "Enable all layers"
    bl_options = {'UNDO'}

    def execute(self, context):
        rig,mesh = getMhxRigMesh(context.object)
        for (left,right) in MhxLayers:
            if type(left) != str:
                for (n, name, prop) in [left,right]:
                    rig.data.layers[n] = True
        return{'FINISHED'}


class VIEW3D_OT_MhxDisableAllLayersButton(bpy.types.Operator):
    bl_idname = "mhx.pose_disable_all_layers"
    bl_label = "Disable all layers"
    bl_options = {'UNDO'}

    def execute(self, context):
        rig,mesh = getMhxRigMesh(context.object)
        layers = 32*[False]
        pb = context.active_pose_bone
        if pb:
            for n in range(32):
                if pb.bone.layers[n]:
                    layers[n] = True
                    break
        else:
            layers[0] = True
        if rig:
            rig.data.layers = layers
        return{'FINISHED'}



def saveMhpFile(rig, scn, filepath):
    roots = []
    for pb in rig.pose.bones:
        if pb.parent is None:
            roots.append(pb)

    (pname, ext) = os.path.splitext(filepath)
    mhppath = pname + ".mhp"

    fp = open(mhppath, "w", encoding="utf-8", newline="\n")
    for root in roots:
        writeMhpBones(fp, root, None)
    fp.close()
    print("Mhp file %s saved" % mhppath)


def writeMhpBones(fp, pb, log):
    if not isMuscleBone(pb):
        b = pb.bone
        if pb.parent:
            mat = b.matrix_local.inverted() * b.parent.matrix_local * pb.parent.matrix.inverted() * pb.matrix
        else:
            mat = pb.matrix.copy()
            maty = mat[1].copy()
            matz = mat[2].copy()
            mat[1] = matz
            mat[2] = -maty

        diff = mat - Matrix()
        nonzero = False
        for i in range(4):
            if abs(diff[i].length) > 5e-3:
                nonzero = True
                break

        if nonzero:
            fp.write("%s\tmatrix" % pb.name)
            for i in range(4):
                row = mat[i]
                fp.write("\t%.4f\t%.4f\t%.4f\t%.4f" % (row[0], row[1], row[2], row[3]))
            fp.write("\n")

    for child in pb.children:
        writeMhpBones(fp, child, log)


def isMuscleBone(pb):
    layers = pb.bone.layers
    if (layers[14] or layers[15] or layers[30] or layers[31]):
        return True
    for cns in pb.constraints:
        if (cns.type == 'STRETCH_TO' or
            cns.type == 'TRANSFORM' or
            cns.type == 'TRACK_TO' or
            cns.type == 'IK' or
            cns.type[0:5] == 'COPY_'):
            return True
    return False


def loadMhpFile(rig, scn, filepath):
    unit = Matrix()
    for pb in rig.pose.bones:
        pb.matrix_basis = unit

    (pname, ext) = os.path.splitext(filepath)
    mhppath = pname + ".mhp"

    fp = open(mhppath, "rU")
    for line in fp:
        words = line.split()
        if len(words) < 4:
            continue

        try:
            pb = rig.pose.bones[words[0]]
        except KeyError:
            print("Warning: Did not find bone %s" % words[0])
            continue

        if isMuscleBone(pb):
            pass
            q = Quaternion((float(words[2]), float(words[3]), float(words[4]), float(words[5])))
            mat = q.to_matrix().to_4x4()
            pb.matrix_basis = mat
        elif words[1] == "gquat":
            q = Quaternion((float(words[2]), float(words[3]), float(words[4]), float(words[5])))
            mat = q.to_matrix().to_4x4()
            maty = mat[1].copy()
            matz = mat[2].copy()
            mat[1] = -matz
            mat[2] = maty
            pb.matrix_basis = pb.bone.matrix_local.inverted() * mat
        elif words[1] == "matrix":
            rows = []
            n = 2
            for i in range(4):
                rows.append((float(words[n]), float(words[n+1]), float(words[n+2]), float(words[n+3])))
                n += 4
            mat = Matrix(rows)
            if pb.parent:
                pb.matrix_basis = mat
            else:
                maty = mat[1].copy()
                matz = mat[2].copy()
                mat[1] = -matz
                mat[2] = maty
                pb.matrix_basis = pb.bone.matrix_local.inverted() * mat
        elif words[1] == "scale":
            pass
        else:
            print("WARNING: Unknown line in mcp file:\n%s" % line)
    fp.close()
    print("Mhp file %s loaded" % mhppath)


class VIEW3D_OT_LoadMhpButton(bpy.types.Operator):
    bl_idname = "mhx.load_mhp"
    bl_label = "Load MHP File"
    bl_description = "Load a pose in MHP format"
    bl_options = {'UNDO'}

    filename_ext = ".mhp"
    filter_glob = StringProperty(default="*.mhp", options={'HIDDEN'})
    filepath = bpy.props.StringProperty(
        name="File Path",
        description="File path used for mhp file",
        maxlen= 1024, default= "")

    def execute(self, context):
        loadMhpFile(context.object, context.scene, self.properties.filepath)
        return {'FINISHED'}

    def invoke(self, context, event):
        context.window_manager.fileselect_add(self)
        return {'RUNNING_MODAL'}


class VIEW3D_OT_SaveasMhpFileButton(bpy.types.Operator, ExportHelper):
    bl_idname = "mhx.saveas_mhp"
    bl_label = "Save MHP File"
    bl_description = "Save current pose in MHP format"
    bl_options = {'UNDO'}

    filename_ext = ".mhp"
    filter_glob = StringProperty(default="*.mhp", options={'HIDDEN'})
    filepath = bpy.props.StringProperty(
        name="File Path",
        description="File path used for mhp file",
        maxlen= 1024, default= "")

    def execute(self, context):
        saveMhpFile(context.object, context.scene, self.properties.filepath)
        return {'FINISHED'}

    def invoke(self, context, event):
        context.window_manager.fileselect_add(self)
        return {'RUNNING_MODAL'}

###################################################################################
###################################################################################
bodyLanguageVisemes = ({
    'Rest' : [
        ('MouthWidth_L', 0),
        ('MouthWidth_R', 0),
        ('MouthNarrow_L', 0),
        ('MouthNarrow_R', 0),
        ('LipsPart', 0.6),
        ('UpLipsMidHeight', 0),
        ('LoLipsMidHeight', 0),
        ('MouthWidth_L', 0),
        ('MouthWidth_R', 0),
        ('MouthNarrow_L', 0),
        ('MouthNarrow_R', 0),
        ('LipsPart', 0.4),
        ('UpLipsMidHeight', 0),
        ('LoLipsMidHeight', 0),
        ('MouthWidth_L', 0),
        ('MouthWidth_R', 0),
        ('MouthNarrow_L', 0),
        ('MouthNarrow_R', 0),
        ('LipsPart', 0),
        ('UpLipsMidHeight', 0),
        ('LoLipsMidHeight', 0),
        ('MouthWidth_L', 0),
        ('MouthWidth_R', 0),
        ('MouthNarrow_L', 1.0),
        ('MouthNarrow_R', 1.0),
        ('LipsPart', 0),
        ('UpLipsMidHeight', 0),
        ('LoLipsMidHeight', 0),
        ('MouthWidth_L', 0),
        ('MouthWidth_R', 0),
        ('MouthNarrow_L', 0.9),
        ('MouthNarrow_R', 0.9),
        ('LipsPart', 0),
        ('UpLipsMidHeight', 0),
        ('LoLipsMidHeight', 0),
        ('MouthWidth_L', 0),
        ('MouthWidth_R', 0),
        ('MouthNarrow_L', 0.5),
        ('MouthNarrow_R', 0.5),
        ('LipsPart', 0),
        ('UpLipsMidHeight', 0.2),
        ('LoLipsMidHeight', -0.2),
        ('MouthWidth_L', 0.2),
        ('MouthWidth_R', 0.2),
        ('MouthNarrow_L', 0),
        ('MouthNarrow_R', 0),
        ('LipsPart', 1.0),
        ('UpLipsMidHeight', 0),
        ('LoLipsMidHeight', 0.3),
        ('MouthWidth_L', 0),
        ('MouthWidth_R', 0),
        ('MouthNarrow_L', 0),
        ('MouthNarrow_R', 0),
        ('LipsPart', 0),
        ('UpLipsMidHeight', 0.5),
        ('LoLipsMidHeight', -0.7),
        ('MouthWidth_L', 0.8),
        ('MouthWidth_R', 0.8),
        ('MouthNarrow_L', 0),
        ('MouthNarrow_R', 0),
        ('LipsPart', 0),
        ('UpLipsMidHeight', 1.0),
        ('LoLipsMidHeight', 0),
        ('MouthWidth_L', 0.2),
        ('MouthWidth_R', 0.2),
        ('MouthNarrow_L', 0),
        ('MouthNarrow_R', 0),
        ('LipsPart', 0),
        ('UpLipsMidHeight', 0.6),
        ('LoLipsMidHeight', -0.6),
        ('MouthWidth_L', 0),
        ('MouthWidth_R', 0),
        ('MouthNarrow_L', 0),
        ('MouthNarrow_R', 0),
        ('LipsPart', 0),
        ('UpLipsMidHeight', 0.4),
        ('LoLipsMidHeight', 0),
        ('MouthWidth_L', 0),
        ('MouthWidth_R', 0),
        ('MouthNarrow_L', 0),
        ('MouthNarrow_R', 0),
        ('LipsPart', 0),
        ('UpLipsMidHeight', 0.5),
        ('LoLipsMidHeight', -0.6),
        ('MouthWidth_L', 0),
        ('MouthWidth_R', 0),
        ('MouthNarrow_L', 0),
        ('MouthNarrow_R', 0),
        ('LipsPart', 0),
        ('UpLipsMidHeight', 0),
        ('LoLipsMidHeight', 0),
        ('MouthWidth_L', 0),
        ('MouthWidth_R', 0),
        ('MouthNarrow_L', 0),
        ('MouthNarrow_R', 0),
        ('LipsPart', 0),
        ('UpLipsMidHeight', 0.5),
        ('LoLipsMidHeight', -0.5),
        ('MouthWidth_L', 0),
        ('MouthWidth_R', 0),
        ('MouthNarrow_L', 0),
        ('MouthNarrow_R', 0),
        ('LipsPart', 0),
        ('UpLipsMidHeight', 0.5),
        ('LoLipsMidHeight', -0.5),
VisemePanelBones = {
    'MouthOpen' :       ('PJaw', (0,0.25)),
    'UpLipsMidHeight' : ('PUpLipMid', (0,-0.25)),
    'LoLipsMidHeight' : ('PLoLipMid', (0,-0.25)),
    'LoLipsIn':         ('PLoLipMid', (-0.25,0)),
    'MouthWidth_L' :    ('PMouth_L', (0.25,0)),
    'MouthWidth_R' :    ('PMouth_R', (-0.25,0)),
    'MouthNarrow_L' :   ('PMouth_L', (-0.25,0)),
    'MouthNarrow_R' :   ('PMouth_R', (0.25,0)),
    'TongueBackHeight': ('PTongue', (-0.25, 0)),
    'TongueHeight' :    ('PTongue', (0, -0.25)),
    'UpLidUp_L' :       ('PUpLid_L', (0,1.0)),
    'UpLidUp_R' :       ('PUpLid_R', (0,1.0)),
    'LoLidDown_L' :     ('PLoLid_L', (0,-1.0)),
    'LoLidDown_R' :     ('PLoLid_R', (0,-1.0)),
}
VisemeList = [
    ('Rest', 'Etc', 'AH'),
    ('MBP', 'OO', 'O'),
    ('R', 'FV', 'S'),
    ('SH', 'EE', 'EH'),
    ('TH', 'L', 'G')
]

#
#   makeVisemes(ob, scn):
#   class VIEW3D_OT_MhxMakeVisemesButton(bpy.types.Operator):
#

def makeVisemes(ob, scn):
    if ob.type != 'MESH':
        print("Active object %s is not a mesh" % ob)
        return
    if not ob.data.shape_keys:
        print("%s has no shapekeys" % ob)
        return
    try:
        ob.data.shape_keys.key_blocks["VIS_Rest"]
        print("Visemes already created")
        return
    try:
        ob.data.shape_keys.key_blocks["MouthOpen"]
    except KeyError:
        print("Mesh does not have face shapes")
        return
    for (vis,shapes) in bodyLanguageVisemes.items():
        vkey = ob.shape_key_add(name="VIS_%s" % vis)
        print(vkey.name)
        for n,v in enumerate(verts):
            vkey.data[n].co = v.co
        for (name,value) in shapes:
            if name[-2:] == "_R":
                continue
            skey = ob.data.shape_keys.key_blocks[name]
            factor = 0.75*value
            for n,v in enumerate(verts):
                vkey.data[n].co += factor*(skey.data[n].co - v.co)
class VIEW3D_OT_MhxMakeVisemesButton(bpy.types.Operator):
    bl_idname = "mhx.make_visemes"
    bl_label = "Generate viseme shapekeys"
    bl_options = {'UNDO'}

    def execute(self, context):
        makeVisemes(context.object, context.scene)
MohoVisemes = dict({
    "rest" : "Rest",
    "etc" : "Etc",
    "AI" : "AH",
    "O" : "O",
    "U" : "OO",
    "WQ" : "AH",
    "L" : "L",
    "E" : "EH",
    "MBP" : "MBP",
    "FV" : "FV",
MagpieVisemes = dict({
    "E" : "EH",
    "O" : "O",
    "UW" : "AH",
    "MBP" : "MBP",
    "L" : "L",
    "FV" : "FV",
    "Sh" : "SH",
})

#
#    setViseme(context, vis, setKey, frame):
#    setBoneLocation(context, pbone, loc, mirror, setKey, frame):
#    class VIEW3D_OT_MhxVisemeButton(bpy.types.Operator):
#
def getVisemeSet(context, rig):
        return stopStaringVisemes
    elif rig.MhxVisemeSet == "BodyLanguage":
        return bodyLanguageVisemes
    else:
        raise MhxError("Unknown viseme set %s" % visset)
def setVisemeAlpha7(context, vis, visemes, setKey, frame):
    (rig, mesh) = getMhxRigMesh(context.object)
    isPanel = False
    isProp = False
    shapekeys = None
    scale = 0.75
    if rig.MhxShapekeyDrivers:
            scale *= rig.pose.bones['PFace'].bone.length
            isPanel = True
            isProp = True
    elif mesh:
        shapekeys = mesh.data.shape_keys.key_blocks
    for (skey, value) in visemes[vis]:
        if isPanel:
            (b, (x,z)) = VisemePanelBones[skey]
            loc = mathutils.Vector((float(x*value),0,float(z*value)))
            pb = rig.pose.bones[b]
            pb.location = loc*scale
            if setKey or context.tool_settings.use_keyframe_insert_auto:
                for n in range(3):
                    pb.keyframe_insert('location', index=n, frame=frame, group=pb.name)
        elif isProp:
            skey = 'Mhf' + skey
            try:
                prop = rig[skey]
            except:
                continue
            rig[skey] = value*scale
            if setKey or context.tool_settings.use_keyframe_insert_auto:
                rig.keyframe_insert('["%s"]' % skey, frame=frame, group="Visemes")
        elif shapekeys:
            try:
                shapekeys[skey].value = value*scale
            except:
                continue
            if setKey or context.tool_settings.use_keyframe_insert_auto:
                shapekeys[skey].keyframe_insert("value", frame=frame)
    updatePose(context)

class VIEW3D_OT_MhxVisemeButton(bpy.types.Operator):
    bl_idname = 'mhx.pose_viseme'
    bl_label = 'Viseme'
    bl_options = {'UNDO'}
    viseme = StringProperty()

    def invoke(self, context, event):
        (rig, mesh) = getMhxRigMesh(context.object)
        visemes = getVisemeSet(context, rig)
        setVisemeAlpha7(context, self.viseme, visemes, False, context.scene.frame_current)

def readLipsync(context, filepath, offs, struct):
    if rig.MhxVisemeSet:
        visemes = getVisemeSet(context, rig)
    else:
        props = getProps(rig, "Mhv")
        visemes = {}
        oldKeys = []
        for prop in props:
            dummy,units = getUnitsFromString("x;"+rig[prop])
            visemes[prop] = units
        props = getProps(rig, "Mhsmouth")
        auto = context.tool_settings.use_keyframe_insert_auto
        auto = True
        factor = rig.MhxStrength
    context.scene.objects.active = rig
    for line in fp:
        words= line.split()
        if len(words) < 2:
            frame = int(words[0])+offs
            setVisemeAlpha7(context, vis, visemes, True, frame)
        else:
            setMhmProps(rig, shapekeys, "Mhsmouth", visemes["Mhv"+vis], factor, auto, frame)
    updatePose(context)
    print("Lipsync file %s loaded" % filepath)
class VIEW3D_OT_MhxMohoButton(bpy.types.Operator, ImportHelper):
    bl_idname = "mhx.pose_load_moho"
    bl_label = "Load Moho (.dat)"
    bl_options = {'UNDO'}
    filename_ext = ".dat"
    filter_glob = StringProperty(default="*.dat", options={'HIDDEN'})
    filepath = StringProperty(subtype='FILE_PATH')
    def execute(self, context):
        readLipsync(context, self.properties.filepath, context.scene.frame_start - 1, MohoVisemes)
        return{'FINISHED'}

    def invoke(self, context, event):
        context.window_manager.fileselect_add(self)


class MhxLipsyncPanel(bpy.types.Panel):
    bl_label = "MHX Lipsync"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_options = {'DEFAULT_CLOSED'}
    @classmethod
    def poll(cls, context):
            if not visemes:
                layout.label("No visemes found")
                return
            layout.operator("mhx.pose_reset_expressions", text="Reset visemes").prefix="Mhsmouth"
            layout.operator("mhx.pose_key_expressions", text="Key visemes").prefix="Mhsmouth"
            layout.prop(rig, "MhxStrength")
            layout.separator()
                if n % 3 == 0:
                    row = layout.row()
                    n = 0
                row.operator("mhx.pose_mhm", text=prop[3:]).data="Mhsmouth;"+rig[prop]
                n += 1
            while n % 3 != 0:
                row.label("")
                n += 1
            layout.separator()
            row = layout.row()
            row.operator("mhx.pose_mhm", text="Blink").data="Mhsmouth;eye_left_closure:1;eye_right_closure:1"
            row.operator("mhx.pose_mhm", text="Unblink").data="Mhsmouth;eye_left_closure:0;eye_right_closure:0"
        else:
            for (vis1, vis2, vis3) in VisemeList:
                row = layout.row()
                row.operator("mhx.pose_viseme", text=vis1).viseme = vis1
                row.operator("mhx.pose_viseme", text=vis2).viseme = vis2
                row.operator("mhx.pose_viseme", text=vis3).viseme = vis3
            layout.separator()
            row = layout.row()
            row.operator("mhx.pose_viseme", text="Blink").viseme = 'Blink'
            row.operator("mhx.pose_viseme", text="Unblink").viseme = 'Unblink'
            layout.separator()
            layout.operator("mhx.make_visemes")
        layout.separator()
        row = layout.row()
        #layout.operator("mhx.update")
#   updatePose(context):
#   class VIEW3D_OT_MhxUpdateButton(bpy.types.Operator):
#

def updatePose(context):
    scn = context.scene
    bpy.ops.object.posemode_toggle()
    bpy.ops.object.posemode_toggle()
    return

class VIEW3D_OT_MhxUpdateButton(bpy.types.Operator):
    bl_idname = "mhx.update"
    bl_label = "Update"

    def execute(self, context):
        updatePose(context)
###################################################################################
###################################################################################

class VIEW3D_OT_MhxResetExpressionsButton(bpy.types.Operator):
    bl_idname = "mhx.pose_reset_expressions"
    bl_label = "Reset expressions"
    bl_options = {'UNDO'}

    def execute(self, context):
        shapekeys = getMhmShapekeys(rig, mesh)
        clearMhmProps(rig, shapekeys, self.prefix, context.tool_settings.use_keyframe_insert_auto, context.scene.frame_current)
        updatePose(context)


class VIEW3D_OT_MhxKeyExpressionsButton(bpy.types.Operator):
    bl_idname = "mhx.pose_key_expressions"
    bl_label = "Key expressions"
    bl_options = {'UNDO'}

    def execute(self, context):
        props = getProps(rig, self.prefix)
        frame = context.scene.frame_current
Thomas Larsson's avatar
Thomas Larsson committed
            rig.keyframe_insert('["%s"]'%prop, frame=frame)
        updatePose(context)

class VIEW3D_OT_MhxPinExpressionButton(bpy.types.Operator):
    bl_idname = "mhx.pose_pin_expression"
    bl_label = "Pin"
    bl_options = {'UNDO'}

    def execute(self, context):
        words = self.data.split(";")
        prefix = words[0]
        expression = words[1]
        if context.tool_settings.use_keyframe_insert_auto:
            frame = context.scene.frame_current
                    rig[prop] = 1.0
                else:
                    rig[prop] = 0.0
                if abs(rig[prop] - old) > 1e-3:
Thomas Larsson's avatar
Thomas Larsson committed
                    rig.keyframe_insert('["%s"]'%prop, frame=frame)
                    rig[prop] = 1.0
                else:
                    rig[prop] = 0.0
        updatePose(context)
def getMhmShapekeys(rig, mesh):
    if rig.MhxShapekeyDrivers:
        return None
    else:
        return mesh.data.shape_keys.key_blocks

def setMhmProps(rig, shapekeys, prefix, units, factor, auto, frame):
    clearMhmProps(rig, shapekeys, prefix, auto, frame)
    for (prop, value) in units:
        if shapekeys:
            skey = prop[3:].replace("_","-")
            shapekeys[skey].value = factor*value
            if auto:
                shapekeys[skey].keyframe_insert("value", frame=frame)
def clearMhmProps(rig, shapekeys, prefix, auto, frame):
    props = getProps(rig, prefix)
    for prop in props:
        if shapekeys:
            skey = prop[3:].replace("_","-")
            shapekeys[skey].value = 0.0
            if auto:
                shapekeys[skey].keyframe_insert("value", frame=frame)
                rig.keyframe_insert('["%s"]'%prop, frame=frame)
    prefix = words[0]
    for word in words[1:]:
        prop = "Mhs" + unit[0]
        value = float(unit[1])
        units.append((prop, value))

class VIEW3D_OT_MhxMhmButton(bpy.types.Operator):
    bl_idname = "mhx.pose_mhm"
    bl_label = "Mhm"
    bl_options = {'UNDO'}
    data = StringProperty()

        rig,mesh = getMhxRigMesh(context.object)
        auto = context.tool_settings.use_keyframe_insert_auto
        frame = context.scene.frame_current
        prefix,units = getUnitsFromString(self.data)
        setMhmProps(rig, shapekeys, prefix, units, rig.MhxStrength, auto, frame)
    props = []
    for prop in rig.keys():
        if prop.startswith(prefix):
    return props
def hasProps(ob, prefix):
    if ob is None:
        return False
    if ob.type == 'MESH' and ob.parent: