Skip to content
Snippets Groups Projects
io_import_scene_mhx.py 52.5 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 #####
    
    bl_addon_info = {
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        "name": "Import: MakeHuman (.mhx)",
    
        "author": "Thomas Larsson",
        "version": "0.9, Make Human Alpha 5",
        "blender": (2, 5, 3),
        "location": "File > Import",
        "description": "Import files in the MakeHuman eXchange format (.mhx)",
        "warning": "",
        "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/Scripts/File_I-O/Make_Human",
        "tracker_url": "https://projects.blender.org/tracker/index.php?func=detail&aid=21872&group_id=153&atid=469",
        "category": "Import/Export"}
    
    
    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
    
    **Copyright(c):**	  MakeHuman Team 2001-2010
    
    **Licensing:**		 GPL3 (see also http://sites.google.com/site/makehumandocs/licensing)
    
    **Coding Standards:**  See http://sites.google.com/site/makehumandocs/developers-guide
    
    Abstract
    MHX (MakeHuman eXchange format) importer for Blender 2.5x.
    Version 0.9
    
    """
    
    """
    Place this file in the .blender/scripts/addons dir
    You have to activated the script in the "Add-Ons" tab (user preferences).
    Access from the File > Import menu.
    """
    
    #
    #
    #
    
    import bpy
    import os
    import time
    import mathutils
    from mathutils import *
    import geometry
    import string
    
    MAJOR_VERSION = 0
    MINOR_VERSION = 9
    MHX249 = False
    Blender24 = False
    Blender25 = True
    TexDir = "~/makehuman/exports"
    
    #
    #
    #
    
    theScale = 1.0
    useMesh = 1
    doSmash = 1
    verbosity = 2
    warnedTextureDir = False
    warnedVersion = False
    
    true = True
    false = False
    Epsilon = 1e-6
    nErrors = 0
    theTempDatum = None
    
    todo = []
    
    #
    #	toggle flags
    #
    
    T_ArmIK = 0x01
    T_LegIK = 0x02
    T_Replace = 0x20
    T_Face = 0x40
    T_Shape = 0x80
    T_Mesh = 0x100
    T_Armature = 0x200
    T_Proxy = 0x400
    T_Panel = 0x800
    
    T_Rigify = 0x1000
    T_Preset = 0x2000
    T_Symm = 0x4000
    T_MHX = 0x8000
    
    toggle = T_Replace + T_ArmIK + T_LegIK + T_Mesh + T_Armature + T_Face
    
    #
    #	setFlagsAndFloats(rigFlags):
    #
    #	Global floats
    fLegIK = 0.0
    fArmIK = 0.0
    fFingerPanel = 0.0
    fFingerIK = 0.0
    fFingerCurl = 0.0
    
    #	rigLeg and rigArm flags
    T_Toes = 0x0001
    T_GoboFoot = 0x0002
    T_InvFoot = 0x0004
    
    T_FingerPanel = 0x100
    T_FingerCurl = 0x0200
    T_FingerIK = 0x0400
    
    
    T_LocalFKIK = 0x8000
    
    rigLeg = 0
    rigArm = 0
    
    def setFlagsAndFloats(rigFlags):
    	global toggle, rigLeg, rigArm
    
    	(footRig, fingerRig) = rigFlags
    	rigLeg = 0
    	rigArm = 0
    	if footRig == 'Reverse foot': rigLeg |= T_InvFoot
    	elif footRig == 'Gobo': rigLeg |= T_GoboFoot
    
    	if fingerRig == 'Panel': rigArm |= T_FingerPanel
    	elif fingerRig == 'IK': rigArm |= T_FingerIK
    	elif fingerRig == 'Curl': rigArm |= T_FingerCurl
    
    	toggle |= T_Panel
    
    	# Global floats, used as influences
    	global fFingerCurl, fLegIK, fArmIK, fFingerIK
    
    	fFingerCurl = 1.0 if rigArm&T_FingerCurl else 0.0
    	fLegIK = 1.0 if toggle&T_LegIK else 0.0
    	fArmIK = 1.0 if toggle&T_ArmIK else 0.0
    	fFingerIK = 1.0 if rigArm&T_FingerIK else 0.0
    
    	return
    
    
    #
    #	Dictionaries
    #
    
    loadedData = {
    	'NONE' : {},
    
    	'Object' : {},
    	'Mesh' : {},
    	'Armature' : {},
    	'Lamp' : {},
    	'Camera' : {},
    	'Lattice' : {},
    	'Curve' : {},
    
    	'Material' : {},
    	'Image' : {},
    	'MaterialTextureSlot' : {},
    	'Texture' : {},
    	
    	'Bone' : {},
    	'BoneGroup' : {},
    	'Rigify' : {},
    
    	'Action' : {},
    	'Group' : {},
    
    	'MeshTextureFaceLayer' : {},
    	'MeshColorLayer' : {},
    	'VertexGroup' : {},
    	'ShapeKey' : {},
    	'ParticleSystem' : {},
    
    	'ObjectConstraints' : {},
    	'ObjectModifiers' : {},
    	'MaterialSlot' : {},
    }
    
    Plural = {
    	'Object' : 'objects',
    	'Mesh' : 'meshes',
    	'Lattice' : 'lattices',
    	'Curve' : 'curves',
    	'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',
    }
    
    #
    #	Creators
    #
    
    def uvtexCreator(me, name):
    	print("uvtexCreator", me, name)
    
    	return me.uv_textures.new(name)
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    def vertcolCreator(me, name):
    	print("vertcolCreator", me, name)
    
    	return me.vertex_colors.new(name)
    
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    #
    #	loadMhx(filePath, context, flags):
    #
    
    def loadMhx(filePath, context, flags):
    	global toggle
    	toggle = flags
    	readMhxFile(filePath)
    	return
    
    #
    #	readMhxFile(filePath, rigFlags):
    #
    
    def readMhxFile(filePath, rigFlags):
    	global todo, nErrors
    	
    	fileName = os.path.expanduser(filePath)
    	(shortName, ext) = os.path.splitext(fileName)
    	if ext != ".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
    
    	setFlagsAndFloats(rigFlags)
    
    	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] == '#':
    			pass
    		elif lineSplit[0] == 'end':
    			try:
    				sub = tokens
    				tokens = stack.pop()
    				if tokens:
    					tokens[-1][2] = sub
    				level -= 1
    			except:
    				print( "Tokenizer error at or before line %d" % lineNo )
    				print( line )
    				dummy = stack.pop()
    		elif lineSplit[-1] == ';':
    			if lineSplit[0] == '\\':
    				key = lineSplit[1]
    				tokens.append([key,lineSplit[2:-1],[]])
    			else:
    				key = lineSplit[0]
    				tokens.append([key,lineSplit[1:-1],[]])
    		else:
    			key = lineSplit[0]
    			tokens.append([key,lineSplit[1:],[]])
    			stack.append(tokens)
    			level += 1
    			tokens = []
    	file.close()
    
    	if level != 0:
    		raise NameError("Tokenizer out of kilter %d" % level)	
    	clearScene()
    	print( "Parsing" )
    	parse(tokens)
    	
    	for (expr, glbals, lcals) in todo:
    		try:
    			# print("Doing %s" % expr)
    			exec(expr, glbals, lcals)
    		except:
    			msg = "Failed: "+expr
    			print( msg )
    			nErrors += 1
    			#raise NameError(msg)
    
    	print("Postprocess")
    	postProcess()
    	print("HideLayers")
    	hideLayers()
    	time2 = time.clock()
    	print("toggle = %x" % toggle)
    	msg = "File %s loaded in %g s" % (fileName, time2-time1)
    	if nErrors:
    		msg += " but there where %d errors. " % (nErrors)
    	print(msg)
    	return	# loadMhx
    
    #
    #	getObject(name, var, glbals, lcals):
    #
    
    def getObject(name, var, glbals, lcals):
    	try:
    		ob = loadedData['Object'][name]
    	except:
    		if name != "None":
    			expr = "%s = loadedData['Object'][name]" % var
    			print("Todo ", expr)
    			todo.append((expr, glbals, lcals))
    		ob = None
    	return ob
    
    #
    #	parse(tokens):
    #
    
    ifResult = False
    
    def parse(tokens):
    	global warnedVersion, MHX249, ifResult
    	
    	for (key, val, sub) in tokens:	
    		# print("Parse %s" % key)
    		data = None
    		if key == 'MHX':
    			if int(val[0]) != MAJOR_VERSION and int(val[1]) != MINOR_VERSION and not warnedVersion:
    				print("Warning: \nThis file was created with another version of MHX\n")
    				warnedVersion = True
    
    		elif key == 'MHX249':
    			MHX249 = eval(val[0])
    			print("Blender 2.49 compatibility mode is %s\n" % MHX249)
    
    		elif key == 'if':
    			try:
    				ifResult = eval(val[0])
    			except:
    				ifResult = False
    			if ifResult:
    				parse(sub)
    				
    		elif key == 'elif':
    			if not ifResult:
    				try:
    					ifResult = eval(val[0])
    				except:
    					ifResult = False
    				if ifResult:
    					parse(sub)
    		
    		elif key == 'else':
    			if not ifResult:
    				parse(sub)
    		
    
    		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 == "Object":
    			parseObject(val, sub)
    		elif key == "Mesh":
    			data = parseMesh(val, sub)
    		elif key == "Curve":
    			data = parseCurve(val, sub)
    		elif key == "Lattice":
    			data = parseLattice(val, sub)
    		elif key == "Group":
    			data = parseGroup(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 == "Process":
    			parseProcess(val, sub)
    		elif key == 'AnimationData':
    			try:
    				ob = loadedData['Object'][val[0]]
    			except:
    				ob = None
    			if ob:
    				bpy.context.scene.objects.active = ob
    				parseAnimationData(ob, sub)
    		elif key == 'ShapeKeys':
    			try:
    				ob = loadedData['Object'][val[0]]
    			except:
    				ob = None
    			if ob:
    				bpy.context.scene.objects.active = ob
    				parseShapeKeys(ob, ob.data, val, sub)
    		else:
    			data = parseDefaultType(key, val, sub)				
    
    		if data and key != 'Mesh':
    			print( data )
    	return
    
    #
    #	parseDefaultType(typ, args, tokens):
    #
    
    def parseDefaultType(typ, args, tokens):
    	global todo
    
    	name = args[0]
    	data = None
    	expr = "bpy.data.%s.new('%s')" % (Plural[typ], name)
    	print(expr)
    	data = eval(expr)
    	print("  ok", data)
    
    	bpyType = typ.capitalize()
    	print(bpyType, name, data)
    	loadedData[bpyType][name] = data
    	if data == None:
    		return None
    
    	for (key, val, sub) in tokens:
    		#print("%s %s" % (key, val))
    		defaultKey(key, val, sub, 'data', [], globals(), locals())
    	print("Done ", data)
    	return data
    	
    #
    #	concatList(elts)
    #
    
    def concatList(elts):
    	string = ""
    	for elt in elts:
    		string += " %s" % elt
    	return string
    
    #
    #	parseAction(args, tokens):
    #	parseFCurve(fcu, args, tokens):
    #	parseKeyFramePoint(pt, args, tokens):
    #
    
    def parseAction(args, tokens):
    	name = args[0]
    	if invalid(args[1]):
    		return
    
    	ob = bpy.context.object
    	bpy.ops.object.mode_set(mode='POSE')
    	if ob.animation_data:
    		ob.animation_data.action = None
    	created = {}
    	for (key, val, sub) in tokens:
    		if key == 'FCurve':
    			prepareActionFCurve(ob, created, val, sub)
    		
    	act = ob.animation_data.action
    	loadedData['Action'][name] = act
    	if act == None:
    		print("Ignoring action %s" % name)
    		return act
    	act.name = name
    	print("Action", name, act, ob)
    	
    	for (key, val, sub) in tokens:
    		if key == 'FCurve':
    			fcu = parseActionFCurve(act, ob, val, sub)
    		else:
    			defaultKey(key, val, sub, 'act', [], globals(), locals())
    	ob.animation_data.action = None
    	bpy.ops.object.mode_set(mode='OBJECT')
    	return act
    
    def prepareActionFCurve(ob, created, args, tokens):			
    	dataPath = args[0]
    	index = args[1]
    	(expr, channel) = channelFromDataPath(dataPath, index)
    	try:
    		if channel in created[expr]:
    			return
    		else:
    			created[expr].append(channel)
    	except:
    		created[expr] = [channel]
    
    	times = []
    	for (key, val, sub) in tokens:
    		if key == 'kp':
    			times.append(int(val[0]))
    
    	try:
    		data = eval(expr)
    	except:
    		print("Ignoring illegal expression: %s" % expr)
    		return
    
    	n = 0
    	for t in times:
    		#bpy.context.scene.current_frame = t
    		bpy.ops.anim.change_frame(frame = t)
    		try:
    			data.keyframe_insert(channel)
    			n += 1
    		except:
    			pass
    			#print("failed", data, expr, channel)
    	if n != len(times):
    		print("Mismatch", n, len(times), expr, channel)
    	return
    
    def channelFromDataPath(dataPath, index):
    	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)
    
    def parseActionFCurve(act, ob, args, tokens):
    	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.use_interpolation = 'LINEAR'
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    				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
    
    def parseKeyFramePoint(pt, args, tokens):
    	pt.co = (float(args[0]), float(args[1]))
    	if len(args) > 2:
    
    		pt.handle_left = (float(args[2]), float(args[3]))
    		pt.handle_right = (float(args[3]), float(args[5]))
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    	return pt
    
    #
    #	parseAnimationData(rna, tokens):
    #	parseDriver(drv, args, tokens):
    #	parseDriverVariable(var, args, tokens):
    #
    
    def parseAnimationData(rna, tokens):
    	if 0 and toggle & T_MHX:
    		return
    	if rna.animation_data == None:	
    		rna.animation_data_create()
    	adata = rna.animation_data
    	for (key, val, sub) in tokens:
    		if key == 'FCurve':
    			fcu = parseAnimDataFCurve(adata, rna, val, sub)
    		else:
    			defaultKey(key, val, sub, 'adata', [], globals(), locals())
    	return adata
    
    def parseAnimDataFCurve(adata, rna, args, tokens):
    	if invalid(args[2]):
    		return
    	dataPath = args[0]
    	index = int(args[1])
    	# print("parseAnimDataFCurve", adata, dataPath, index)
    	for (key, val, sub) in tokens:
    		if key == 'Driver':
    			fcu = parseDriver(adata, dataPath, index, rna, val, sub)
    		elif key == 'FModifier':
    			parseFModifier(fcu, val, sub)
    		else:
    			defaultKey(key, val, sub, 'fcu', [], globals(), locals())
    	return fcu
    
    """
    		fcurve = con.driver_add("influence", 0)
    		driver = fcurve.driver
    		driver.type = 'AVERAGE'
    """
    def parseDriver(adata, dataPath, index, rna, args, tokens):
    	if dataPath[-1] == ']':
    		words = dataPath.split(']')
    		expr = "rna." + words[0] + ']'
    		pwords = words[1].split('"')
    		prop = pwords[1]
    		# print("prop", expr, prop)
    		bone = eval(expr)
    		return None
    	else:
    		words = dataPath.split('.')
    		channel = words[-1]
    		expr = "rna"
    		for n in range(len(words)-1):
    			expr += "." + words[n]
    		expr += ".driver_add('%s', index)" % channel
    	
    	# print("expr", rna, expr)
    	fcu = eval(expr)
    	drv = fcu.driver
    	drv.type = args[0]
    	for (key, val, sub) in tokens:
    		if key == 'DriverVariable':
    			var = parseDriverVariable(drv, rna, val, sub)
    		else:
    			defaultKey(key, val, sub, 'drv', [], globals(), locals())
    	return fcu
    
    def parseDriverVariable(drv, rna, args, tokens):
    	var = drv.variables.new()
    	var.name = args[0]
    	var.type = args[1]
    	nTarget = 0
    	# print("var", var, var.name, var.type)
    	for (key, val, sub) in tokens:
    		if key == 'Target':
    			parseDriverTarget(var, nTarget, rna, val, sub)
    			nTarget += 1
    		else:
    			defaultKey(key, val, sub, 'var', [], globals(), locals())
    	return var
    
    def parseFModifier(fcu, args, tokens):
    	#fmod = fcu.modifiers.new()
    	fmod = fcu.modifiers[0]
    	#fmod.type = args[0]
    	#print("fmod", fmod, fmod.type)
    	for (key, val, sub) in tokens:
    		defaultKey(key, val, sub, 'fmod', [], globals(), locals())
    	return fmod
    
    """
    		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
    """
    def parseDriverTarget(var, nTarget, rna, args, tokens):
    	targ = var.targets[nTarget]
    	# targ.rna_path = args[0]
    	# targ.id_type = args[1]
    	targ.id = loadedData['Object'][args[0]]
    	for (key, val, sub) in tokens:
    		defaultKey(key, val, sub, 'targ', [], globals(), locals())
    
    	#print("Targ", targ, targ.id, targ.data_path, targ.id_type, targ.bone_target, targ.use_local_space_transform)
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    	return targ
    
    	
    #
    #	parseMaterial(args, ext, tokens):
    #	parseMTex(mat, args, tokens):
    #	parseTexture(args, tokens):
    #
    
    def parseMaterial(args, tokens):
    	global todo
    	name = args[0]
    	#print("Parse material "+name)
    	mat = bpy.data.materials.new(name)
    	if mat == None:
    		return None
    	loadedData['Material'][name] = mat
    	#print("Material %s %s %s" % (mat, name, loadedData['Material'][name]))
    	for (key, val, sub) in tokens:
    		if key == 'MTex':
    			parseMTex(mat, val, sub)
    		elif key == 'Ramp':
    			parseRamp(mat, val, sub)
    		elif key == 'SSS':
    			parseSSS(mat, val, sub)
    		elif key == 'Strand':
    			parseStrand(mat, val, sub)
    		else:
    
    			exclude = ['specular_intensity', 'use_tangent_shading']
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    			defaultKey(key, val, sub, 'mat', [], globals(), locals())
    	#print("Done ", mat)
    	
    	return mat
    
    def parseMTex(mat, args, tokens):
    	global todo
    	index = int(args[0])
    	texname = args[1]
    	texco = args[2]
    	mapto = args[3]
    
    	mat.add_texture(texture = loadedData['Texture'][texname], texture_coordinates = texco, map_to = mapto)
    	mtex = mat.texture_slots[index]
    	#mat.use_textures[index] = Bool(use)
    
    	for (key, val, sub) in tokens:
    		defaultKey(key, val, sub, "mtex", [], globals(), locals())
    
    	return mtex
    
    def parseTexture(args, tokens):
    	global todo
    	if verbosity > 2:
    		print( "Parsing texture %s" % args )
    
    	tex = bpy.data.textures.new(name=args[0], type=args[1])
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    	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)
    		else:
    			defaultKey(key, val,  sub, "tex", ['use_nodes', 'use_textures', 'contrast'], globals(), locals())
    
    	return tex
    
    def parseRamp(data, args, tokens):
    	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())
    	
    def parseSSS(mat, args, tokens):
    	sss = mat.subsurface_scattering
    	for (key, val, sub) in tokens:
    		defaultKey(key, val, sub, "sss", [], globals(), locals())
    
    def parseStrand(mat, args, tokens):
    	strand = mat.strand
    	for (key, val, sub) in tokens:
    		defaultKey(key, val, sub, "strand", [], globals(), locals())
    
    #
    #	doLoadImage(filepath):
    #	loadImage(filepath):
    #	parseImage(args, tokens):
    #
    
    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
    
    
    def loadImage(filepath):
    	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
    	
    def parseImage(args, tokens):
    	global todo
    	imgName = args[0]
    	img = None
    	for (key, val, sub) in tokens:
    		if key == 'Filename':
    			filename = val[0]
    			for n in range(1,len(val)):
    				filename += " " + val[n]
    			img = loadImage(filename)
    			if img == None:
    				return None
    			img.name = imgName
    		else:
    
    			defaultKey(key, val,  sub, "img", ['depth', 'is_dirty', 'has_data', 'size', 'type'], globals(), locals())
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    	print ("Image %s" % img )
    	loadedData['Image'][imgName] = img
    	return img
    
    #
    #	parseObject(args, tokens):
    #	createObject(type, name, data, datName):
    #	createObjectAndData(args, typ):
    #
    	
    def parseObject(args, tokens):
    	if verbosity > 2:
    		print( "Parsing object %s" % args )
    	name = args[0]
    	typ = args[1]
    	datName = args[2]
    	try:
    		data = loadedData[typ.capitalize()][datName]	
    	except:
    		data = None
    
    	if data == None and typ != 'EMPTY':
    		print("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")
    	except:
    		ob = createObject(typ, name, data, datName)
    	if bpy.context.object != ob:
    		print("Context", ob, bpy.context.object, bpy.context.scene.objects.active)
    		# ob = foo 
    
    	for (key, val, sub) in tokens:
    		if key == 'Modifier':
    			parseModifier(ob, val, sub)
    		elif key == 'Constraint':
    			parseConstraint(ob.constraints, val, sub)
    		elif key == 'AnimationData':
    			if eval(val[0]):
    				parseAnimationData(ob, sub)
    		elif key == 'ParticleSystem':
    			parseParticleSystem(ob, val, sub)
    		else:
    			defaultKey(key, val, sub, "ob", ['type', 'data'], globals(), locals())
    
    	# Needed for updating layers
    	bpy.ops.object.mode_set(mode='EDIT')
    	bpy.ops.object.mode_set(mode='OBJECT')
    	return
    
    def createObject(typ, name, data, datName):
    	#print( "Creating object %s %s %s" % (typ, name, data) )	
    	ob = bpy.data.objects.new(name, data)
    	loadedData[typ][datName] = data
    	loadedData['Object'][name] = ob
    	return ob
    	
    def linkObject(ob, data):
    	#print("Data", data, ob.data)
    	if data and ob.data == None:
    		ob.data = 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 createObjectAndData(args, typ):
    	datName = args[0]
    	obName = args[1]
    	bpy.ops.object.add(type=typ.upper())
    	ob = bpy.context.object
    	ob.name = obName
    	ob.data.name = datName
    	loadedData[typ][datName] = ob.data
    	loadedData['Object'][obName] = ob
    	return ob.data
    
    
    #
    #	parseModifier(ob, args, tokens):
    #
    
    def parseModifier(ob, args, tokens):
    	name = args[0]
    	typ = args[1]
    	if typ == 'PARTICLE_SYSTEM':
    		return None
    	mod = ob.modifiers.new(name, typ)
    	for (key, val, sub) in tokens:
    		defaultKey(key, val, sub, 'mod', [], globals(), locals())
    	return mod