# Copyright 2009 Autodesk, Inc.  All rights reserved.
# Use of this software is subject to the terms of the Autodesk license agreement 
# provided at the time of installation or download, or which otherwise accompanies
# this software in either electronic or hard copy form.
#
# Script description:
# This script is executed when a template with the script name ((in Asset\Character)) is dragged on a character.
# It will Characterize a 3DS Max Biped so it fits the MoBu naming.
#
# Topic: FBFindModelByName,FBCharacter.SetCharacterizeOn,FBProgress
#

from pyfbsdk import *

# These three variables controls how characterization is done

# This is the Root Name. For a Biped this will be the Biped Name. For Custom Skeleton user must set
# it according to their naming convention
bipedrootname = "<CharacterName>"

# For biped, all bones have the following naming scheme <BipedName> <BipedBone>. Set this variable to 
# False if you have Custom Skeleton.
bipedPrefixNamingScheme = True

# This is the biped map mapping all bipeds Name to Mobu Names.
# If you have a custom skeleton, you need to recreate this map according to your naming convention.
bipedMap = {'Reference' : 'Fbx_Root',
            'Hips':'',
             'LeftUpLeg' : 'L Thigh',
             'LeftLeg' : 'L Calf',
             'LeftFoot' : 'L Foot',
             'RightUpLeg' : 'R Thigh',
             'RightLeg' : 'R Calf',
             'RightFoot' : 'R Foot',
             'Spine' : 'Spine',
             'LeftArm' : 'L UpperArm',
             'LeftForeArm' : 'L Forearm',
             'LeftHand' : 'L Hand',
             'RightArm' : 'R UpperArm',
             'RightForeArm' : 'R Forearm',
             'RightHand' : 'R Hand',
             'Head' : 'Head',
             'LeftShoulder' : 'L Clavicle',
             'RightShoulder' : 'R Clavicle',
             'Neck' : 'Neck',
             'Spine1' : 'Spine1',
             'Spine2' : 'Spine2',
             'Spine3' : 'Spine3',
             'Spine4' : 'Spine4',
             'Spine5' : 'Spine5',
             'Spine6' : 'Spine6',
             'Spine7' : 'Spine7',
             'Spine8' : 'Spine8',
             'Spine9' : 'Spine9',
             'Neck1' : 'Neck1',
             'Neck2' : 'Neck2',
             'Neck3' : 'Neck3',
             'Neck4' : 'Neck4',
             'Neck5' : 'Neck5',
             'Neck6' : 'Neck6',
             'Neck7' : 'Neck7',
             'Neck8' : 'Neck8',
             'Neck9' : 'Neck9',
             'LeftHandThumb1' : 'L Finger0',
             'LeftHandThumb2' : 'L Finger01',
             'LeftHandThumb3' : 'L Finger02',
             'LeftHandIndex1' : 'L Finger1',
             'LeftHandIndex2' : 'L Finger11',
             'LeftHandIndex3' : 'L Finger12',
             'LeftHandMiddle1' : 'L Finger2',
             'LeftHandMiddle2' : 'L Finger21',
             'LeftHandMiddle3' : 'L Finger22',
             'LeftHandRing1' : 'L Finger3',
             'LeftHandRing2' : 'L Finger31',
             'LeftHandRing3' : 'L Finger32',
             'LeftHandPinky1' : 'L Finger4',
             'LeftHandPinky2' : 'L Finger41',
             'LeftHandPinky3' : 'L Finger42',
             'RightHandThumb1' : 'R Finger0',
             'RightHandThumb2' : 'R Finger01',
             'RightHandThumb3' : 'R Finger02',
             'RightHandIndex1' : 'R Finger1',
             'RightHandIndex2' : 'R Finger11',
             'RightHandIndex3' : 'R Finger12',
             'RightHandMiddle1' : 'R Finger2',
             'RightHandMiddle2' : 'R Finger21',
             'RightHandMiddle3' : 'R Finger22',
             'RightHandRing1' : 'R Finger3',
             'RightHandRing2' : 'R Finger31',
             'RightHandRing3' : 'R Finger32',
             'RightHandPinky1' : 'R Finger4',
             'RightHandPinky2' : 'R Finger41',
             'RightHandPinky3' : 'R Finger42',
             'LeftFootThumb1' : 'L Toe4',
             'LeftFootThumb2' : 'L Toe41',
             'LeftFootThumb3' : 'L Toe42',
             'LeftFootIndex1' : 'L Toe3',
             'LeftFootIndex2' : 'L Toe31',
             'LeftFootIndex3' : 'L Toe32',
             'LeftFootMiddle1' : 'L Toe2',
             'LeftFootMiddle2' : 'L Toe21',
             'LeftFootMiddle3' : 'L Toe22',
             'LeftFootRing1' : 'L Toe1',
             'LeftFootRing2' : 'L Toe11',
             'LeftFootRing3' : 'L Toe12',
             'LeftFootPinky1' : 'L Toe0',
             'LeftFootPinky2' : 'L Toe01',
             'LeftFootPinky3' : 'L Toe02',
             'RightFootThumb1' : 'R Toe4',
             'RightFootThumb2' : 'R Toe41',
             'RightFootThumb3' : 'R Toe42',
             'RightFootIndex1' : 'R Toe3',
             'RightFootIndex2' : 'R Toe31',
             'RightFootIndex3' : 'R Toe32',
             'RightFootMiddle1' : 'R Toe2',
             'RightFootMiddle2' : 'R Toe21',
             'RightFootMiddle3' : 'R Toe22',
             'RightFootRing1' : 'R Toe1',
             'RightFootRing2' : 'R Toe11',
             'RightFootRing3' : 'R Toe12',
             'RightFootPinky1' : 'R Toe0',
             'RightFootPinky2' : 'R Toe01',
             'RightFootPinky3' : 'R Toe02',
             'LeftUpLegRoll' : 'LThighTwist',
             'LeftLegRoll' : 'LCalfTwist',
             'RightUpLegRoll' : 'RThighTwist',
             'RightLegRoll' : 'RCalfTwist',
             'LeftArmRoll' : 'LUpArmTwist',
             'LeftForeArmRoll' : 'L ForeTwist',
             'RightArmRoll' : 'RUpArmTwist',
             'RightForeArmRoll' : 'R ForeTwist' }

