Skip to content
Snippets Groups Projects
io_import_scene_mhx.py 132 KiB
Newer Older
  • Learn to ignore specific revisions
  • # ##### BEGIN GPL LICENSE BLOCK #####
    #
    #  This program is free software; you can redistribute it and/or
    #  modify it under the terms of the GNU General Public License
    #  as published by the Free Software Foundation; either version 2
    #  of the License, or (at your option) any later version.
    #
    #  This program is distributed in the hope that it will be useful,
    #  but WITHOUT ANY WARRANTY; without even the implied warranty of
    #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #  GNU General Public License for more details.
    #  You should have received a copy of the GNU General Public License
    
    #  along with this program; if not, write to the Free Software Foundation,
    #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
    #
    # ##### END GPL LICENSE BLOCK #####
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    # Project Name:        MakeHuman
    # Product Home Page:   http://www.makehuman.org/
    # Code Home Page:      http://code.google.com/p/makehuman/
    # Authors:             Thomas Larsson
    
    # Script copyright (C) MakeHuman Team 2001-2013
    # Coding Standards: See http://www.makehuman.org/node/165
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    Abstract
    MHX (MakeHuman eXchange format) importer for Blender 2.5x.
    
    
    This script should be distributed with Blender.
    If not, place it in the .blender/scripts/addons dir
    
    Activate the script in the "Addons" tab (user preferences).
    
    Access from the File > Import menu.
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Alternatively, run the script in the script editor (Alt-P), and access from the File > Import menu
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    """
    
    
    bl_info = {
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        'name': 'Import: MakeHuman (.mhx)',
        'author': 'Thomas Larsson',
    
        'version': (1, 15, 1),
    
    Thomas Larsson's avatar
    Thomas Larsson committed
        "blender": (2, 65, 0),
    
        'location': "File > Import > MakeHuman (.mhx)",
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        'description': 'Import files in the MakeHuman eXchange format (.mhx)',
        'warning': '',
    
        'wiki_url': 'http://sites.google.com/site/makehumandocs/blender-export-and-mhx',
    
    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'}
    
    MINOR_VERSION = 15
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    #
    #
    #
    
    import bpy
    import os
    import time
    
    from bpy.props import *
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    MHX249 = False
    Blender24 = False
    Blender25 = True
    
    theDir = "~/makehuman/exports"
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    #
    #
    #
    
    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
    
    theMessage = ""
    theMhxFile = ""
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    todo = []
    
    #
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    toggle flags
    
    T_EnforceVersion = 0x01
    T_Clothes = 0x02
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    T_Replace = 0x20
    
    T_Shapekeys = 0x40
    T_ShapeDrivers = 0x80
    
    T_Face = T_Shapekeys
    T_Shape = T_Shapekeys
    
    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
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    T_Symm = 0x4000
    
    
    DefaultToggle = ( T_EnforceVersion + T_Mesh + T_Armature + 
    
        T_Shapekeys + T_ShapeDrivers + T_Proxy + T_Clothes + T_Rigify )
    
        
    toggle = DefaultToggle
    toggleSettings = toggle
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    #    Dictionaries
    
    def initLoadedData():
        global loadedData
    
        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' : {},
    
        }
        return
        
    def reinitGlobalData():
        global loadedData
        for key in [
            'MeshTextureFaceLayer', 'MeshColorLayer', 'VertexGroup', 'ShapeKey',
            'ParticleSystem', 'ObjectConstraints', 'ObjectModifiers', 'MaterialSlot']:
            loadedData[key] = {}
        return
    
    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',
    
        global todo, nErrors, theScale, theArmature, defaultScale, One
    
        global toggle, warnedVersion, theMessage, alpha7, theDir
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        One = 1.0/theScale
    
        theArmature = None
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
        theDir = os.path.dirname(filePath)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        fileName = os.path.expanduser(filePath)
    
        _,ext = os.path.splitext(fileName)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        if ext.lower() != ".mhx":
    
            print("Error: Not a mhx file: %s" % fileName.encode('utf-8', 'strict'))
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            return
    
        print( "Opening MHX file %s " % fileName.encode('utf-8', 'strict') )
        print("Toggle %x" % toggle)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        time1 = time.clock()
    
    
    Campbell Barton's avatar
    Campbell Barton committed
        # ignore = False  # UNUSED
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        stack = []
        tokens = []
        key = "toplevel"
        level = 0
        nErrors = 0
        comment = 0
        nesting = 0
    
        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.\nThe mhx file has been corrupted.\nTry to export it again from MakeHuman." % lineNo )
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    print( line )
    
    Campbell Barton's avatar
    Campbell Barton committed
                    stack.pop()
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            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:
    
            MyError("Tokenizer error (%d).\nThe mhx file has been corrupted.\nTry to export it again from MakeHuman." % level)    
    
        scn = clearScene()
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        print( "Parsing" )
        parse(tokens)
        
        for (expr, glbals, lcals) in todo:
            try:
                print("Doing %s" % expr)
                exec(expr, glbals, lcals)
            except:
    
                msg = "Failed: %s\n" % expr
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                print( msg )
                nErrors += 1
    
                #MyError(msg)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
    
        theArmature.MhAlpha8 = not alpha7
        #bpy.ops.wm.properties_edit(data_path="object", property="MhxRig", value=theArmature["MhxRig"])
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        time2 = time.clock()
        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
    
        print("MHX", (major,minor), (MAJOR_VERSION, MINOR_VERSION), warnedVersion)
    
        if  major != MAJOR_VERSION or minor < FROM_VERSION:
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            if warnedVersion:
                return
            else:
                msg = (
    
    "Expected MHX %d.%02d but the loaded file " % (MAJOR_VERSION, MINOR_VERSION) +
    "has version MHX %d.%02d\n" % (major, minor))
    
    "You can disable this error message by deselecting the \n" +
    
    "Enforce version option when importing. Better:\n" +
    "Export the MHX file again with an updated version of MakeHuman.\n" +
    "The most up-to-date version of MakeHuman is the nightly build.\n")
                else:
                    msg += (
    "Download the most recent Blender build from www.graphicall.org. \n" +
    
    "The most up-to-date version of the import script is distributed\n" +
    
    "with Blender. It can also be downloaded from MakeHuman. \n" +
    
    "It is located in the importers/mhx/blender25x \n" +
    
    "folder and is called import_scene_mhx.py. \n")
            if (toggle & T_EnforceVersion or minor > MINOR_VERSION):
    
                MyError(msg)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            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: 
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            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)
    
                MyError(msg)    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            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":
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                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 == "DefineProperty":
                parseDefineProperty(val, sub)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            elif key == "Process":
                parseProcess(val, sub)
    
            elif key == "PostProcess":
                postProcess(val)
                hideLayers(val)
            elif key == "CorrectRig":
                correctRig(val)
    
            elif key == "Rigify":
                if toggle & T_Rigify:
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            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])]
                    parseAnimationData(mat, val, sub)
            elif key == 'ShapeKeys':
                try:
                    ob = loadedData['Object'][val[0]]
                except:
    
                    MyError("ShapeKeys object %s does not exist" % val[0])
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                if ob:
                    bpy.context.scene.objects.active = ob
    
                    parseShapeKeys(ob, ob.data, val, sub)        
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            else:
                data = parseDefaultType(key, val, sub)                
    
    #
    #    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)
        data = eval(expr)
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        bpyType = typ.capitalize()
        loadedData[bpyType][name] = data
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            return None
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        for (key, val, sub) in tokens:
            defaultKey(key, val, sub, 'data', [], globals(), locals())
        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
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            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]
        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)
    
                    #MyError("kp", fcu, n, len(fcu.keyframe_points), val)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            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 is None:    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            rna.animation_data_create()
        adata = rna.animation_data
        for (key, val, sub) in tokens:
            if key == 'FCurve':
    
                fcu = parseAnimDataFCurve(adata, rna, val, sub)            
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            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])
        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]
            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
        
        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
        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]
    
        name = args[0]
        #targ.id_type = args[1]
        dtype = args[1].capitalize()
        dtype = 'Object'
        targ.id = loadedData[dtype][name]
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        for (key, val, sub) in tokens:
    
            if key == 'data_path':
                words = val[0].split('"')
                if len(words) > 1:
                    targ.data_path = propNames(words[1])[1]
                else:
                    targ.data_path = propNames(val)[1]
            else:
                defaultKey(key, val, sub, 'targ', [], globals(), locals())
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        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)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            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)
    
            elif key == 'AnimationData':
                parseAnimationData(mat, val, sub)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            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', 'use_alpha'], globals(), locals())
    
    Luca Bonavita's avatar
    Luca Bonavita committed
    
        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
    #    loadImage(filepath):
    #    parseImage(args, tokens):
    
    def loadImage(relFilepath):
        filepath = os.path.normpath(os.path.join(theDir, relFilepath))
        print( "Loading %s" % filepath.encode('utf-8','strict'))
        if os.path.isfile(filepath):
            #print( "Found file %s." % filepath.encode('utf-8','strict') )
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            try:
    
                img = bpy.data.images.load(filepath)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                return img
            except:
                print( "Cannot read image" )
                return None
        else:
    
            print( "No such file: %s" % filepath.encode('utf-8','strict') )
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            return None
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        
    
    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)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    return None
                img.name = imgName
            else:
    
                defaultKey(key, val,  sub, "img", ['depth', 'dirty', 'has_data', 'size', 'type', 'use_premultiply'], globals(), locals())
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        print ("Image %s" % img )
        loadedData['Image'][imgName] = img
        return img
    
    #
    #    parseObject(args, tokens):
    #    createObject(type, name, data, datName):
    #    setObjectAndData(args, typ):
    #
        
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    def parseObject(args, tokens):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        if verbosity > 2:
            print( "Parsing object %s" % args )
        name = args[0]
        typ = args[1]
        datName = args[2]
    
        if typ == 'EMPTY':
            ob = bpy.data.objects.new(name, None)
            loadedData['Object'][name] = ob
            linkObject(ob, None)
        else:
            try:
                data = loadedData[typ.capitalize()][datName]    
            except:
    
                MyError("Failed to find data: %s %s %s" % (name, typ, datName))
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                return
    
        try:
            ob = loadedData['Object'][name]
            bpy.context.scene.objects.active = ob
            #print("Found data", ob)
        except:
            ob = None
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            ob = createObject(typ, name, data, datName)
            linkObject(ob, data)
    
        for (key, val, sub) in tokens:
            if key == 'Modifier':
                parseModifier(ob, val, sub)
            elif key == 'Constraint':
    
                parseConstraint(ob.constraints, None, val, sub)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            elif key == 'AnimationData':
                parseAnimationData(ob, val, sub)
            elif key == 'ParticleSystem':
                parseParticleSystem(ob, val, sub)
            elif key == 'FieldSettings':
                parseDefault(ob.field, sub, {}, [])
            else:
                defaultKey(key, val, sub, "ob", ['type', 'data'], globals(), locals())
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        if bpy.context.object == ob:
    
            if ob.type == 'MESH':
                bpy.ops.object.shade_smooth()
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        else:
            print("Context", ob, bpy.context.object, bpy.context.scene.objects.active)
        return