Skip to content
Snippets Groups Projects
io_import_scene_mhx.py 74.1 KiB
Newer Older
# ##### 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-2011
# Coding Standards:    See http://sites.google.com/site/makehumandocs/developers-guide
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 "Add-Ons" 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',
    "blender": (2, 5, 7),
    '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 = 4
SUB_VERSION = 0
BLENDER_VERSION = (2, 57, 0)
Brendon Murphy's avatar
Brendon Murphy committed
#
#
#

import bpy
import os
import time
import mathutils
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
Brendon Murphy's avatar
Brendon Murphy committed
T_Symm = 0x4000

toggle = T_EnforceVersion + T_Replace + T_Mesh + T_Armature + T_Face + T_Shape + T_Proxy + T_Clothes
Brendon Murphy's avatar
Brendon Murphy committed

#
#    Blender versions
#

BLENDER_GRAPHICALL = 0
BLENDER_256a = 1

BlenderVersions = ['Graphicall', 'Blender256a']
theBlenderVersion = BLENDER_GRAPHICALL

Brendon Murphy's avatar
Brendon Murphy committed
#
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' : {},
Luca Bonavita's avatar
Luca Bonavita committed
    '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
    global todo, nErrors, theScale, defaultScale, One, toggle

Luca Bonavita's avatar
Luca Bonavita committed
    
Luca Bonavita's avatar
Luca Bonavita committed
    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)

    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
    print((major,minor), (MAJOR_VERSION, MINOR_VERSION), warnedVersion)
    if  major != MAJOR_VERSION or minor != MINOR_VERSION:
Luca Bonavita's avatar
Luca Bonavita committed
        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:    
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)
            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 == "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)
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])]
                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)        
Luca Bonavita's avatar
Luca Bonavita committed
        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)
Luca Bonavita's avatar
Luca Bonavita committed
    data = eval(expr)
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
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:
        #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
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]
    # 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
    print("Parse Animation data")
    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())
Luca Bonavita's avatar
Luca Bonavita committed
    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':
            if theBlenderVersion >= BLENDER_256a:
                pt = fcu.keyframe_points.add(n, 0)
            else:
                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]
Luca Bonavita's avatar
Luca Bonavita committed
        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
    #print("   Driver type", drv, args[0])
Luca Bonavita's avatar
Luca Bonavita committed
    drv.type = args[0]
Luca Bonavita's avatar
Luca Bonavita committed
    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]
    #print("   Var type", var, args[1])
Luca Bonavita's avatar
Luca Bonavita committed
    var.type = args[1]
Luca Bonavita's avatar
Luca Bonavita committed
    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]
    ob = loadedData['Object'][args[0]]
    #print("    targ id", targ, ob)
    targ.id = ob
    #print("    ->", targ.id)
Luca Bonavita's avatar
Luca Bonavita committed
    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)
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)
        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)
Luca Bonavita's avatar
Luca Bonavita committed
                return None
            img.name = imgName
        else:
            defaultKey(key, val,  sub, "img", ['depth', 'dirty', 'has_data', 'size', 'type'], globals(), locals())
    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:
            raise NameError("Failed to find data: %s %s %s" % (name, typ, datName))
            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
        print("Create", name, data, datName)
        ob = createObject(typ, name, data, datName)
        print("created", ob)
        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())

    # Needed for updating layers
    if bpy.context.object == ob:
        pass
        '''
        if ob.data in ['MESH', 'ARMATURE']:
            print(ob, ob.data)
            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.object.mode_set(mode='OBJECT')
        '''
    else:
        print("Context", ob, bpy.context.object, bpy.context.scene.objects.active)
    return
Brendon Murphy's avatar
Brendon Murphy committed

def createObject(typ, name, data, datName):
Luca Bonavita's avatar
Luca Bonavita committed
    # print( "Creating object %s %s %s" % (typ, name, data) )    
    ob = bpy.data.objects.new(name, data)
    if data:
        loadedData[typ.capitalize()][datName] = data
    loadedData['Object'][name] = ob
    return ob
    
Brendon Murphy's avatar
Brendon Murphy committed
def linkObject(ob, data):
Luca Bonavita's avatar
Luca Bonavita committed
    #print("Data", data, ob.data)
    if data and ob.data is None:
Luca Bonavita's avatar
Luca Bonavita committed
        ob.data = data
        print("Data linked", ob, ob.data)
    scn = bpy.context.scene
    scn.objects.link(ob)
    scn.objects.active = ob
    #print("Linked object", ob)
    #print("Scene", scn)
    #print("Active", scn.objects.active)
    #print("Context", bpy.context.object)
    return ob

def setObjectAndData(args, typ):
Luca Bonavita's avatar
Luca Bonavita committed
    datName = args[0]
    obName = args[1]
    #bpy.ops.object.add(type=typ)
    ob = bpy.context.object
    ob.name = obName
    ob.data.name = datName
    loadedData[typ][datName] = ob.data
    loadedData['Object'][obName] = ob
    return ob.data
Luca Bonavita's avatar
Luca Bonavita committed
#    parseModifier(ob, args, tokens):
Brendon Murphy's avatar
Brendon Murphy committed
def parseModifier(ob, args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    name = args[0]
    typ = args[1]
    if typ == 'PARTICLE_SYSTEM':
        return None
    mod = ob.modifiers.new(name, typ)
    for (key, val, sub) in tokens:
        if key == 'HookAssignNth':
            if val[0] == 'CURVE':
                hookAssignNth(mod, int(val[1]), True, ob.data.splines[0].points)
            elif val[0] == 'LATTICE':
                hookAssignNth(mod, int(val[1]), False, ob.data.points)
            elif val[0] == 'MESH':
                hookAssignNth(mod, int(val[1]), True, ob.data.vertices)
            else:
                raise NameError("Unknown hook %s" % val)
        else:            
            defaultKey(key, val, sub, 'mod', [], globals(), locals())
Luca Bonavita's avatar
Luca Bonavita committed
    return mod
def hookAssignNth(mod, n, select, points):
    if select:
        for pt in points:
            pt.select = False
        points[n].select = True
        sel = []
        for pt in points:
            sel.append(pt.select)
        #print(mod, sel, n, points)

    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.object.hook_reset(modifier=mod.name)
    bpy.ops.object.hook_select(modifier=mod.name)
    bpy.ops.object.hook_assign(modifier=mod.name)
    bpy.ops.object.mode_set(mode='OBJECT')
    return

Brendon Murphy's avatar
Brendon Murphy committed
#
Luca Bonavita's avatar
Luca Bonavita committed
#    parseParticleSystem(ob, args, tokens):
#    parseParticles(particles, args, tokens):
#    parseParticle(par, args, tokens):
Brendon Murphy's avatar
Brendon Murphy committed
#

def parseParticleSystem(ob, args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    print(ob, bpy.context.object)
    pss = ob.particle_systems
    print(pss, pss.values())
    name = args[0]
    typ = args[1]
    #psys = pss.new(name, typ)
    bpy.ops.object.particle_system_add()
    print(pss, pss.values())
    psys = pss[-1]
    psys.name = name
    psys.settings.type = typ
    loadedData['ParticleSystem'][name] = psys
    print("Psys", psys)

    for (key, val, sub) in tokens:
        if key == 'Particles':
            parseParticles(psys, val, sub)
        else:
            defaultKey(key, val, sub, 'psys', [], globals(), locals())
    return psys
Brendon Murphy's avatar
Brendon Murphy committed

def parseParticles(psys, args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    particles = psys.particles
    bpy.ops.particle.particle_edit_toggle()
    n = 0
    for (key, val, sub) in tokens:
        if key == 'Particle':
            parseParticle(particles[n], val, sub)
            n += 1
        else:
            for par in particles:
                defaultKey(key, val, sub, 'par', [], globals(), locals())
    bpy.ops.particle.particle_edit_toggle()
    return particles
Brendon Murphy's avatar
Brendon Murphy committed

def parseParticle(par, args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    n = 0
    for (key, val, sub) in tokens:
        if key == 'h':
            h = par.hair[n]
            h.location = eval(val[0])
            h.time = int(val[1])
            h.weight = float(val[2])
            n += 1
        elif key == 'location':
            par.location = eval(val[0])
    return
Luca Bonavita's avatar
Luca Bonavita committed
#    unpackList(list_of_tuples):
Brendon Murphy's avatar
Brendon Murphy committed
#

def unpackList(list_of_tuples):
Luca Bonavita's avatar
Luca Bonavita committed
    l = []
    for t in list_of_tuples:
        l.extend(t)
    return l
Luca Bonavita's avatar
Luca Bonavita committed
#    parseMesh (args, tokens):
Brendon Murphy's avatar
Brendon Murphy committed
#

def parseMesh (args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    global todo
    if verbosity > 2:
        print( "Parsing mesh %s" % args )

    mename = args[0]
    obname = args[1]
    me = bpy.data.meshes.new(mename)
    ob = createObject('MESH', obname, me, mename)

    verts = []
    edges = []
    faces = []
    vertsTex = []
    texFaces = []

    for (key, val, sub) in tokens:
        if key == 'Verts':
            verts = parseVerts(sub)
        elif key == 'Edges':
            edges = parseEdges(sub)
        elif key == 'Faces':
            faces = parseFaces(sub)

    if faces:
        me.from_pydata(verts, [], faces)
    else:
        me.from_pydata(verts, edges, [])
Luca Bonavita's avatar
Luca Bonavita committed
    linkObject(ob, me)
        
    mats = []
    for (key, val, sub) in tokens:
        if key == 'Verts' or key == 'Edges' or key == 'Faces':
            pass
        elif key == 'MeshTextureFaceLayer':
            parseUvTexture(val, sub, me)
        elif key == 'MeshColorLayer':
            parseVertColorLayer(val, sub, me)
        elif key == 'VertexGroup':
            parseVertexGroup(ob, me, val, sub)
        elif key == 'ShapeKeys':
            parseShapeKeys(ob, me, val, sub)
        elif key == 'Material':
            try:                
                mat = loadedData['Material'][val[0]]
            except:
                mat = None
            if mat:
                me.materials.append(mat)
        else:
            defaultKey(key, val,  sub, "me", [], globals(), locals())

    for (key, val, sub) in tokens:
        if key == 'Faces':
            parseFaces2(sub, me)
Luca Bonavita's avatar
Luca Bonavita committed
    return me

#
#    parseVerts(tokens):
#    parseEdges(tokens):
#    parseFaces(tokens):
#    parseFaces2(tokens, me):        
Brendon Murphy's avatar
Brendon Murphy committed
#

def parseVerts(tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    verts = []
    for (key, val, sub) in tokens:
        if key == 'v':
            verts.append( (theScale*float(val[0]), theScale*float(val[1]), theScale*float(val[2])) )
    return verts
Brendon Murphy's avatar
Brendon Murphy committed

def parseEdges(tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    edges = []
    for (key, val, sub) in tokens:
        if key == 'e':
            edges.append((int(val[0]), int(val[1])))
    return edges
    
def parseFaces(tokens):    
    faces = []
    for (key, val, sub) in tokens:
        if key == 'f':
            if len(val) == 3:
                face = [int(val[0]), int(val[1]), int(val[2])]
            elif len(val) == 4:
                face = [int(val[0]), int(val[1]), int(val[2]), int(val[3])]
            faces.append(face)
    return faces

def parseFaces2(tokens, me):    
    n = 0
    for (key, val, sub) in tokens:
        if key == 'ft':
            f = me.faces[n]
            f.material_index = int(val[0])
            f.use_smooth = int(val[1])
            n += 1
        elif key == 'mn':
            fn = int(val[0])
            mn = int(val[1])
            f = me.faces[fn]
            f.material_index = mn
        elif key == 'ftall':
            mat = int(val[0])
            smooth = int(val[1])
            for f in me.faces:
                f.material_index = mat
                f.use_smooth = smooth
    return


#
#    parseUvTexture(args, tokens, me):
#    parseUvTexData(args, tokens, uvdata):
Brendon Murphy's avatar
Brendon Murphy committed
#

def parseUvTexture(args, tokens, me):
Luca Bonavita's avatar
Luca Bonavita committed
    name = args[0]
    me.uv_textures.new(name = name)
    uvtex = me.uv_textures[-1]
    loadedData['MeshTextureFaceLayer'][name] = uvtex
    for (key, val, sub) in tokens:
        if key == 'Data':
            parseUvTexData(val, sub, uvtex.data)
        else:
            defaultKey(key, val,  sub, "uvtex", [], globals(), locals())
    return
Brendon Murphy's avatar
Brendon Murphy committed

def parseUvTexData(args, tokens, data):
Luca Bonavita's avatar
Luca Bonavita committed
    n = 0
    for (key, val, sub) in tokens:
        if key == 'vt':
            data[n].uv1 = (float(val[0]), float(val[1]))
            data[n].uv2 = (float(val[2]), float(val[3]))
            data[n].uv3 = (float(val[4]), float(val[5]))
            if len(val) > 6:
                data[n].uv4 = (float(val[6]), float(val[7]))
            n += 1    
        else:
            pass
            #for i in range(n):
            #    defaultKey(key, val,  sub, "data[i]", [], globals(), locals())
    return

#
#    parseVertColorLayer(args, tokens, me):
#    parseVertColorData(args, tokens, data):
Brendon Murphy's avatar
Brendon Murphy committed
#

def parseVertColorLayer(args, tokens, me):
Luca Bonavita's avatar
Luca Bonavita committed
    name = args[0]
    print("VertColorLayer", name)
    vcol = me.vertex_colors.new(name)
    loadedData['MeshColorLayer'][name] = vcol
    for (key, val, sub) in tokens:
        if key == 'Data':
            parseVertColorData(val, sub, vcol.data)
        else:
            defaultKey(key, val,  sub, "vcol", [], globals(), locals())
    return
Brendon Murphy's avatar
Brendon Murphy committed

def parseVertColorData(args, tokens, data):
Luca Bonavita's avatar
Luca Bonavita committed
    n = 0
    for (key, val, sub) in tokens:
        if key == 'cv':
            data[n].color1 = eval(val[0])
            data[n].color2 = eval(val[1])
            data[n].color3 = eval(val[2])
            data[n].color4 = eval(val[3])
            n += 1    
    return
Luca Bonavita's avatar
Luca Bonavita committed
#    parseVertexGroup(ob, me, args, tokens):
Brendon Murphy's avatar
Brendon Murphy committed
#

def parseVertexGroup(ob, me, args, tokens):
    global toggle, theBlenderVersion
Luca Bonavita's avatar
Luca Bonavita committed
    if verbosity > 2:
        print( "Parsing vertgroup %s" % args )
    grpName = args[0]
    try:
        res = eval(args[1])
    except:
        res = True
    if not res:
        return

    if (toggle & T_Armature) or (grpName in ['Eye_L', 'Eye_R', 'Gums', 'Head', 'Jaw', 'Left', 'Middle', 'Right', 'Scalp']):
        group = ob.vertex_groups.new(grpName)
        loadedData['VertexGroup'][grpName] = group
        if theBlenderVersion >= BLENDER_256a:
            for (key, val, sub) in tokens:
                if key == 'wv':
                    ob.vertex_groups.assign([int(val[0])], group, float(val[1]), 'REPLACE')
        else:
            for (key, val, sub) in tokens:
                if key == 'wv':
                    group.add( [int(val[0])], float(val[1]), 'REPLACE' )
Luca Bonavita's avatar
Luca Bonavita committed
    return


#
#    parseShapeKeys(ob, me, args, tokens):
#    parseShapeKey(ob, me, args, tokens):
#    addShapeKey(ob, name, vgroup, tokens):
#    doShape(name):
Brendon Murphy's avatar
Brendon Murphy committed
#

def doShape(name):
Luca Bonavita's avatar
Luca Bonavita committed
    if (toggle & T_Shape+T_Face) and (name == 'Basis'):
        return True
    else:
        return (toggle & T_Face)
Brendon Murphy's avatar
Brendon Murphy committed

def parseShapeKeys(ob, me, args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    for (key, val, sub) in tokens:
        if key == 'ShapeKey':
            parseShapeKey(ob, me, val, sub)
        elif key == 'AnimationData':
            if me.shape_keys:
                parseAnimationData(me.shape_keys, val, sub)
    ob.active_shape_key_index = 0
Luca Bonavita's avatar
Luca Bonavita committed
    return
Brendon Murphy's avatar
Brendon Murphy committed


def parseShapeKey(ob, me, args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    if verbosity > 2:
        print( "Parsing ob %s shape %s" % (bpy.context.object, args[0] ))
    name = args[0]
    lr = args[1]
    if invalid(args[2]):
        return

    if lr == 'Sym' or toggle & T_Symm:
        addShapeKey(ob, name, None, tokens)
    elif lr == 'LR':
        addShapeKey(ob, name+'_L', 'Left', tokens)
        addShapeKey(ob, name+'_R', 'Right', tokens)
    else:
        raise NameError("ShapeKey L/R %s" % lr)
    return
Brendon Murphy's avatar
Brendon Murphy committed

def addShapeKey(ob, name, vgroup, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    skey = ob.shape_key_add(name=name, from_mix=False)
    if name != 'Basis':
        skey.relative_key = loadedData['ShapeKey']['Basis']
    skey.name = name
    if vgroup:
        skey.vertex_group = vgroup
    loadedData['ShapeKey'][name] = skey
Luca Bonavita's avatar
Luca Bonavita committed
    for (key, val, sub) in tokens:
        if key == 'sv':
            index = int(val[0])
            pt = skey.data[index].co
            pt[0] += theScale*float(val[1])
            pt[1] += theScale*float(val[2])
            pt[2] += theScale*float(val[3])
        else:
            defaultKey(key, val,  sub, "skey", [], globals(), locals())
Luca Bonavita's avatar
Luca Bonavita committed
    return    
Luca Bonavita's avatar
Luca Bonavita committed
    
Brendon Murphy's avatar
Brendon Murphy committed
#
Luca Bonavita's avatar
Luca Bonavita committed
#    parseArmature (obName, args, tokens)
Brendon Murphy's avatar
Brendon Murphy committed
#

def parseArmature (args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    global toggle
    if verbosity > 2:
        print( "Parsing armature %s" % args )
    
    amtname = args[0]
    obname = args[1]
    mode = args[2]
    
    if mode == 'Rigify':
        toggle |= T_Rigify
        return parseRigify(amtname, obname, tokens)

    toggle &= ~T_Rigify
    amt = bpy.data.armatures.new(amtname)
    ob = createObject('ARMATURE', obname, amt, amtname)    

    linkObject(ob, amt)
    print("Linked")

    bpy.ops.object.mode_set(mode='OBJECT')
    bpy.ops.object.mode_set(mode='EDIT')

    heads = {}
    tails = {}
    for (key, val, sub) in tokens:
        if key == 'Bone':
            bname = val[0]
            if not invalid(val[1]):
                bone = amt.edit_bones.new(bname)
                parseBone(bone, amt, sub, heads, tails)
                loadedData['Bone'][bname] = bone
        elif key == 'RecalcRoll':
            for bone in amt.edit_bones:
                bone.select = False
            blist = eval(val[0])
            for name in blist:
                bone = amt.edit_bones[name]
                bone.select = True
            bpy.ops.armature.calculate_roll(type='Z')
            for bone in amt.edit_bones:
                rolls[bone.name] = bone.roll
            bpy.ops.object.mode_set(mode='OBJECT')
            for bone in amt.bones:
                bone['Roll'] = rolls[bone.name]
            bpy.ops.object.mode_set(mode='EDIT')
Luca Bonavita's avatar
Luca Bonavita committed
        else:
            defaultKey(key, val,  sub, "amt", ['MetaRig'], globals(), locals())
    bpy.ops.object.mode_set(mode='OBJECT')
    return amt

#
#    parseRigify(amtname, obname, tokens):        
#

def parseRigify(amtname, obname, tokens):        
    (key,val,sub) = tokens[0]
    if key != 'MetaRig':
        raise NameError("Expected MetaRig")
    typ = val[0]
    if typ == "human":
        bpy.ops.object.armature_human_advanced_add()
    else:
        bpy.ops.pose.metarig_sample_add(type = typ)
    ob = bpy.context.scene.objects.active
    amt = ob.data
    loadedData['Rigify'][obname] = ob
    loadedData['Armature'][amtname] = amt
    loadedData['Object'][obname] = ob
    print("Rigify object", ob, amt)

    bpy.ops.object.mode_set(mode='OBJECT')
    bpy.ops.object.mode_set(mode='EDIT')

    heads = {}
    tails = {}
    for (bname, bone) in amt.edit_bones.items():
        heads[bname] = 10*theScale*bone.head
        tails[bname] = 10*theScale*bone.tail

    for (key, val, sub) in tokens:
        if key == 'Bone':
            bname = val[0]
            print("Bone", bname)
            try:
                bone = amt.edit_bones[bname]
            except:
                print("Did not find bone %s" % bname)
                bone = None
            print(" -> ", bone)
            if bone:
                parseBone(bone, amt, sub, heads, tails)
        else:
            defaultKey(key, val,  sub, "amt", ['MetaRig'], globals(), locals())
    bpy.ops.object.mode_set(mode='OBJECT')
    return amt
        
#
#    parseBone(bone, amt, tokens, heads, tails):
#

def parseBone(bone, amt, tokens, heads, tails):
Luca Bonavita's avatar
Luca Bonavita committed
    global todo
Luca Bonavita's avatar
Luca Bonavita committed
    for (key, val, sub) in tokens:
        if key == "head":
            bone.head = (theScale*float(val[0]), theScale*float(val[1]), theScale*float(val[2]))
        elif key == "tail":
            bone.tail = (theScale*float(val[0]), theScale*float(val[1]), theScale*float(val[2]))
        #elif key == 'restrict_select':
        #    pass
        elif key == 'hide' and val[0] == 'True':
            name = bone.name
            '''
            #bpy.ops.object.mode_set(mode='OBJECT')
            pbone = amt.bones[name]
            pbone.hide = True
            print("Hide", pbone, pbone.hide)
            #bpy.ops.object.mode_set(mode='EDIT')            
            '''
        else:
            defaultKey(key, val,  sub, "bone", [], globals(), locals())
    return bone
Luca Bonavita's avatar
Luca Bonavita committed
#    parsePose (args, tokens):
Brendon Murphy's avatar
Brendon Murphy committed
#

def parsePose (args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    global todo
    if toggle & T_Rigify:
        return
    name = args[0]
    ob = loadedData['Object'][name]
    bpy.context.scene.objects.active = ob
    bpy.ops.object.mode_set(mode='POSE')
    pbones = ob.pose.bones    
    nGrps = 0
    for (key, val, sub) in tokens:
        if key == 'Posebone':
            parsePoseBone(pbones, ob, val, sub)
        elif key == 'BoneGroup':
            parseBoneGroup(ob.pose, nGrps, val, sub)
            nGrps += 1
        elif key == 'SetProp':
            bone = val[0]
            prop = val[1]
            value = eval(val[2])
            pb = pbones[bone]
            print("Setting", pb, prop, val)
            pb[prop] = value
            print("Prop set", pb[prop])
        else:
            defaultKey(key, val,  sub, "ob.pose", [], globals(), locals())
    bpy.ops.object.mode_set(mode='OBJECT')
    return ob


#
#    parsePoseBone(pbones, args, tokens):
#    parseArray(data, exts, args):
Brendon Murphy's avatar
Brendon Murphy committed
#

def parseBoneGroup(pose, nGrps, args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    global todo
    if verbosity > 2:
        print( "Parsing bonegroup %s" % args )
Luca Bonavita's avatar
Luca Bonavita committed
    name = args[0]
    bpy.ops.pose.group_add()
    bg = pose.bone_groups.active
    loadedData['BoneGroup'][name] = bg
    for (key, val, sub) in tokens:
        defaultKey(key, val,  sub, "bg", [], globals(), locals())
    return
Brendon Murphy's avatar
Brendon Murphy committed

def parsePoseBone(pbones, ob, args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    global todo
    if invalid(args[1]):
        return
    name = args[0]
    pb = pbones[name]
    amt = ob.data
Luca Bonavita's avatar
Luca Bonavita committed

    for (key, val, sub) in tokens:
        if key == 'Constraint':
            amt.bones.active = pb.bone 
            cns = parseConstraint(pb.constraints, pb, val, sub)
Luca Bonavita's avatar
Luca Bonavita committed
        elif key == 'bpyops':
Luca Bonavita's avatar
Luca Bonavita committed
            expr = "bpy.ops.%s" % val[0]
Luca Bonavita's avatar
Luca Bonavita committed
            exec(expr)
        elif key == 'ik_dof':
            parseArray(pb, ["ik_dof_x", "ik_dof_y", "ik_dof_z"], val)
        elif key == 'ik_limit':
            parseArray(pb, ["ik_limit_x", "ik_limit_y", "ik_limit_z"], val)
        elif key == 'ik_max':
            parseArray(pb, ["ik_max_x", "ik_max_y", "ik_max_z"], val)
        elif key == 'ik_min':
            parseArray(pb, ["ik_min_x", "ik_min_y", "ik_min_z"], val)
        elif key == 'ik_stiffness':
            parseArray(pb, ["ik_stiffness_x", "ik_stiffness_y", "ik_stiffness_z"], val)
        elif key == 'hide':
            #bpy.ops.object.mode_set(mode='OBJECT')
            amt.bones[name].hide = eval(val[0])
            #bpy.ops.object.mode_set(mode='POSE')
            
        else:
            defaultKey(key, val,  sub, "pb", [], globals(), locals())
    #print("pb %s done" % name)
    return
Brendon Murphy's avatar
Brendon Murphy committed

def parseArray(data, exts, args):
Luca Bonavita's avatar
Luca Bonavita committed
    n = 1
    for ext in exts:
        expr = "data.%s = %s" % (ext, args[n])
        # print(expr)
        exec(expr)
        n += 1
    return
        
Brendon Murphy's avatar
Brendon Murphy committed
#
#    parseConstraint(constraints, pb, args, tokens)
def parseConstraint(constraints, pb, args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    if invalid(args[2]):
        return None
    if (toggle&T_Opcns and pb):
        print("Active")
        aob = bpy.context.object
        print("ob", aob)
        aamt = aob.data
        print("amt", aamt)
        apose = aob.pose
        print("pose", apose)
        abone = aamt.bones.active
        print("bone", abone)
        print('Num cns before', len(list(constraints)))
        bpy.ops.pose.constraint_add(type=args[1])
        cns = constraints.active
        print('and after', pb, cns, len(list(constraints)))
    else:
        cns = constraints.new(args[1])
Luca Bonavita's avatar
Luca Bonavita committed
    cns.name = args[0]
    for (key,val,sub) in tokens:
        if key == 'invert':
            parseArray(cns, ["invert_x", "invert_y", "invert_z"], val)
        elif key == 'use':
            parseArray(cns, ["use_x", "use_y", "use_z"], val)
        elif key == 'pos_lock':
            parseArray(cns, ["lock_location_x", "lock_location_y", "lock_location_z"], val)
        elif key == 'rot_lock':
            parseArray(cns, ["lock_rotation_x", "lock_rotation_y", "lock_rotation_z"], val)
        else:
            defaultKey(key, val,  sub, "cns", [], globals(), locals())
Luca Bonavita's avatar
Luca Bonavita committed
    #print("cns %s done" % cns.name)
    return cns
Luca Bonavita's avatar
Luca Bonavita committed
#    parseCurve (args, tokens):
#    parseSpline(cu, args, tokens):
#    parseBezier(spline, n, args, tokens):
Brendon Murphy's avatar
Brendon Murphy committed
#

def parseCurve (args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    global todo
    if verbosity > 2:
        print( "Parsing curve %s" % args )
    bpy.ops.object.add(type='CURVE')
    cu = setObjectAndData(args, 'Curve')

    for (key, val, sub) in tokens:
        if key == 'Spline':
            parseSpline(cu, val, sub)
        else:
            defaultKey(key, val, sub, "cu", [], globals(), locals())
    return

def parseTextCurve (args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    global todo
    if verbosity > 2:
        print( "Parsing text curve %s" % args )
    bpy.ops.object.text_add()
    txt = setObjectAndData(args, 'Text')

    for (key, val, sub) in tokens:
        if key == 'Spline':
            parseSpline(txt, val, sub)
        elif key == 'BodyFormat':
            parseCollection(txt.body_format, sub, [])
        elif key == 'EditFormat':
            parseDefault(txt.edit_format, sub, {}, [])
        elif key == 'Font':
            parseDefault(txt.font, sub, {}, [])
        elif key == 'TextBox':
            parseCollection(txt.body_format, sub, [])
        else:
            defaultKey(key, val, sub, "txt", [], globals(), locals())
    return
Luca Bonavita's avatar
Luca Bonavita committed
    typ = args[0]
    spline = cu.splines.new(typ)
    nPointsU = int(args[1])
    nPointsV = int(args[2])
    #spline.point_count_u = nPointsU
    #spline.point_count_v = nPointsV
    if typ == 'BEZIER' or typ == 'BSPLINE':
        spline.bezier_points.add(nPointsU)
    else:
        spline.points.add(nPointsU)

    n = 0
    for (key, val, sub) in tokens:
        if key == 'bz':
            parseBezier(spline.bezier_points[n], val, sub)
            n += 1
        elif key == 'pt':
            parsePoint(spline.points[n], val, sub)
            n += 1
        else:
            defaultKey(key, val, sub, "spline", [], globals(), locals())
    return
    
def parseBezier(bez, args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    bez.co = eval(args[0])
    bez.co = theScale*bez.co    
    bez.handle1 = eval(args[1])    
    bez.handle1_type = args[2]
    bez.handle2 = eval(args[3])    
    bez.handle2_type = args[4]
    return

def parsePoint(pt, args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    pt.co = eval(args[0])
    pt.co = theScale*pt.co
Luca Bonavita's avatar
Luca Bonavita committed
    return
Luca Bonavita's avatar
Luca Bonavita committed
#    parseLattice (args, tokens):
Brendon Murphy's avatar
Brendon Murphy committed
#

def parseLattice (args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    global todo
    if verbosity > 2:
        print( "Parsing lattice %s" % args )
    bpy.ops.object.add(type='LATTICE')
    lat = setObjectAndData(args, 'Lattice')    
    for (key, val, sub) in tokens:
        if key == 'Points':
            parseLatticePoints(val, sub, lat.points)
        else:
            defaultKey(key, val, sub, "lat", [], globals(), locals())
    return
Brendon Murphy's avatar
Brendon Murphy committed

def parseLatticePoints(args, tokens, points):
Luca Bonavita's avatar
Luca Bonavita committed
    global todo
    n = 0
    for (key, val, sub) in tokens:
        if key == 'pt':
            v = points[n].co_deform
            v.x = theScale*float(val[0])
            v.y = theScale*float(val[1])
            v.z = theScale*float(val[2])
Luca Bonavita's avatar
Luca Bonavita committed
            n += 1
    return
Luca Bonavita's avatar
Luca Bonavita committed
#    parseLamp (args, tokens):
#    parseFalloffCurve(focu, args, tokens):
def parseLamp (args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    global todo
    if verbosity > 2:
        print( "Parsing lamp %s" % args )
    bpy.ops.object.add(type='LAMP')
    lamp = setObjectAndData(args, 'Lamp')    
    for (key, val, sub) in tokens:
        if key == 'FalloffCurve':
            parseFalloffCurve(lamp.falloff_curve, val, sub)
        else:
            defaultKey(key, val, sub, "lamp", [], globals(), locals())
    return
def parseFalloffCurve(focu, args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    return
Luca Bonavita's avatar
Luca Bonavita committed
#    parseGroup (args, tokens):
#    parseGroupObjects(args, tokens, grp):
Luca Bonavita's avatar
Luca Bonavita committed
    global todo
    if verbosity > 2:
        print( "Parsing group %s" % args )

    grpName = args[0]
    grp = bpy.data.groups.new(grpName)
    loadedData['Group'][grpName] = grp
    for (key, val, sub) in tokens:
        if key == 'Objects':
            parseGroupObjects(val, sub, grp)
        else:
            defaultKey(key, val, sub, "grp", [], globals(), locals())
    return

def parseGroupObjects(args, tokens, grp):
Luca Bonavita's avatar
Luca Bonavita committed
    global todo
    for (key, val, sub) in tokens:
        if key == 'ob':
            try:
                ob = loadedData['Object'][val[0]]
                grp.objects.link(ob)
            except:
                pass
    return
Luca Bonavita's avatar
Luca Bonavita committed
#    parseWorld (args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    global todo
    if verbosity > 2:
        print( "Parsing world %s" % args )
    world = bpy.context.scene.world
    for (key, val, sub) in tokens:
        if key == 'Lighting':
            parseDefault(world.lighting, sub, {}, [])
        elif key == 'Mist':
            parseDefault(world.mist, sub, {}, [])
        elif key == 'Stars':
            parseDefault(world.stars, sub, {}, [])
        else:
            defaultKey(key, val, sub, "world", [], globals(), locals())
    return

#
#    parseScene (args, tokens):
#    parseRenderSettings(render, args, tokens):
#    parseToolSettings(tool, args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    global todo
    if verbosity > 2:
        print( "Parsing scene %s" % args )
    scn = bpy.context.scene
    for (key, val, sub) in tokens:
        if key == 'NodeTree':
            scn.use_nodes = True
            parseNodeTree(scn, val, sub)
        elif key == 'GameData':
            parseDefault(scn.game_data, sub, {}, [])
        elif key == 'KeyingSet':
            pass
            #parseDefault(scn.keying_sets, sub, {}, [])
        elif key == 'ObjectBase':
            pass
            #parseDefault(scn.bases, sub, {}, [])
        elif key == 'RenderSettings':
            parseRenderSettings(scn.render, sub, [])
        elif key == 'ToolSettings':
            subkeys = {'ImagePaint' : "image_paint",  
                'Sculpt' : "sculpt",  
                'VertexPaint' : "vertex_paint",  
                'WeightPaint' : "weight_paint" }
            parseDefault(scn.tool_settings, sub, subkeys, [])
        elif key == 'UnitSettings':
            parseDefault(scn.unit_settings, sub, {}, [])
        else:
            defaultKey(key, val, sub, "scn", [], globals(), locals())
    return

def parseRenderSettings(render, args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    global todo
    if verbosity > 2:
        print( "Parsing RenderSettings %s" % args )
    for (key, val, sub) in tokens:
        if key == 'Layer':
            pass
            #parseDefault(scn.layers, sub, [])
        else:
            defaultKey(key, val, sub, "render", [], globals(), locals())
    return
#    parseDefineProperty(args, tokens):
def parseDefineProperty(args, tokens):
    expr = "bpy.types.Object.%s = %sProperty" % (args[0], args[1])
    c = '('
    for option in args[2:]:
        expr += "%s %s" % (c, option)
        c = ','
    expr += ')'
    #print(expr)
    exec(expr)
    #print("Done")
    return

#
#    correctRig(args):
#

def correctRig(args):
    human = args[0]
    print("CorrectRig %s" % human)    
    try:
        ob = loadedData['Object'][human]
    except:
Luca Bonavita's avatar
Luca Bonavita committed
        return
    bpy.context.scene.objects.active = ob
    bpy.ops.object.mode_set(mode='POSE')
    amt = ob.data
    cnslist = []
    for pb in ob.pose.bones:
        for cns in pb.constraints:
            if cns.type == 'CHILD_OF':
                cnslist.append((pb, cns, cns.influence))
                cns.influence = 0

    for (pb, cns, inf) in cnslist:
        amt.bones.active = pb.bone
        cns.influence = 1
        #print("Childof %s %s %s %.2f" % (amt.name, pb.name, cns.name, inf))
        bpy.ops.constraint.childof_clear_inverse(constraint=cns.name, owner='BONE')
        bpy.ops.constraint.childof_set_inverse(constraint=cns.name, owner='BONE')
        cns.influence = 0

    for (pb, cns, inf) in cnslist:
        cns.influence = inf
    return
        

#
#    postProcess(args)
#

def postProcess(args):
    human = args[0]
    print("Postprocess %s" % human)    
Luca Bonavita's avatar
Luca Bonavita committed
    try:
        ob = loadedData['Object'][human]
Luca Bonavita's avatar
Luca Bonavita committed
    except:
        ob = None
    if toggle & T_Diamond == 0 and ob:
        deleteDiamonds(ob)
    if toggle & T_Rigify and False:
        for rig in loadedData['Rigify'].values():
            bpy.context.scene.objects.active = rig
            print("Rigify", rig)
            bpy.ops.pose.metarig_generate()
            print("Metarig generated")
            #bpy.context.scene.objects.unlink(rig)

            rig = bpy.context.scene.objects.active
            print("Rigged", rig, bpy.context.object)
            ob = loadedData['Object'][human]
Luca Bonavita's avatar
Luca Bonavita committed
            mod = ob.modifiers[0]
            print(ob, mod, mod.object)
            mod.object = rig
            print("Rig changed", mod.object)
    return            

#
#    deleteDiamonds(ob)
#    Delete joint diamonds in main mesh
Luca Bonavita's avatar
Luca Bonavita committed
    bpy.context.scene.objects.active = ob
    if not bpy.context.object:
        return
    print("Delete diamonds in %s" % bpy.context.object)
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='DESELECT')
    bpy.ops.object.mode_set(mode='OBJECT')
    me = ob.data
    for f in me.faces:        
        if len(f.vertices) < 4:
            for vn in f.vertices:
                me.vertices[vn].select = True
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.delete(type='VERT')
    bpy.ops.object.mode_set(mode='OBJECT')
    return

    
#
#    parseProcess(args, tokens):
#    applyTransform(objects, rig, parents):
Brendon Murphy's avatar
Brendon Murphy committed
#

def parseProcess(args, tokens):
Luca Bonavita's avatar
Luca Bonavita committed
    if toggle & T_Bend == 0:
        return
    try:
        rig = loadedData['Object'][args[0]]
    except:
        rig = None
    if not rig:
        return

    parents = {}
    objects = []

    for (key, val, sub) in tokens:
        #print(key, val)
        if key == 'Reparent':
            bname = val[0]
            try:
                eb = ebones[bname]
                parents[bname] = eb.parent.name
                eb.parent = ebones[val[1]]
            except:
                pass
        elif key == 'Bend':
            axis = val[1]
            angle = float(val[2])
            mat = Matrix.Rotation(angle, 4, axis)
Luca Bonavita's avatar
Luca Bonavita committed
            try:
                pb = pbones[val[0]]
            except:
Luca Bonavita's avatar
Luca Bonavita committed
                print("No bone "+val[0])
            if pb:
                prod = pb.matrix_basis * mat
                for i in range(4):
                    for j in range(4):
                        pb.matrix_basis[i][j] = prod[i][j]
Luca Bonavita's avatar
Luca Bonavita committed
        elif key == 'Snap':
            try:
                eb = ebones[val[0]]
            except:
                eb = None
            tb = ebones[val[1]]
            typ = val[2]
Luca Bonavita's avatar
Luca Bonavita committed
                pass
            elif typ == 'Inv':
                eb.head = tb.tail
                eb.tail = tb.head
            elif typ == 'Head':
                eb.head = tb.head
            elif typ == 'Tail':
                eb.tail = tb.tail
            elif typ == 'Both':
                eb.head = tb.head
                eb.tail = tb.tail
                eb.roll = tb.roll
            else:
                raise NameError("Snap type %s" % typ)
        elif key == 'PoseMode':
            bpy.context.scene.objects.active = rig
            bpy.ops.object.mode_set(mode='POSE')
            pbones = rig.pose.bones    
        elif key == 'ObjectMode':
            bpy.context.scene.objects.active = rig
            bpy.ops.object.mode_set(mode='POSE')
            pbones = rig.pose.bones    
        elif key == 'EditMode':
Luca Bonavita's avatar
Luca Bonavita committed
            bpy.context.scene.objects.active = rig
            bpy.ops.object.mode_set(mode='EDIT')
            ebones = rig.data.edit_bones    
            bpy.ops.armature.select_all(action='DESELECT')
        elif key == 'Roll':
            try:
                eb = ebones[val[0]]
            except:
                eb = None
            if eb:
                eb.roll = float(val[1])
        elif key == 'Select':
            pass
        elif key == 'RollUp':
            pass
        elif key == 'Apply':
            applyTransform(objects, rig, parents)
        elif key == 'ApplyArmature':
            try:
                ob = loadedData['Object'][val[0]]
                objects.append((ob,sub))
            except:
                ob = None
        elif key == 'Object':
            try:
                ob = loadedData['Object'][val[0]]
            except:
                ob = None
            if ob:
                bpy.context.scene.objects.active = ob
                #mod = ob.modifiers[0]
                #ob.modifiers.remove(mod)
                for (key1, val1, sub1) in sub:
                    if key1 == 'Modifier':
                        parseModifier(ob, val1, sub1)
    return

def applyTransform(objects, rig, parents):
Luca Bonavita's avatar
Luca Bonavita committed
    for (ob,tokens) in objects:
        print("Applying transform to %s" % ob)
        bpy.context.scene.objects.active = ob        
        bpy.ops.object.visual_transform_apply()
        bpy.ops.object.modifier_apply(apply_as='DATA', modifier='Armature')
Luca Bonavita's avatar
Luca Bonavita committed
    bpy.context.scene.objects.active = rig
    bpy.ops.object.mode_set(mode='POSE')
    bpy.ops.pose.armature_apply()
    bpy.ops.object.mode_set(mode='OBJECT')
    bpy.ops.object.mode_set(mode='EDIT')
    ebones = rig.data.edit_bones
    for (bname, pname) in parents.items():
        eb = ebones[bname]
        par = ebones[pname]
        if eb.use_connect:
            par.tail = eb.head
        eb.parent = par
Luca Bonavita's avatar
Luca Bonavita committed
    bpy.ops.object.mode_set(mode='OBJECT')
    return            
Luca Bonavita's avatar
Luca Bonavita committed
#    defaultKey(ext, args, tokens, var, exclude, glbals, lcals):
Brendon Murphy's avatar
Brendon Murphy committed
#

def defaultKey(ext, args, tokens, var, exclude, glbals, lcals):
Luca Bonavita's avatar
Luca Bonavita committed
    global todo

    if ext == 'Property':
        try:
            expr = "%s['%s'] = %s" % (var, args[0], args[1])
        except:
            expr = None
Luca Bonavita's avatar
Luca Bonavita committed
        if expr:
            exec(expr, glbals, lcals)
        return

    if ext == 'bpyops':
        expr = "bpy.ops.%s" % args[0]
        print(expr)
        exec(expr)
        return
Luca Bonavita's avatar
Luca Bonavita committed
        
    nvar = "%s.%s" % (var, ext)
    #print(ext)
    if ext in exclude:
        return
    #print("D", nvar)

    if len(args) == 0:
        raise NameError("Key length 0: %s" % ext)
        
    rnaType = args[0]
    if rnaType == 'Add':
        print("*** Cannot Add yet ***")
        return

    elif rnaType == 'Refer':
        typ = args[1]
        name = args[2]
        data = "loadedData['%s']['%s']" % (typ, name)

    elif rnaType == 'Struct' or rnaType == 'Define':
        typ = args[1]
        name = args[2]
        try:
            data = eval(nvar, glbals, lcals)
        except:
            data = None            
        # print("Old structrna", nvar, data)

Luca Bonavita's avatar
Luca Bonavita committed
            try:
                creator = args[3]
            except:
                creator = None
            # print("Creator", creator, eval(var,glbals,lcals))

            try:
                rna = eval(var,glbals,lcals)
                data = eval(creator)
            except:
                data = None    
            # print("New struct", nvar, typ, data)

        if rnaType == 'Define':
            loadedData[typ][name] = data

        if data:
            for (key, val, sub) in tokens:
                defaultKey(key, val, sub, "data", [], globals(), locals())

        print("Struct done", nvar)
        return

    elif rnaType == 'PropertyRNA':
        raise NameError("PropertyRNA!")
        #print("PropertyRNA ", ext, var)
        for (key, val, sub) in tokens:
            defaultKey(ext, val, sub, nvar, [], glbals, lcals)
        return

    elif rnaType == 'Array':
        for n in range(1, len(args)):
            expr = "%s[%d] = %s" % (nvar, n-1, args[n])
            exec(expr, glbals, lcals)
        if len(args) > 0:
            expr = "%s[0] = %s" % (nvar, args[1])
            exec(expr, glbals, lcals)            
        return
        
    elif rnaType == 'List':
        data = []
        for (key, val, sub) in tokens:
            elt = eval(val[1], glbals, lcals)
            data.append(elt)

    elif rnaType == 'Matrix':
        return
        i = 0
        n = len(tokens)
        for (key, val, sub) in tokens:
            if key == 'row':    
                for j in range(n):
                    expr = "%s[%d][%d] = %g" % (nvar, i, j, float(val[j]))
                    exec(expr, glbals, lcals)
                i += 1
        return

    else:
        try:
            data = loadedData[rnaType][args[1]]
            #print("From loaded", rnaType, args[1], data)
            return data
        except:
            data = rnaType

    #print(var, ext, data)
    expr = "%s = %s" % (nvar, data)
    try:
        exec(expr, glbals, lcals)
    except:
        pushOnTodoList(var, expr, glbals, lcals)
    return
Luca Bonavita's avatar
Luca Bonavita committed
    global todo
    print("Tdo", var)
    print(dir(eval(var, glbals, lcals)))
    raise NameError("Todo", expr)
    todo.append((expr, glbals, lcals))
    return
Luca Bonavita's avatar
Luca Bonavita committed
            
Luca Bonavita's avatar
Luca Bonavita committed
#    parseBoolArray(mask):
Brendon Murphy's avatar
Brendon Murphy committed
#

def parseBoolArray(mask):
Luca Bonavita's avatar
Luca Bonavita committed
    list = []
    for c in mask:
        if c == '0':            
            list.append(False)
        else:
            list.append(True)
    return list
Luca Bonavita's avatar
Luca Bonavita committed
#    parseMatrix(args, tokens)
Brendon Murphy's avatar
Brendon Murphy committed
#

def parseMatrix(args, tokens):
    matrix = Matrix()
Luca Bonavita's avatar
Luca Bonavita committed
    i = 0
    for (key, val, sub) in tokens:
        if key == 'row':    
            matrix[i][0] = float(val[0])
            matrix[i][1] = float(val[1])
            matrix[i][2] = float(val[2])
            matrix[i][3] = float(val[3])
            i += 1
    return matrix
Luca Bonavita's avatar
Luca Bonavita committed
#    parseDefault(data, tokens, subkeys, exclude):
def parseDefault(data, tokens, subkeys, exclude):
Luca Bonavita's avatar
Luca Bonavita committed
    for (key, val, sub) in tokens:    
        if key in subkeys.keys():
            for (key2, val2, sub2) in sub:
                defaultKey(key2, val2, sub2, "data.%s" % subkeys[key], [], globals(), locals())
        else:
            defaultKey(key, val, sub, "data", exclude, globals(), locals())

def parseCollection(data, tokens, exclude):
Luca Bonavita's avatar
Luca Bonavita committed
    return
Luca Bonavita's avatar
Luca Bonavita committed
#    Utilities    
Luca Bonavita's avatar
Luca Bonavita committed
#    extractBpyType(data):
Brendon Murphy's avatar
Brendon Murphy committed
#

def extractBpyType(data):
Luca Bonavita's avatar
Luca Bonavita committed
    typeSplit = str(type(data)).split("'")
    if typeSplit[0] != '<class ':
        return None
    classSplit = typeSplit[1].split(".")
    if classSplit[0] == 'bpy' and classSplit[1] == 'types':
        return classSplit[2]
    elif classSplit[0] == 'bpy_types':
        return classSplit[1]
    else:
        return None
Luca Bonavita's avatar
Luca Bonavita committed
#    Bool(string):
Brendon Murphy's avatar
Brendon Murphy committed
#

def Bool(string):
Luca Bonavita's avatar
Luca Bonavita committed
    if string == 'True':
        return True
    elif string == 'False':
        return False
    else:
        raise NameError("Bool %s?" % string)
        
Brendon Murphy's avatar
Brendon Murphy committed
#
Luca Bonavita's avatar
Luca Bonavita committed
#    invalid(condition):
Brendon Murphy's avatar
Brendon Murphy committed
#

def invalid(condition):
Luca Bonavita's avatar
Luca Bonavita committed
    global rigLeg, rigArm, toggle
    res = eval(condition, globals())
    try:
        res = eval(condition, globals())
        #print("%s = %s" % (condition, res))
        return not res
    except:
        #print("%s invalid!" % condition)
        return True
Luca Bonavita's avatar
Luca Bonavita committed
    
Luca Bonavita's avatar
Luca Bonavita committed
#    clearScene(context):
Luca Bonavita's avatar
Luca Bonavita committed
    
Brendon Murphy's avatar
Brendon Murphy committed
def clearScene():
Luca Bonavita's avatar
Luca Bonavita committed
    global toggle
    scn = bpy.context.scene
    for n in range(len(scn.layers)):
        scn.layers[n] = True
    print("clearScene %s %s" % (toggle & T_Replace, scn))
    if not toggle & T_Replace:
        return scn

    for ob in scn.objects:
        if ob.type in ["MESH", "ARMATURE", 'EMPTY', 'CURVE', 'LATTICE']:
Luca Bonavita's avatar
Luca Bonavita committed
            scn.objects.active = ob
            try:
                bpy.ops.object.mode_set(mode='OBJECT')
            except:
                pass
Luca Bonavita's avatar
Luca Bonavita committed
            scn.objects.unlink(ob)
            del ob
    #print(scn.objects)
    return scn
#
#    hideLayers(args):
#    args = sceneLayers sceneHideLayers boneLayers boneHideLayers or nothing
#

def hideLayers(args):
    if len(args) > 1:
        sceneLayers = int(args[2], 16)
        sceneHideLayers = int(args[3], 16)
        boneLayers = int(args[4], 16)
        boneHideLayers = int(args[5], 16)
    else:
        sceneLayers = 0x00ff
        sceneHideLayers = 0
        boneLayers = 0
        boneHideLayers = 0

Luca Bonavita's avatar
Luca Bonavita committed
    scn = bpy.context.scene
    mask = 1
    hidelayers = []
    for n in range(20):
        scn.layers[n] = True if sceneLayers & mask else False
        if sceneHideLayers & mask:
            hidelayers.append(n)
        mask = mask << 1

    for ob in scn.objects:
        for n in hidelayers:
            if ob.layers[n]:
                ob.hide = True

    if boneLayers:    
        human = args[1]
        try:
            ob = loadedData['Object'][human]
        except:
            return

        mask = 1
        hidelayers = []
        for n in range(32):
            ob.data.layers[n] = True if boneLayers & mask else False
            if boneHideLayers & mask:
                hidelayers.append(n)
            mask = mask << 1

        for b in ob.data.bones:
            for n in hidelayers:
                if b.layers[n]:
                    b.hide = True

    return
    

#
#    readDefaults():
#    writeDefaults():
#

ConfigFile = '~/mhx_import.cfg'


def readDefaults():
    global toggle, theScale, theBlenderVersion, BlenderVersions
    path = os.path.realpath(os.path.expanduser(ConfigFile))
    try:
        fp = open(path, 'rU')
        print('Storing defaults')
    except:
        print('Cannot open "%s" for reading' % path)
        return
    bver = ''
    for line in fp: 
        words = line.split()
        if len(words) >= 3:
            try:
                toggle = int(words[0],16)
                theScale = float(words[1])
                theBlenderVersion = BlenderVersions.index(words[2])
            except:
                print('Configuration file "%s" is corrupt' % path)                
    fp.close()
    return

def writeDefaults():
    global toggle, theScale, theBlenderVersion, BlenderVersions
    path = os.path.realpath(os.path.expanduser(ConfigFile))
    try:
        fp = open(path, 'w')
        print('Storing defaults')
    except:
        print('Cannot open "%s" for writing' % path)
        return
    fp.write("%x %f %s" % (toggle, theScale, BlenderVersions[theBlenderVersion]))
    fp.close()
Luca Bonavita's avatar
Luca Bonavita committed
    return
Luca Bonavita's avatar
Luca Bonavita committed
#    User interface
from bpy.props import StringProperty, FloatProperty, EnumProperty, BoolProperty


MhxBoolProps = [
    ("enforce", "Enforce version", "Only accept MHX files of correct version", T_EnforceVersion),
    ("mesh", "Mesh", "Use main mesh", T_Mesh),
    ("proxy", "Proxies", "Use proxies", T_Proxy),
    ("armature", "Armature", "Use armature", T_Armature),
    ("replace", "Replace scene", "Replace scene", T_Replace),
    ("cage", "Cage", "Load mesh deform cage", T_Cage),
    ("clothes", "Clothes", "Include clothes", T_Clothes),
    ("stretch", "Stretchy limbs", "Stretchy limbs", T_Stretch),
    ("face", "Face shapes", "Include facial shapekeys", T_Face),
    ("shape", "Body shapes", "Include body shapekeys", T_Shape),
    ("symm", "Symmetric shapes", "Keep shapekeys symmetric", T_Symm),
    ("diamond", "Diamonds", "Keep joint diamonds", T_Diamond),
    ("bend", "Bend joints", "Bend joints for better IK", T_Bend),
    #("opcns", "Operator constraints", "Only for Aligorith", T_Opcns),
]

class ImportMhx(bpy.types.Operator, ImportHelper):
Luca Bonavita's avatar
Luca Bonavita committed
    '''Import from MHX file format (.mhx)'''
    bl_idname = "import_scene.makehuman_mhx"
    bl_description = 'Import from MHX file format (.mhx)'
    bl_label = "Import MHX"
    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"

    scale = FloatProperty(name="Scale", description="Default meter, decimeter = 1.0", default = theScale)
    enums = []
    for enum in BlenderVersions:
        enums.append((enum,enum,enum))
    bver = EnumProperty(name="Blender version", items=enums, default = BlenderVersions[0])
Luca Bonavita's avatar
Luca Bonavita committed

    filename_ext = ".mhx"
    filter_glob = StringProperty(default="*.mhx", options={'HIDDEN'})
    filepath = StringProperty(name="File Path", description="File path used for importing the MHX file", maxlen= 1024, default= "")
Luca Bonavita's avatar
Luca Bonavita committed

    for (prop, name, desc, flag) in MhxBoolProps:
        expr = '%s = BoolProperty(name="%s", description="%s", default=toggle&%s)' % (prop, name, desc, flag)
        exec(expr)
Luca Bonavita's avatar
Luca Bonavita committed
        
    def execute(self, context):
        global toggle, theScale, MhxBoolProps, theBlenderVersion, BlenderVersions
        toggle = 0
        for (prop, name, desc, flag) in MhxBoolProps:
            expr = '(%s if self.%s else 0)' % (flag, prop)
            toggle |=  eval(expr)
        print("execute flags %x" % toggle)
        theScale = self.scale
        theBlenderVersion = BlenderVersions.index(self.bver)
        readMhxFile(self.filepath)
Luca Bonavita's avatar
Luca Bonavita committed
        return {'FINISHED'}

    def invoke(self, context, event):
        global toggle, theScale, MhxBoolProps, theBlenderVersion, BlenderVersions
        readDefaults()
        self.scale = theScale
        self.bver = BlenderVersions[theBlenderVersion]
        for (prop, name, desc, flag) in MhxBoolProps:
            expr = 'self.%s = toggle&%s' % (prop, flag)
Luca Bonavita's avatar
Luca Bonavita committed
        context.window_manager.fileselect_add(self)
        return {'RUNNING_MODAL'}
    self.layout.operator(ImportMhx.bl_idname, text="MakeHuman (.mhx)...")
Brendon Murphy's avatar
Brendon Murphy committed
def register():
Luca Bonavita's avatar
Luca Bonavita committed
    bpy.types.INFO_MT_file_import.append(menu_func)
Brendon Murphy's avatar
Brendon Murphy committed
def unregister():
Luca Bonavita's avatar
Luca Bonavita committed
    bpy.types.INFO_MT_file_import.remove(menu_func)
Brendon Murphy's avatar
Brendon Murphy committed

if __name__ == "__main__":
Luca Bonavita's avatar
Luca Bonavita committed
    try:
        unregister()
    except:
        pass
    register()
Luca Bonavita's avatar
Luca Bonavita committed
#    Testing
Brendon Murphy's avatar
Brendon Murphy committed
#
"""
#readMhxFile("C:/Documents and Settings/xxxxxxxxxxxxxxxxxxxx/Mina dokument/makehuman/exports/foo-25.mhx", 'Classic')
readMhxFile("/home/thomas/makehuman/exports/foo-25.mhx", 1.0)

#toggle = T_Replace + T_Mesh + T_Armature + T_MHX
#readMhxFile("/home/thomas/myblends/test.mhx", 1.0)
"""