def addJointToCharacter ( characterObject, slot, jointName ):
    myJoint = FBFindModelByName(jointName)
    if myJoint:
        proplist = characterObject.PropertyList.Find(slot + "Link")
        proplist.append (myJoint)

def Characterize(rootname, useBipedPrefixNamingScheme, boneMap):
    # Create an empty FBModelList object.
    models = FBModelList()

    # Obtain the list of selected models.
    FBGetSelectedModels(models)

    system = FBSystem()
    app = FBApplication()

    # check if there is a selection
    if len( models ) == 0:
        FBMessageBox( "Message", "Please select a Biped joint.", "OK", None, None )
    elif len( models ) > 1:
        # Only one biped joint must be selected else we can have problems if joints belongs to different bipeds.
        FBMessageBox( "Message", "Only one Biped joint must be selected.", "OK", None, None )
    else:
        # Extract the name of the model including its namespace
        longname = models[0].LongName
        namespaceindex = longname.rfind(":")
        if namespaceindex != -1:
            namespace = longname[0:namespaceindex+1]
            name = longname[namespaceindex + 1:]
        else:
            namespace = ""
            name = longname

        # If in Biped mode, extract the character prefix name
        bipednameprefix = ""
        if useBipedPrefixNamingScheme:
            splitname = name.split()
            bipednameprefix = splitname[0] + " "
            # Override the rootname so it is the character orefix name            
            rootname = splitname[0]

        myBiped = FBCharacter("mycharacter")
        myBiped.LongName = namespace + rootname
        app.CurrentCharacter = myBiped

        # Create a FBProgress object and set default values for the caption and text.    
        fbp = FBProgress()
        fbp.Caption = ""
        fbp.Text = " -----------------------------------   Creating Biped character"
        progress = 0.0
        progresssteps = len(boneMap)

        # assign Biped to Character Mapping.
        for pslot, pjointName in boneMap.iteritems():
            if not pjointName:
                addJointToCharacter (myBiped, pslot, namespace + rootname)
            else:
                addJointToCharacter (myBiped, pslot, namespace + bipednameprefix + pjointName)
            progress += 1
            val = progress / len(boneMap)  * 100
            fbp.Percent = int(val)

        switchOn = myBiped.SetCharacterizeOn( True )
        print "Character mapping created for " + (myBiped.LongName)

        # We must call FBDelete when the FBProgress object is no longer needed.
        fbp.FBDelete()


# Call the Characterize Character Function with all bipeds defined variables.
Characterize(bipedrootname, bipedPrefixNamingScheme, bipedMap)