From b1961c2097c4857482ccd20a309053565b1e124f Mon Sep 17 00:00:00 2001
From: Brendon Murphy <meta.androcto1@gmail.com>
Date: Wed, 12 May 2010 13:33:53 +0000
Subject: [PATCH] make human import. imports fully rigged, textured characters
 from make human alpha 5. (current MH release)

---
 import_scene_mhx.py | 2243 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 2243 insertions(+)
 create mode 100644 import_scene_mhx.py

diff --git a/import_scene_mhx.py b/import_scene_mhx.py
new file mode 100644
index 000000000..cf1afbb74
--- /dev/null
+++ b/import_scene_mhx.py
@@ -0,0 +1,2243 @@
+""" 
+**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
+
+"""
+
+bl_addon_info = {
+	'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)',
+	'url': 'http://wiki.blender.org/index.php/Extensions:2.5/Py/' \
+        'Scripts/File_I-O/Make_Human',
+	'category': 'Import/Export'}
+
+"""
+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)
+	me.add_uv_texture()
+	uvtex = me.uv_textures[-1]
+	uvtex.name = name
+	return uvtex
+
+
+def vertcolCreator(me, name):
+	print("vertcolCreator", me, name)
+	me.add_vertex_color()
+	vcol = me.vertex_colors[-1]
+	vcol.name = name
+	return vcol
+		
+
+#
+#	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.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
+
+def parseKeyFramePoint(pt, args, tokens):
+	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
+
+#
+#	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_transforms)
+	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', 'tangent_shading']
+			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 )
+	name = args[0]
+	tex = bpy.data.textures.new(name)
+	typ = args[1]
+	tex.type = typ
+	tex = tex.recast_type()
+	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', '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):
+#	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
+
+#
+#	parseParticleSystem(ob, args, tokens):
+#	parseParticles(particles, args, tokens):
+#	parseParticle(par, args, tokens):
+#
+
+def parseParticleSystem(ob, args, tokens):
+	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
+
+def parseParticles(psys, args, tokens):
+	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
+
+def parseParticle(par, args, tokens):
+	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
+
+#
+#	unpackList(list_of_tuples):
+#
+
+def unpackList(list_of_tuples):
+	l = []
+	for t in list_of_tuples:
+		l.extend(t)
+	return l
+
+#
+#	parseMesh (args, tokens):
+#
+
+def parseMesh (args, tokens):
+	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:
+		#x = me.from_pydata(verts, [], faces)
+		me.add_geometry(len(verts), 0, len(faces))
+		me.verts.foreach_set("co", unpackList(verts))
+		me.faces.foreach_set("verts_raw", unpackList(faces))
+	else:
+		#x = me.from_pydata(verts, edges, [])
+		me.add_geometry(len(verts), len(edges), 0)
+		me.verts.foreach_set("co", unpackList(verts))
+		me.edges.foreach_set("verts", unpackList(edges))
+	#print(x)
+	me.update()
+	#print(me)
+	linkObject(ob, me)
+		
+	mats = []
+	for (key, val, sub) in tokens:
+		if key == 'Verts' or \
+		   key == 'Edges':
+				pass
+		elif key == 'Faces':
+			parseFaces2(sub, me)
+		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:
+				me.add_material(loadedData['Material'][val[0]])
+			except:
+				print("Could not add material", val[0])
+		else:
+			defaultKey(key, val,  sub, "me", [], globals(), locals())
+
+	return me
+
+#
+#	parseVerts(tokens):
+#	parseEdges(tokens):
+#	parseFaces(tokens):
+#	parseFaces2(tokens, me):		
+#
+
+def parseVerts(tokens):
+	verts = []
+	for (key, val, sub) in tokens:
+		if key == 'v':
+			verts.append( (float(val[0]), float(val[1]), float(val[2])) )
+	return verts
+
+def parseEdges(tokens):
+	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]), 0]
+			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.smooth = int(val[1])
+			n += 1
+		elif key == 'ftall':
+			mat = int(val[0])
+			smooth = int(val[1])
+			for f in me.faces:
+				f.material_index = mat
+				f.smooth = smooth
+	return
+
+
+#
+#	parseUvTexture(args, tokens, me):
+#	parseUvTexData(args, tokens, uvdata):
+#
+
+def parseUvTexture(args, tokens, me):
+	me.add_uv_texture()
+	uvtex = me.uv_textures[-1]
+	name = args[0]
+	uvtex.name = name
+	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
+
+def parseUvTexData(args, tokens, data):
+	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):
+#
+
+def parseVertColorLayer(args, tokens, me):
+	name = args[0]
+	print("VertColorLayer", name)
+	me.add_vertex_color()
+	vcol = me.vertex_colors[-1]
+	vcol.name = 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
+
+def parseVertColorData(args, tokens, data):
+	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
+
+
+#
+#	parseVertexGroup(ob, me, args, tokens):
+#
+
+def parseVertexGroup(ob, me, args, tokens):
+	global toggle
+	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.add_vertex_group(grpName)
+		group.name = grpName
+		loadedData['VertexGroup'][grpName] = group
+		for (key, val, sub) in tokens:
+			if key == 'wv':
+				ob.add_vertex_to_group( int(val[0]), group, float(val[1]), 'REPLACE')
+	return
+
+
+#
+#	parseShapeKeys(ob, me, args, tokens):
+#	parseShapeKey(ob, me, args, tokens):
+#	addShapeKey(ob, name, vgroup, tokens):
+#	doShape(name):
+#
+
+def doShape(name):
+	if (toggle & T_Shape+T_Face) and (name == 'Basis'):
+		return True
+	else:
+		return (toggle & T_Face)
+
+def parseShapeKeys(ob, me, args, tokens):
+	if bpy.context.object == None:
+		return
+	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, sub)
+	return
+
+
+def parseShapeKey(ob, me, args, tokens):
+	if verbosity > 0:
+		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
+
+def addShapeKey(ob, name, vgroup, tokens):
+	bpy.ops.object.shape_key_add(False)
+	skey = ob.active_shape_key
+	if name != 'Basis':
+		skey.relative_key = loadedData['ShapeKey']['Basis']
+	skey.name = name
+	if vgroup:
+		skey.vertex_group = vgroup
+	loadedData['ShapeKey'][name] = skey
+
+	for (key, val, sub) in tokens:
+		if key == 'sv':
+			index = int(val[0])
+			pt = skey.data[index].co
+			pt[0] += float(val[1])
+			pt[1] += float(val[2])
+			pt[2] += float(val[3])
+		else:
+			defaultKey(key, val,  sub, "skey", [], globals(), locals())
+
+	return	
+
+	
+#
+#	parseArmature (obName, args, tokens)
+#
+
+def parseArmature (args, tokens):
+	global toggle,  theScale
+	if verbosity > 2:
+		print( "Parsing armature %s" % args )
+	
+	amtname = args[0]
+	obname = args[1]
+	mode = args[2]
+	
+	if mode == 'Rigify':
+		toggle |= T_Rigify
+		theScale = 0.1
+		return parseRigify(amtname, obname, tokens)
+
+	toggle &= ~T_Rigify
+	theScale = 1.0
+	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.edit_bones, sub, heads, tails)
+				loadedData['Bone'][bname] = bone
+		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.edit_bones, sub, heads, tails)
+		else:
+			defaultKey(key, val,  sub, "amt", ['MetaRig'], globals(), locals())
+	bpy.ops.object.mode_set(mode='OBJECT')
+	return amt
+		
+#
+#	parseBone(bone, bones, tokens, heads, tails):
+#
+
+def parseBone(bone, bones, tokens, heads, tails):
+	global todo
+
+	for (key, val, sub) in tokens:
+		if key == "head":
+			bone.head = (float(val[0]), float(val[1]), float(val[2]))
+		elif key == "tail":
+			bone.tail = (float(val[0]), float(val[1]), float(val[2]))
+		elif key == "head-as":
+			target = val[0]
+			if val[1] == 'head':
+				bone.head = heads[bone.name] + bones[target].head - heads[target]
+			elif val[1] == 'tail':
+				bone.head = heads[bone.name] + bones[target].tail - tails[target]
+			else:
+				raise NameError("head-as %s" % val)
+		elif key == "tail-as":
+			target = val[0]
+			if val[1] == 'head':
+				bone.tail = tails[bone.name] + bones[target].head - heads[target]
+			elif val[1] == 'tail':
+				bone.tail = tails[bone.name] + bones[target].tail - tails[target]
+			else:
+				raise NameError("tail-as %s" % val)
+		elif key == 'restrict_select':
+			pass
+		else:
+			defaultKey(key, val,  sub, "bone", [], globals(), locals())
+
+	return bone
+
+#
+#	parsePose (args, tokens):
+#
+
+def parsePose (args, tokens):
+	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):
+#
+
+def parseBoneGroup(pose, nGrps, args, tokens):
+	global todo
+	return
+	print( "Parsing bonegroup %s" % args )
+	name = args[0]
+	print(dir(pose.bone_groups))
+	bg = pose.bone_groups.add()
+	print("Created", bg)
+	loadedData['BoneGroup'][name] = bg
+	for (key, val, sub) in tokens:
+		defaultKey(key, val,  sub, "bg", [], globals(), locals())
+	return
+
+def parsePoseBone(pbones, ob, args, tokens):
+	global todo
+	#print( "Parsing posebone %s" % args )
+	if invalid(args[1]):
+		return
+	name = args[0]
+	pb = pbones[name]
+
+	# Make posebone active - don't know how to do this in pose mode
+	bpy.ops.object.mode_set(mode='OBJECT')
+	ob.data.bones.active = pb.bone
+	bpy.ops.object.mode_set(mode='POSE')
+
+	for (key, val, sub) in tokens:
+		if key == 'Constraint':
+			cns = parseConstraint(pb.constraints, val, sub)
+		elif key == 'bpyops':
+			expr = "bpy.ops.%s" % val[0]
+			print(expr)
+			print("ob", bpy.context.active_object)
+			print("b", bpy.context.active_bone)
+			print("pb", bpy.context.active_pose_bone)
+			print("md", bpy.context.mode)
+			exec(expr)
+			print("alive")
+		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)
+		else:
+			defaultKey(key, val,  sub, "pb", [], globals(), locals())
+	#print("pb %s done" % name)
+	return
+
+def parseArray(data, exts, args):
+	n = 1
+	for ext in exts:
+		expr = "data.%s = %s" % (ext, args[n])
+		# print(expr)
+		exec(expr)
+		n += 1
+	return
+		
+#
+#	parseConstraint(constraints, args, tokens)
+#
+
+def parseConstraint(constraints, args, tokens):
+	if invalid(args[2]):
+		return None
+	cns = constraints.new(args[1])
+	#bpy.ops.pose.constraint_add(type=args[1])
+	#cns = pb.constraints[-1]
+
+	cns.name = args[0]
+	#print("cns", cns.name)
+	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, ["pos_lock_x", "pos_lock_y", "pos_lock_z"], val)
+		elif key == 'rot_lock':
+			parseArray(cns, ["rot_lock_x", "rot_lock_y", "rot_lock_z"], val)
+		else:
+			defaultKey(key, val,  sub, "cns", [], globals(), locals())
+	#print("cns %s done" % cns.name)
+	return cns
+	
+def insertInfluenceIpo(cns, bone):
+	global todo
+	if bone != 'PArmIK_L' and bone != 'PArmIK_R' and bone != 'PLegIK_L' and bone != 'PLegIK_R':
+		return False
+
+	if (toggle & T_FKIK):
+		fcurve = cns.driver_add("influence", 0)
+		fcurve.driver.type = 'AVERAGE'
+
+		var = fcurve.driver.variables.new()
+		var.name = bone
+		var.targets[0].id_type = 'OBJECT'
+		var.targets[0].id = getObject('HumanRig', 'var.targets[0].id', globals(), locals())
+		var.targets[0].bone_target = bone
+		var.targets[0].transform_type = 'LOC_X'
+		# controller_path = fk_chain.arm_p.path_to_id()
+		#var.targets[0].data_path = controller_path + '["hinge"]'
+
+		mod = fcurve.modifiers[0]
+		mod.poly_order = 2
+		mod.coefficients[0] = 0.0
+		mod.coefficients[1] = 1.0
+	elif bone == 'PArmIK_L' or bone == 'PArmIK_R':
+		if toggle & T_ArmIK:
+			cns.influence = 1.0
+		else:
+			cns.influence = 0.0
+	elif bone == 'PLegIK_L' or bone == 'PLegIK_R':
+		if toggle & T_LegIK:
+			cns.influence = 1.0
+		else:
+			cns.influence = 0.0
+
+	return True
+
+#
+#	parseCurve (args, tokens):
+#	parseNurb(cu, nNurbs, args, tokens):
+#	parseBezier(nurb, n, args, tokens):
+#
+
+def parseCurve (args, tokens):
+	global todo
+	if verbosity > 2:
+		print( "Parsing curve %s" % args )
+	cu = createObjectAndData(args, 'Curve')
+
+	nNurbs = 0
+	for (key, val, sub) in tokens:
+		if key == 'Nurb':
+			parseNurb(cu, nNurbs, val, sub)
+			nNurbs += 1
+		else:
+			defaultKey(key, val, sub, "cu", [], globals(), locals())
+	return
+
+def parseNurb(cu, nNurbs, args, tokens):
+	if nNurbs > 0:
+		bpy.ops.object.curve_add(type='BEZIER_CURVE')
+	print(cu.splines, list(cu.splines), nNurbs)
+	nurb = cu.splines[nNurbs]
+	nPoints = int(args[0])
+	print(nurb, nPoints)
+	for n in range(2, nPoints):
+		bpy.ops.curve.extrude(mode=1)		
+
+	n = 0
+	for (key, val, sub) in tokens:
+		if key == 'bz':
+			parseBezier(nurb, n, val, sub)
+			n += 1
+		elif key == 'pt':
+			parsePoint(nurb, n, val, sub)
+			n += 1
+		else:
+			defaultKey(key, val, sub, "nurb", [], globals(), locals())
+	return
+	
+def parseBezier(nurb, n, args, tokens):
+	bez = nurb[n]
+	bez.co = eval(args[0])	
+	bez.handle1 = eval(args[1])	
+	bez.handle1_type = args[2]
+	bez.handle2 = eval(args[3])	
+	bez.handle2_type = args[4]
+	return
+
+def parsePoint(nurb, n, args, tokens):
+	pt = nurb[n]
+	pt.co = eval(args[0])
+	return
+
+#
+#	parseLattice (args, tokens):
+#
+
+def parseLattice (args, tokens):
+	global todo
+	if verbosity > 2:
+		print( "Parsing lattice %s" % args )
+	lat = createObjectAndData(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
+
+def parseLatticePoints(args, tokens, points):
+	global todo
+	n = 0
+	for (key, val, sub) in tokens:
+		if key == 'pt':
+			v = points[n].co
+			(x,y,z) = eval(val[0])
+			v.x = x
+			v.y = y
+			v.z = z
+
+			v = points[n].deformed_co
+			(x,y,z) = eval(val[1])
+			v.x = x
+			v.y = y
+			v.z = z
+
+			n += 1
+	return
+
+#
+#	parseGroup (args, tokens):
+#
+
+def parseGroup (args, tokens):
+	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):
+	global todo
+	for (key, val, sub) in tokens:
+		if key == 'ob':
+			try:
+				ob = loadedData['Object'][val[0]]
+				grp.objects.link(ob)
+			except:
+				pass
+	return
+
+#
+#	postProcess()
+#	setInfluence(bones, cnsName, w):
+#
+
+def postProcess():
+	if not toggle & T_MHX:
+		return
+	if toggle & T_Rigify:
+		return
+		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']
+			mod = ob.modifiers[0]
+			print(ob, mod, mod.object)
+			mod.object = rig
+			print("Rig changed", mod.object)
+	return			
+		
+#
+#	parseProcess(args, tokens):
+#
+
+def parseProcess(args, tokens):
+	return
+	rig = loadedData['Object'][args[0]]
+	parents = {}
+	objects = []
+
+	for (key, val, sub) in tokens:
+		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':
+			print(val)
+			axis = val[1]
+			angle = float(val[2])
+			mat = mathutils.RotationMatrix(angle, 4, axis)
+			try:
+				pb = pbones[val[0]]
+				prod = pb.matrix_local * mat
+				for i in range(4):
+					for j in range(4):
+						pb.matrix_local[i][j] = prod[i][j]
+				print("Done", pb.matrix_local)
+			except:
+				pass
+		elif key == 'Pose':
+			bpy.context.scene.objects.active = rig
+			bpy.ops.object.mode_set(mode='POSE')
+			pbones = rig.pose.bones	
+		elif key == 'Edit':
+			bpy.context.scene.objects.active = rig
+			bpy.ops.object.mode_set(mode='EDIT')
+			ebones = rig.data.edit_bones	
+		elif key == 'Object':
+			bpy.ops.object.mode_set(mode='OBJECT')
+			try:
+				ob = loadedData['Object'][val[0]]
+				objects.append((ob,sub))
+			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)
+
+	for (ob,tokens) in objects:
+		bpy.context.scene.objects.active = ob
+		bpy.ops.object.visual_transform_apply()
+		#print("vis", list(ob.modifiers))
+		bpy.ops.object.modifier_apply(apply_as='DATA', modifier='Armature')
+		#print("app", list(ob.modifiers))
+
+	bpy.context.scene.objects.active = rig
+	bpy.ops.object.mode_set(mode='POSE')
+	bpy.ops.pose.armature_apply()
+	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.connected:
+			par.tail = eb.head
+		eb.parent = par
+	bpy.ops.object.mode_set(mode='OBJECT')
+
+	for (ob,tokens) in objects:
+		bpy.context.scene.objects.active = ob
+		for (key, val, sub) in tokens:
+			if key == 'Modifier':
+				parseModifier(ob, val, sub)
+
+	return			
+
+#
+#	defaultKey(ext, args, tokens, var, exclude, glbals, lcals):
+#
+
+def defaultKey(ext, args, tokens, var, exclude, glbals, lcals):
+	global todo
+
+	if ext == 'Property':
+		expr = "%s['%s'] = %s" % (var, args[0], args[1])
+		print("Property", expr)
+		exec(expr, glbals, lcals)
+		#print("execd")
+		return
+		
+	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)
+
+		if data == None:
+			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:
+		#print("Failed ",expr)
+		todo.append((expr, glbals, lcals))
+	return
+			
+#
+#	parseBoolArray(mask):
+#
+
+def parseBoolArray(mask):
+	list = []
+	for c in mask:
+		if c == '0':			
+			list.append(False)
+		else:
+			list.append(True)
+	return list
+
+#	parseMatrix(args, tokens)
+#
+
+def parseMatrix(args, tokens):
+	matrix = Matrix( [1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1] )
+	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
+
+#
+#	parseDefault(data, tokens, exclude):
+#
+
+def parseDefault(data, tokens):
+	for (key, val, sub) in tokens:	
+		defaultKey(key, val, sub, "data", exclude, globals(), locals())
+
+
+#
+#	Utilities	
+#
+
+#
+#	extractBpyType(data):
+#
+
+def extractBpyType(data):
+	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
+
+#
+#	Bool(string):
+#
+
+def Bool(string):
+	if string == 'True':
+		return True
+	elif string == 'False':
+		return False
+	else:
+		raise NameError("Bool %s?" % string)
+		
+#
+#	invalid(condition):
+#
+
+def invalid(condition):
+	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
+	
+#
+#	clearScene(context):
+#	hideLayers():
+#
+	
+def clearScene():
+	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 == "MESH" or ob.type == "ARMATURE":
+			scn.objects.active = ob
+			bpy.ops.object.mode_set(mode='OBJECT')
+			scn.objects.unlink(ob)
+			del ob
+	#print(scn.objects)
+	return scn
+
+def hideLayers():
+	scn = bpy.context.scene
+	for n in range(len(scn.layers)):
+		if n < 3:
+			scn.layers[n] = True
+		else:
+			scn.layers[n] = False
+	return
+
+#
+#	User interface
+#
+
+DEBUG= False
+from bpy.props import *
+
+class IMPORT_OT_makehuman_mhx(bpy.types.Operator):
+	'''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"
+
+	path = StringProperty(name="File Path", description="File path used for importing the MHX file", maxlen= 1024, default= "")
+
+	#preset = BoolProperty(name="Use rig preset", description="Use rig preset (Classic/Gobo)?", default=True)
+	#presetRig = EnumProperty(name="Rig", description="Choose preset rig", 
+	#	items = [('Classic','Classic','Classic'), ('Gobo','Gobo','Gobo')], default = '1')
+	footRig = EnumProperty(name="Foot rig", description="Foot rig", 
+		items = [('Reverse foot','Reverse foot','Reverse foot'), ('Gobo','Gobo','Gobo')], default = '1')
+	fingerRig = EnumProperty(name="Finger rig", description="Finger rig", 
+		items = [('Panel','Panel','Panel'), ('Curl','Curl','Curl'), ('IK','IK','IK')], default = '1')
+
+	mesh = BoolProperty(name="Mesh", description="Use main mesh", default=toggle&T_Mesh)
+	armature = BoolProperty(name="Armature", description="Use armature", default=toggle&T_Armature)
+	proxy = BoolProperty(name="Proxy", description="Use proxy object", default=toggle&T_Proxy)
+	replace = BoolProperty(name="Replace scene", description="Replace scene", default=toggle&T_Replace)
+	face = BoolProperty(name="Face shapes", description="Include facial shapekeys", default=toggle&T_Face)
+	shape = BoolProperty(name="Body shapes", description="Include body shapekeys", default=toggle&T_Shape)
+	symm = BoolProperty(name="Symmetric shapes", description="Keep shapekeys symmetric", default=toggle&T_Symm)
+		
+	def execute(self, context):
+		global toggle
+		O_Mesh = T_Mesh if self.properties.mesh else 0
+		O_Armature = T_Armature if self.properties.armature else 0
+		O_Proxy = T_Proxy if self.properties.proxy else 0
+		O_Replace = T_Replace if self.properties.replace else 0
+		O_Face = T_Face if self.properties.face else 0
+		O_Shape = T_Shape if self.properties.shape else 0
+		O_Symm = T_Symm if self.properties.symm else 0
+		#O_Preset = T_Preset if self.properties.preset else 0
+		toggle =  O_Mesh | O_Armature | O_Proxy | T_ArmIK | T_LegIK | O_Replace | O_Face | O_Shape | O_Symm | T_MHX 
+
+		
+		readMhxFile(self.properties.path, 	
+			(self.properties.footRig, 
+			self.properties.fingerRig))
+		return {'FINISHED'}
+
+	def invoke(self, context, event):
+		wm = context.manager
+		wm.add_fileselect(self)
+		return {'RUNNING_MODAL'}
+
+'''
+class MakeHumanFKIKPanel(bpy.types.Panel):
+	bl_label = "MakeHuman FK/IK"
+	bl_space_type = "VIEW_3D"
+	bl_region_type = "UI"
+	
+	def draw(self, context):
+		layout = self.layout
+		ob = bpy.context.active_object
+		if ob.type == 'ARMATURE':
+			layout.row().prop(ob, "PArmIK_L")
+			layout.row().prop(ob, "PArmIK_R")
+			layout.row().prop(ob, "PLegIK_L")
+			layout.row().prop(ob, "PLegIK_R")
+
+			layout.row().prop(ob, "PHandLocal_L")
+			layout.row().prop(ob, "PHandLocal_R")
+			layout.row().prop(ob, "PFootLocal_L")
+			layout.row().prop(ob, "PFootLocal_R")
+		return
+		  
+class MakeHumanFingerPanel(bpy.types.Panel):
+	bl_label = "MakeHuman Fingers"
+	bl_space_type = "VIEW_3D"
+	bl_region_type = "UI"
+	
+	def draw(self, context):
+		layout = self.layout
+		pb = bpy.context.active_pose_bone
+		layout.row().prop(pb, "MHRelax")
+		layout.row().prop(pb, "MHCurl")
+		layout.row().prop(pb, "MHCone")
+		layout.row().prop(pb, "MHSpread")
+		layout.row().prop(pb, "MHScrunch")
+		layout.row().prop(pb, "MHLean")
+		return
+		  
+
+def registerPanels():
+	bpy.types.Object.FloatProperty(attr="PArmIK_L", name="L arm - IK", default = 0, min = 0.0, max = 1.0)
+	bpy.types.Object.FloatProperty(attr="PArmIK_R", name="R arm - IK", default = 0, min = 0.0, max = 1.0)
+	bpy.types.Object.FloatProperty(attr="PLegIK_L", name="L leg - IK", default = 0, min = 0.0, max = 1.0)
+	bpy.types.Object.FloatProperty(attr="PLegIK_R", name="R leg - IK", default = 0, min = 0.0, max = 1.0)
+
+	bpy.types.Object.FloatProperty(attr="PHandLocal_L", name="L hand - Loc", default = 0, min = 0.0, max = 1.0)
+	bpy.types.Object.FloatProperty(attr="PHandLocal_R", name="R hand - Loc", default = 0, min = 0.0, max = 1.0)
+	bpy.types.Object.FloatProperty(attr="PFootLocal_L", name="L foot - Loc", default = 0, min = 0.0, max = 1.0)
+	bpy.types.Object.FloatProperty(attr="PFootLocal_R", name="R foot - Loc", default = 0, min = 0.0, max = 1.0)
+
+	bpy.types.PoseBone.FloatProperty(attr="MHCone", name="Cone", default = 0, min = -0.5, max = 1.0)
+	bpy.types.PoseBone.FloatProperty(attr="MHRelax", name="Relax", default = 0, min = -0.5, max = 1.0)
+	bpy.types.PoseBone.FloatProperty(attr="MHCurl", name="Curl", default = 0, min = -0.5, max = 1.0)
+	bpy.types.PoseBone.FloatProperty(attr="MHLean", name="Lean", default = 0, min = -1.0, max = 1.0)
+	bpy.types.PoseBone.FloatProperty(attr="MHScrunch", name="Scrunch", default = 0, min = -0.5, max = 1.0)
+	bpy.types.PoseBone.FloatProperty(attr="MHSpread", name="Spread", default = 0, min = -0.5, max = 1.0)
+
+	bpy.types.register(MakeHumanFKIKPanel)
+	bpy.types.register(MakeHumanFingerPanel)
+
+def unregisterPanels():
+	bpy.types.unregister(MakeHumanFKIKPanel)
+	bpy.types.unregister(MakeHumanFingerPanel)
+	'''
+
+def register():
+	# registerPanels()
+	bpy.types.register(IMPORT_OT_makehuman_mhx)
+	menu_func = lambda self, context: self.layout.operator(IMPORT_OT_makehuman_mhx.bl_idname, text="MakeHuman (.mhx)...")
+	bpy.types.INFO_MT_file_import.append(menu_func)
+	return
+ 
+def unregister():
+	# unregisterPanels()
+	bpy.types.unregister(IMPORT_OT_makehuman_mhx)
+	menu_func = lambda self, context: self.layout.operator(IMPORT_OT_makehuman_mhx.bl_idname, text="MakeHuman (.mhx)...")
+	bpy.types.INFO_MT_file_import.remove(menu_func)
+
+if __name__ == "__main__":
+	register()
+
+#
+#	Testing
+#
+"""
+theScale = 1.0
+
+toggle = T_Replace + T_Mesh + T_Armature + T_MHX + T_ArmIK + T_LegIK
+#rigLeg = T_Toes + T_GoboFoot
+#rigArm = T_ElbowPT + T_FingerCurl
+
+#readMhxFile("/home/thomas/makehuman/exports/foo-25.mhx")
+
+#toggle = T_Replace + T_Armature 
+#readMhxFile("/home/thomas/makehuman/exports/foo-sintel-25.mhx")
+
+readMhxFile("C:/Documents and Settings/xxxxxxxxxxxxxxxxxxxx/Mina dokument/makehuman/exports/foo-25.mhx", 'Classic')
+#readMhxFile("/home/thomas/mhx5/test1.mhx")
+#readMhxFile("/home/thomas/myblends/gobo/gobo.mhx")
+#readMhxFile("/home/thomas/myblends/sintel/simple.mhx")
+"""
+
+
+
+
+
-- 
GitLab