Skip to content
Snippets Groups Projects
io_import_scene_mhx.py 67.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • Brendon Murphy's avatar
    Brendon Murphy committed
    """ 
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    **Project Name:**      MakeHuman
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    **Product Home Page:** http://www.makehuman.org/
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    **Code Home Page:**    http://code.google.com/p/makehuman/
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    **Authors:**           Thomas Larsson
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    **Copyright(c):**      MakeHuman Team 2001-2010
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    **Licensing:**         GPL3 (see also http://sites.google.com/site/makehumandocs/licensing)
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    **Coding Standards:**  See http://sites.google.com/site/makehumandocs/developers-guide
    
    Abstract
    MHX (MakeHuman eXchange format) importer for Blender 2.5x.
    
    bl_info = {
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        'name': 'Import: MakeHuman (.mhx)',
        'author': 'Thomas Larsson',
    
        'version': (1, 0, 4),
        'blender': (2, 5, 6),
        'api': 34326,
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        'location': "File > Import",
        'description': 'Import files in the MakeHuman eXchange format (.mhx)',
        'warning': '',
        'wiki_url': 'http://wiki.blender.org/index.php/Extensions:2.5/Py/'\
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            'Scripts/Import-Export/Make_Human',
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        'tracker_url': 'https://projects.blender.org/tracker/index.php?'\
    
            'func=detail&aid=21872',
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        'category': 'Import-Export'}
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    """
    Place this file in the .blender/scripts/addons dir
    You have to activated the script in the "Add-Ons" tab (user preferences).
    Access from the File > Import menu.
    """
    
    
    MAJOR_VERSION = 1
    MINOR_VERSION = 0
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    #
    #
    
    import bpy
    import os
    import time
    import mathutils
    from mathutils import *
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #import geometry
    #import string
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    MHX249 = False
    Blender24 = False
    Blender25 = True
    TexDir = "~/makehuman/exports"
    
    #
    #
    #
    
    theScale = 1.0
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    useMesh = 1
    verbosity = 2
    warnedTextureDir = False
    warnedVersion = False
    
    true = True
    false = False
    Epsilon = 1e-6
    nErrors = 0
    theTempDatum = None
    
    todo = []
    
    #
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    toggle flags
    
    T_EnforceVersion = 0x01
    T_Clothes = 0x02
    T_Stretch = 0x04
    T_Bend = 0x08
    
    T_Diamond = 0x10
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    T_Replace = 0x20
    T_Face = 0x40
    T_Shape = 0x80
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    T_Mesh = 0x100
    T_Armature = 0x200
    T_Proxy = 0x400
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    T_Rigify = 0x1000
    T_Preset = 0x2000
    T_Symm = 0x4000
    T_MHX = 0x8000
    
    
    toggle = T_EnforceVersion + T_Replace + T_Mesh + T_Armature + T_Face + T_Shape + T_Proxy + T_Clothes
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    setFlagsAndFloats(rigFlags):
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    Global floats
    
    #fFingerPanel = 0.0
    #fFingerIK = 0.0
    fNoStretch = 0.0
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    rigLeg and rigArm flags
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    T_Toes = 0x0001
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    #T_InvFoot = 0x0010
    #T_InvFootPT = 0x0020
    #T_InvFootNoPT = 0x0040
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    #T_FingerPanel = 0x100
    #T_FingerRot = 0x0200
    #T_FingerIK = 0x0400
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        '''
        global toggle, rigLeg, rigArm
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        (footRig, fingerRig) = rigFlags
        rigLeg = 0
        if footRig == 'Reverse foot': 
            rigLeg |= T_InvFoot
            if toggle & T_PoleTar:
                rigLeg |= T_InvFootPT
            else:
                rigLeg |= T_InvFootNoPT
        elif footRig == 'Gobo': rigLeg |= T_GoboFoot        
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        rigArm = 0
        if fingerRig == 'Panel': rigArm |= T_FingerPanel
        elif fingerRig == 'Rotation': rigArm |= T_FingerRot
        elif fingerRig == 'IK': rigArm |= T_FingerIK
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        toggle |= T_Panel
        '''
        global fNoStretch
        if toggle&T_Stretch: fNoStretch == 0.0
        else: fNoStretch = 1.0
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        return
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    Dictionaries
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    loadedData = {
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        'NONE' : {},
    
        'Object' : {},
        'Mesh' : {},
        'Armature' : {},
        'Lamp' : {},
        'Camera' : {},
        'Lattice' : {},
        'Curve' : {},
        'Text' : {},
    
        'Material' : {},
        'Image' : {},
        'MaterialTextureSlot' : {},
        'Texture' : {},
        
        'Bone' : {},
        'BoneGroup' : {},
        'Rigify' : {},
    
        'Action' : {},
        'Group' : {},
    
        'MeshTextureFaceLayer' : {},
        'MeshColorLayer' : {},
        'VertexGroup' : {},
        'ShapeKey' : {},
        'ParticleSystem' : {},
    
        'ObjectConstraints' : {},
        'ObjectModifiers' : {},
        'MaterialSlot' : {},
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    }
    
    Plural = {
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        'Object' : 'objects',
        'Mesh' : 'meshes',
        'Lattice' : 'lattices',
        'Curve' : 'curves',
        'Text' : 'texts',
        'Group' : 'groups',
        'Empty' : 'empties',
        'Armature' : 'armatures',
        'Bone' : 'bones',
        'BoneGroup' : 'bone_groups',
        'Pose' : 'poses',
        'PoseBone' : 'pose_bones',
        'Material' : 'materials',
        'Texture' : 'textures',
        'Image' : 'images',
        'Camera' : 'cameras',
        'Lamp' : 'lamps',
        'World' : 'worlds',
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    checkBlenderVersion()
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        print("Found Blender", bpy.app.version)
        (A, B, C) = bpy.app.version
        (a, b, c) = BLENDER_VERSION
        if a <= A: return
        if b <= B: return
        if c <= C: return
        msg = (
    
    "This version of the MHX importer only works with Blender (%d, %d, %d) or later. " % (a, b, c) +
    "Download a more recent Blender from www.blender.org or www.graphicall.org.\n"
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        )
        raise NameError(msg)
        return
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    readMhxFile(filePath, scale):
    
    #
    
    def readMhxFile(filePath, scale):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        global todo, nErrors, theScale, defaultScale, One, toggle
    
        checkBlenderVersion()    
        
        theScale = scale
        defaultScale = scale
        One = 1.0/theScale
    
        fileName = os.path.expanduser(filePath)
        (shortName, ext) = os.path.splitext(fileName)
        if ext.lower() != ".mhx":
            print("Error: Not a mhx file: " + fileName)
            return
        print( "Opening MHX file "+ fileName )
        time1 = time.clock()
    
        ignore = False
        stack = []
        tokens = []
        key = "toplevel"
        level = 0
        nErrors = 0
        comment = 0
        nesting = 0
    
        setFlagsAndFloats()
    
        file= open(fileName, "rU")
        print( "Tokenizing" )
        lineNo = 0
        for line in file: 
            # print(line)
            lineSplit= line.split()
            lineNo += 1
            if len(lineSplit) == 0:
                pass
            elif lineSplit[0][0] == '#':
                if lineSplit[0] == '#if':
                    if comment == nesting:
                        try:
                            res = eval(lineSplit[1])
                        except:
                            res = False
                        if res:
                            comment += 1
                    nesting += 1
                elif lineSplit[0] == '#else':
                    if comment == nesting-1:
                        comment += 1
                    elif comment == nesting:
                        comment -= 1
                elif lineSplit[0] == '#endif':
                    if comment == nesting:
                        comment -= 1
                    nesting -= 1
            elif comment < nesting:
                pass
            elif lineSplit[0] == 'end':
                try:
                    sub = tokens
                    tokens = stack.pop()
                    if tokens:
                        tokens[-1][2] = sub
                    level -= 1
                except:
                    print( "Tokenizer error at or before line %d" % lineNo )
                    print( line )
                    dummy = stack.pop()
            elif lineSplit[-1] == ';':
                if lineSplit[0] == '\\':
                    key = lineSplit[1]
                    tokens.append([key,lineSplit[2:-1],[]])
                else:
                    key = lineSplit[0]
                    tokens.append([key,lineSplit[1:-1],[]])
            else:
                key = lineSplit[0]
                tokens.append([key,lineSplit[1:],[]])
                stack.append(tokens)
                level += 1
                tokens = []
        file.close()
    
        if level != 0:
            raise NameError("Tokenizer out of kilter %d" % level)    
        clearScene()
        print( "Parsing" )
        parse(tokens)
        
        for (expr, glbals, lcals) in todo:
            try:
                print("Doing %s" % expr)
                exec(expr, glbals, lcals)
            except:
                msg = "Failed: "+expr
                print( msg )
                nErrors += 1
                #raise NameError(msg)
    
        print("Postprocess")
        postProcess()
        print("HideLayers")
        hideLayers()
        time2 = time.clock()
        print("toggle = %x" % toggle)
        msg = "File %s loaded in %g s" % (fileName, time2-time1)
        if nErrors:
            msg += " but there where %d errors. " % (nErrors)
        print(msg)
        return
    
    #
    #    getObject(name, var, glbals, lcals):
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    def getObject(name, var, glbals, lcals):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        try:
            ob = loadedData['Object'][name]
        except:
            if name != "None":
                pushOnTodoList(None, "ob = loadedData['Object'][name]" % globals(), locals())
            ob = None
        return ob
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    checkMhxVersion(major, minor):
    
    #
    
    def checkMhxVersion(major, minor):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        global warnedVersion
        if  major != MAJOR_VERSION or minor != MINOR_VERSION:
            if warnedVersion:
                return
            else:
                msg = (
    
    "Wrong MHX version\n" +
    "Expected MHX %d.%d but the loaded file has version MHX %d.%d\n" % (MAJOR_VERSION, MINOR_VERSION, major, minor) +
    "You can disable this error message by deselecting the Enforce version option when importing. " +
    "Alternatively, you can try to download the most recent nightly build from www.makehuman.org. " +
    "The current version of the import script is located in the importers/mhx/blender25x folder and is called import_scene_mhx.py. " +
    "The version distributed with Blender builds from www.graphicall.org may be out of date.\n"
    )
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            if toggle & T_EnforceVersion:
                raise NameError(msg)
            else:
                print(msg)
                warnedVersion = True
        return
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    parse(tokens):
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    ifResult = False
    
    def parse(tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        global MHX249, ifResult, theScale, defaultScale, One
        
        for (key, val, sub) in tokens:    
            # print("Parse %s" % key)
            data = None
            if key == 'MHX':
                checkMhxVersion(int(val[0]), int(val[1]))
            elif key == 'MHX249':
                MHX249 = eval(val[0])
                print("Blender 2.49 compatibility mode is %s\n" % MHX249)
            elif MHX249:
                pass
            elif key == 'print':
                msg = concatList(val)
                print(msg)
            elif key == 'warn':
                msg = concatList(val)
                print(msg)
            elif key == 'error':
                msg = concatList(val)
                raise NameError(msg)    
            elif key == 'NoScale':
                if eval(val[0]):
                    theScale = 1.0
                else:
                    theScale = defaultScale        
                One = 1.0/theScale
            elif key == "Object":
                parseObject(val, sub)
            elif key == "Mesh":
                data = parseMesh(val, sub)
            elif key == "Armature":
                data = parseArmature(val, sub)
            elif key == "Pose":
                data = parsePose(val, sub)
            elif key == "Action":
                data = parseAction(val, sub)
            elif key == "Material":
                data = parseMaterial(val, sub)
            elif key == "Texture":
                data = parseTexture(val, sub)
            elif key == "Image":
                data = parseImage(val, sub)
            elif key == "Curve":
                data = parseCurve(val, sub)
            elif key == "TextCurve":
                data = parseTextCurve(val, sub)
            elif key == "Lattice":
                data = parseLattice(val, sub)
            elif key == "Group":
                data = parseGroup(val, sub)
            elif key == "Lamp":
                data = parseLamp(val, sub)
            elif key == "World":
                data = parseWorld(val, sub)
            elif key == "Scene":
                data = parseScene(val, sub)
            elif key == "Process":
                parseProcess(val, sub)
            elif key == 'AnimationData':
                try:
                    ob = loadedData['Object'][val[0]]
                except:
                    ob = None
                if ob:
                    bpy.context.scene.objects.active = ob
                    parseAnimationData(ob, val, sub)
            elif key == 'MaterialAnimationData':
                try:
                    ob = loadedData['Object'][val[0]]
                except:
                    ob = None
                if ob:
                    bpy.context.scene.objects.active = ob
                    mat = ob.data.materials[int(val[2])]
                    print("matanim", ob, mat)
                    parseAnimationData(mat, val, sub)
            elif key == 'ShapeKeys':
                try:
                    ob = loadedData['Object'][val[0]]
                except:
                    raise NameError("ShapeKeys object %s does not exist" % val[0])
                if ob:
                    bpy.context.scene.objects.active = ob
                    parseShapeKeys(ob, ob.data, val, sub)
            else:
                data = parseDefaultType(key, val, sub)                
    
            if data and key != 'Mesh':
                print( data )
        return
    
    #
    #    parseDefaultType(typ, args, tokens):
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    def parseDefaultType(typ, args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        global todo
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        name = args[0]
        data = None
        expr = "bpy.data.%s.new('%s')" % (Plural[typ], name)
        print(expr)
        data = eval(expr)
        print("  ok", data)
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        bpyType = typ.capitalize()
        print(bpyType, name, data)
        loadedData[bpyType][name] = data
        if data == None:
            return None
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        for (key, val, sub) in tokens:
            #print("%s %s" % (key, val))
            defaultKey(key, val, sub, 'data', [], globals(), locals())
        print("Done ", data)
        return data
        
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    concatList(elts)
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    def concatList(elts):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        string = ""
        for elt in elts:
            string += " %s" % elt
        return string
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    parseAction(args, tokens):
    #    parseFCurve(fcu, args, tokens):
    #    parseKeyFramePoint(pt, args, tokens):
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    def parseAction(args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        name = args[0]
        if invalid(args[1]):
            return
    
        ob = bpy.context.object
        bpy.ops.object.mode_set(mode='POSE')
        if ob.animation_data:
            ob.animation_data.action = None
        created = {}
        for (key, val, sub) in tokens:
            if key == 'FCurve':
                prepareActionFCurve(ob, created, val, sub)
            
        act = ob.animation_data.action
        loadedData['Action'][name] = act
        if act == None:
            print("Ignoring action %s" % name)
            return act
        act.name = name
        print("Action", name, act, ob)
        
        for (key, val, sub) in tokens:
            if key == 'FCurve':
                fcu = parseActionFCurve(act, ob, val, sub)
            else:
                defaultKey(key, val, sub, 'act', [], globals(), locals())
        ob.animation_data.action = None
        bpy.ops.object.mode_set(mode='OBJECT')
        return act
    
    def prepareActionFCurve(ob, created, args, tokens):            
        dataPath = args[0]
        index = args[1]
        (expr, channel) = channelFromDataPath(dataPath, index)
        try:
            if channel in created[expr]:
                return
            else:
                created[expr].append(channel)
        except:
            created[expr] = [channel]
    
        times = []
        for (key, val, sub) in tokens:
            if key == 'kp':
                times.append(int(val[0]))
    
        try:
            data = eval(expr)
        except:
            print("Ignoring illegal expression: %s" % expr)
            return
    
        n = 0
        for t in times:
            #bpy.context.scene.current_frame = t
            bpy.ops.anim.change_frame(frame = t)
            try:
                data.keyframe_insert(channel)
                n += 1
            except:
                pass
                #print("failed", data, expr, channel)
        if n != len(times):
            print("Mismatch", n, len(times), expr, channel)
        return
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    def channelFromDataPath(dataPath, index):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        words = dataPath.split(']')
        if len(words) == 1:
            # location
            expr = "ob"
            channel = dataPath
        elif len(words) == 2:
            # pose.bones["tongue"].location
            expr = "ob.%s]" % (words[0])
            cwords = words[1].split('.')
            channel = cwords[1]
        elif len(words) == 3:
            # pose.bones["brow.R"]["mad"]
            expr = "ob.%s]" % (words[0])
            cwords = words[1].split('"')
            channel = cwords[1]
        # print(expr, channel, index)
        return (expr, channel)
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    def parseActionFCurve(act, ob, args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        dataPath = args[0]
        index = args[1]
        (expr, channel) = channelFromDataPath(dataPath, index)
        index = int(args[1])
    
        success = False
        for fcu in act.fcurves:
            (expr1, channel1) = channelFromDataPath(fcu.data_path, fcu.array_index)
            if expr1 == expr and channel1 == channel and fcu.array_index == index:
                success = True
                break
        if not success:
            return None
    
        n = 0
        for (key, val, sub) in tokens:
            if key == 'kp':
                try:
                    pt = fcu.keyframe_points[n]
                    pt.interpolation = 'LINEAR'
                    pt = parseKeyFramePoint(pt, val, sub)
                    n += 1
                except:
                    pass
                    #print(tokens)
                    #raise NameError("kp", fcu, n, len(fcu.keyframe_points), val)
            else:
                defaultKey(key, val, sub, 'fcu', [], globals(), locals())
        return fcu
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    def parseKeyFramePoint(pt, args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        pt.co = (float(args[0]), float(args[1]))
        if len(args) > 2:
            pt.handle1 = (float(args[2]), float(args[3]))
            pt.handle2 = (float(args[3]), float(args[5]))
        return pt
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    parseAnimationData(rna, args, tokens):
    #    parseDriver(drv, args, tokens):
    #    parseDriverVariable(var, args, tokens):
    
    #
    
    def parseAnimationData(rna, args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        if not eval(args[1]):
            return
        if rna.animation_data == None:    
            rna.animation_data_create()
        adata = rna.animation_data
        for (key, val, sub) in tokens:
            if key == 'FCurve':
                fcu = parseAnimDataFCurve(adata, rna, val, sub)
            else:
                defaultKey(key, val, sub, 'adata', [], globals(), locals())
        return adata
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    def parseAnimDataFCurve(adata, rna, args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        if invalid(args[2]):
            return
        dataPath = args[0]
        index = int(args[1])
        # print("parseAnimDataFCurve", adata, dataPath, index)
        n = 1
        for (key, val, sub) in tokens:
            if key == 'Driver':
                fcu = parseDriver(adata, dataPath, index, rna, val, sub)
                fmod = fcu.modifiers[0]
                fcu.modifiers.remove(fmod)
            elif key == 'FModifier':
                parseFModifier(fcu, val, sub)
            elif key == 'kp':
    
                pt = fcu.keyframe_points.insert(n, 0)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                pt.interpolation = 'LINEAR'
                pt = parseKeyFramePoint(pt, val, sub)
                n += 1
            else:
                defaultKey(key, val, sub, 'fcu', [], globals(), locals())
        return fcu
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    """
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            fcurve = con.driver_add("influence", 0)
            driver = fcurve.driver
            driver.type = 'AVERAGE'
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    """
    def parseDriver(adata, dataPath, index, rna, args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        if dataPath[-1] == ']':
            words = dataPath.split(']')
            expr = "rna." + words[0] + ']'
            pwords = words[1].split('"')
            prop = pwords[1]
            # print("prop", expr, prop)
            bone = eval(expr)
            return None
        else:
            words = dataPath.split('.')
            channel = words[-1]
            expr = "rna"
            for n in range(len(words)-1):
                expr += "." + words[n]
            expr += ".driver_add('%s', index)" % channel
        
        #print("expr", rna, expr)
        fcu = eval(expr)
        drv = fcu.driver
        drv.type = args[0]
        for (key, val, sub) in tokens:
            if key == 'DriverVariable':
                var = parseDriverVariable(drv, rna, val, sub)
            else:
                defaultKey(key, val, sub, 'drv', [], globals(), locals())
        return fcu
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    def parseDriverVariable(drv, rna, args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        var = drv.variables.new()
        var.name = args[0]
        var.type = args[1]
        nTarget = 0
        # print("var", var, var.name, var.type)
        for (key, val, sub) in tokens:
            if key == 'Target':
                parseDriverTarget(var, nTarget, rna, val, sub)
                nTarget += 1
            else:
                defaultKey(key, val, sub, 'var', [], globals(), locals())
        return var
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    def parseFModifier(fcu, args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        fmod = fcu.modifiers.new(args[0])
        #fmod = fcu.modifiers[0]
        for (key, val, sub) in tokens:
            defaultKey(key, val, sub, 'fmod', [], globals(), locals())
        return fmod
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    """
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            var = driver.variables.new()
            var.name = target_bone
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = obj
            var.targets[0].rna_path = driver_path
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    """
    def parseDriverTarget(var, nTarget, rna, args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        targ = var.targets[nTarget]
        targ.id = loadedData['Object'][args[0]]
        for (key, val, sub) in tokens:
            defaultKey(key, val, sub, 'targ', [], globals(), locals())
        return targ
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    parseMaterial(args, ext, tokens):
    #    parseMTex(mat, args, tokens):
    #    parseTexture(args, tokens):
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    
    def parseMaterial(args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        global todo
        name = args[0]
        mat = bpy.data.materials.new(name)
        if mat == None:
            return None
        loadedData['Material'][name] = mat
        for (key, val, sub) in tokens:
            if key == 'MTex':
                parseMTex(mat, val, sub)
            elif key == 'Ramp':
                parseRamp(mat, val, sub)
            elif key == 'RaytraceTransparency':
                parseDefault(mat.raytrace_transparency, sub, {}, [])
            elif key == 'Halo':
                parseDefault(mat.halo, sub, {}, [])
            elif key == 'SSS':
                parseDefault(mat.subsurface_scattering, sub, {}, [])
            elif key == 'Strand':
                parseDefault(mat.strand, sub, {}, [])
            elif key == 'NodeTree':
                mat.use_nodes = True
                parseNodeTree(mat.node_tree, val, sub)
            else:
                exclude = ['specular_intensity', 'tangent_shading']
                defaultKey(key, val, sub, 'mat', [], globals(), locals())
        
        return mat
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    def parseMTex(mat, args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        global todo
        index = int(args[0])
        texname = args[1]
        texco = args[2]
        mapto = args[3]
        tex = loadedData['Texture'][texname]
        mtex = mat.texture_slots.add()
        mtex.texture_coords = texco
        mtex.texture = tex
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        for (key, val, sub) in tokens:
            defaultKey(key, val, sub, "mtex", [], globals(), locals())
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        return mtex
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    def parseTexture(args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        global todo
        if verbosity > 2:
            print( "Parsing texture %s" % args )
        name = args[0]
        tex = bpy.data.textures.new(name=name, type=args[1])
        loadedData['Texture'][name] = tex
        
        for (key, val, sub) in tokens:
            if key == 'Image':
                try:
                    imgName = val[0]
                    img = loadedData['Image'][imgName]
                    tex.image = img
                except:
                    msg = "Unable to load image '%s'" % val[0]
            elif key == 'Ramp':
                parseRamp(tex, val, sub)
            elif key == 'NodeTree':
                tex.use_nodes = True
                parseNodeTree(tex.node_tree, val, sub)
            else:
                defaultKey(key, val,  sub, "tex", ['use_nodes', 'use_textures', 'contrast'], globals(), locals())
    
        return tex
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    def parseRamp(data, args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        nvar = "data.%s" % args[0]
        use = "data.use_%s = True" % args[0]
        exec(use)
        ramp = eval(nvar)
        elts = ramp.elements
        n = 0
        for (key, val, sub) in tokens:
            # print("Ramp", key, val)
            if key == 'Element':
                elts[n].color = eval(val[0])
                elts[n].position = eval(val[1])
                n += 1
            else:
                defaultKey(key, val,  sub, "tex", ['use_nodes', 'use_textures', 'contrast'], globals(), locals())
        
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    def parseSSS(mat, args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        sss = mat.subsurface_scattering
        for (key, val, sub) in tokens:
            defaultKey(key, val, sub, "sss", [], globals(), locals())
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    def parseStrand(mat, args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        strand = mat.strand
        for (key, val, sub) in tokens:
            defaultKey(key, val, sub, "strand", [], globals(), locals())
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    parseNodeTree(tree, args, tokens):
    #    parseNode(node, args, tokens):
    #    parseSocket(socket, args, tokens):
    
    #
    
    def parseNodeTree(tree, args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        return
        print("Tree", tree, args)
        print(list(tree.nodes))
        tree.name = args[0]
        for (key, val, sub) in tokens:
            if key == 'Node':
                parseNodes(tree.nodes, val, sub)
            else:
                defaultKey(key, val, sub, "tree", [], globals(), locals())
    
    
    def parseNodes(nodes, args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        print("Nodes", nodes, args)
        print(list(nodes))
        node.name = args[0]
        for (key, val, sub) in tokens:
            if key == 'Inputs':
                parseSocket(node.inputs, val, sub)
            elif key == 'Outputs':
                parseSocket(node.outputs, val, sub)
            else:
                defaultKey(key, val, sub, "node", [], globals(), locals())
    
    
    def parseNode(node, args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        print("Node", node, args)
        print(list(node.inputs), list(node.outputs))
        node.name = args[0]
        for (key, val, sub) in tokens:
            if key == 'Inputs':
                parseSocket(node.inputs, val, sub)
            elif key == 'Outputs':
                parseSocket(node.outputs, val, sub)
            else:
                defaultKey(key, val, sub, "node", [], globals(), locals())
    
    
    def parseSocket(socket, args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        print("Socket", socket, args)
        socket.name = args[0]
        for (key, val, sub) in tokens:
            if key == 'Node':
                parseNode(tree.nodes, val, sub)
            else:
                defaultKey(key, val, sub, "tree", [], globals(), locals())
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    doLoadImage(filepath):
    #    loadImage(filepath):
    #    parseImage(args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    def doLoadImage(filepath):        
        path1 = os.path.expanduser(filepath)
        file1 = os.path.realpath(path1)
        if os.path.isfile(file1):
            print( "Found file "+file1 )
            try:
                img = bpy.data.images.load(file1)
                return img
            except:
                print( "Cannot read image" )
                return None
        else:
            print( "No file "+file1 )
            return None
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    def loadImage(filepath):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        global TexDir, warnedTextureDir, loadedData
    
        texDir = os.path.expanduser(TexDir)
        path1 = os.path.expanduser(filepath)
        file1 = os.path.realpath(path1)
        (path, filename) = os.path.split(file1)
        (name, ext) = os.path.splitext(filename)
        print( "Loading ", filepath, " = ", filename )
    
        # img = doLoadImage(texDir+"/"+name+".png")
        # if img:
        #    return img
    
        img = doLoadImage(texDir+"/"+filename)
        if img:
            return img
    
        # img = doLoadImage(path+"/"+name+".png")
        # if img:
        #    return img
    
        img = doLoadImage(path+"/"+filename)
        if img:
            return img
    
        if warnedTextureDir:
            return None
        warnedTextureDir = True
        return None
        TexDir = Draw.PupStrInput("TexDir? ", path, 100)
    
        texDir = os.path.expanduser(TexDir)
        img =  doLoadImage(texDir+"/"+name+".png")
        if img:
            return img
    
        img = doLoadImage(TexDir+"/"+filename)
        return img
        
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    def parseImage(args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        global todo
        imgName = args[0]
        img = None
        for (key, val, sub) in tokens:
            if key == 'Filename':
                filename = val[0]
                for n in range(1,len(val)):
                    filename += " " + val[n]
                img = loadImage(filename)
                if img == None: