利用者:Korc/Indigo exporter

提供: wiki
移動先: 案内検索

This indigo v0.6 exporter script for blender.

Save the following code as .py file under your .blender/scripts directory.

indigo0.6_export.py:

#!BPY
"""Registration info for Blender menus:
Name: 'Indigo v0.6t6-b1...'
Blender: 240
Group: 'Export'
Tooltip: 'Export to Indigo v0.6 scene format (.xml)'
"""

#
# ***** BEGIN GPL LICENSE BLOCK *****
#
# --------------------------------------------------------------------------
# INDIGO v0.6 test 6 exporter beta 1
# --------------------------------------------------------------------------
#
# Authors:
# * Indigo exporter - Nick Chapman, Zuegs, Ewout Fernhout, Leope
#
# 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------


######################################################
# Importing modules
######################################################

import math
#import subprocess
import os
import Blender
import struct
from Blender import NMesh, Scene, Object, Material, Texture, Window
from Blender import sys as bsys, Mathutils, Draw, BGL
from Blender.sys import *


def info(object, spacing=10, collapse=1):
	"""Print methods and doc strings.

	Takes module, class, list, dictionary, or string."""
	methodList = [e for e in dir(object) if callable(getattr(object, e))]
	processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
	print "\n".join(["%s %s" %
					 (method.ljust(spacing),
					  processFunc(str(getattr(object, method).__doc__)))
					 for method in methodList])


######################################################
# Data Structures
######################################################




######################################################
# Functions
######################################################


# New name based on old with a different extension
def newFName(ext):
	return Blender.Get('filename')[: -len(Blender.Get('filename').split('.', -1)[-1]) ] + ext



# exporting a mesh
def exportMesh(mesh):
	vdata = []   # list of [ii0, ii1, ii2, ...] lists indexed by Blender-Vertex-index
	vlist = []   # list of [coord, normal, uv] lists indexed by Indigo-Vertex-index
	flist = []

	def addVertex(bvindex, coord, normal, uv):
		index = -1
		if (bvindex < len(vdata)):
			for ivindex in vdata[bvindex]:
				v = vlist[ivindex]
				if (abs(v[0][0]-coord[0])<0.0001) and \
				(abs(v[0][1]-coord[1])<0.0001) and \
				(abs(v[0][2]-coord[2])<0.0001) and \
				(abs(v[1][0]-normal[0])<0.0001) and \
				(abs(v[1][1]-normal[1])<0.0001) and \
				(abs(v[1][2]-normal[2])<0.0001):
					if ((v[2]==[]) and (uv==[])) or \
					((abs(v[2][0]-uv[0])<0.0001) and \
					(abs(v[2][1]-uv[1])<0.0001)):
						index = ivindex
		if index < 0:
			index = len(vlist)
			vlist.append([coord, normal, uv])
			while bvindex >= len(vdata):
				vdata.append([])
			vdata[bvindex].append(index)
		return index

	def getVertices():
		def getUVStr(uv):
			if uv != []: return " uv0=\"%f %f\"" %(uv[0], uv[1])
			else: return ""
		return "".join(map( \
			lambda v: "\t\t\t<vertex pos=\"%f %f %f\" normal=\"%f %f %f\"%s />\n" \
			%(v[0][0], v[0][1], v[0][2], v[1][0], v[1][1], v[1][2], getUVStr(v[2])), \
			vlist))

	def addFace(mindex, index0, index1, index2):
		while mindex >= len(flist):
			flist.append([])
		flist[mindex].append([index0, index1, index2])

	def getFaces():
		def getMaterialName(mindex):
			if mindex < len(mesh.materials): return mesh.materials[mindex].name
			else:
				print "Warning: faces without material"
				return "Default"
		return "".join(map( \
			lambda fli: "\t\t\t<triangle_set>\n\t\t\t\t<material_name>%s</material_name>\n"%(getMaterialName(fli)) \
				+ "".join(map(lambda f: "\t\t\t\t<tri>%d %d %d</tri>\n"%(f[0], f[1], f[2]), flist[fli])) \
				+ "\t\t\t</triangle_set>\n" , range(len(flist))))

	vdata = []
	vlist = []
	flist = []
	for face in mesh.faces:
		iis = [-1, -1, -1, -1]
		for vi in range(len(face.v)):
			vert = face.v[vi]
			if face.smooth:
				normal = vert.no
			else:
				normal = face.no
			if len(face.uv) == len(face.v):
				uv = face.uv[vi]
			else:
				uv = []
			iis[vi] = addVertex(vert.index, vert.co, normal, uv)
		addFace(face.materialIndex, iis[0], iis[1], iis[2])
		if len(face.v)==4:
			addFace(face.materialIndex, iis[2], iis[3], iis[0])
	str = "\t<mesh>\n"
	str += "\t\t<name>%s</name>\n" %(mesh.name.replace("<","-").replace(">","-"))
	str += "\t\t<embedded>\n"
	str += "\t\t\t<expose_uv_set>\n"
	str += "\t\t\t\t<index>0</index>\n"
	str += "\t\t\t\t<name>uv</name>\n"
	str += "\t\t\t</expose_uv_set>\n"
	str += getVertices()
	str += getFaces()
	str += "\t\t</embedded>\n"
	str += "\t</mesh>\n\n"
	return str


# zuegs: added color exponent
def colGamma(value):
	global ColExponent
	return value**(1.0*ColExponent.val)


# exporting a material
def exportMaterial(mat):
	str = "\t<material>\n"
	str += "\t\t<name>%s</name>\n" %mat.name
		
	if (mat.mode & Material.Modes.RAYTRANSP) or (mat.mode & Material.Modes.RAYMIRROR):
		str += "\t\t<specular>\n"
		if (mat.mode & Material.Modes.RAYMIRROR):
			str += "\t\t\t<normal_reflectance>%.3f</normal_reflectance>\n" %mat.rayMirr
		#else:
			#str += "\t\t\t<normal_reflectance>0</normal_reflectance>\n"
		str += "\t\t\t<ior>%.3f</ior>\n" %mat.IOR
		if (mat.mode & Material.Modes.RAYTRANSP):
			str += "\t\t\t<transparent>true</transparent>\n"
			str += "\t\t\t<cauchy_b_coeff>%.3f</cauchy_b_coeff>\n" %mat.filter
			str += "\t\t\t<rgb_absorptivity>%.3f %.3f %.3f</rgb_absorptivity>\n" %((1-mat.R)*(1-mat.R),(1-mat.G)*(1-mat.G),(1-mat.B)*(1-mat.B))
		else:
			str += "\t\t\t<transparent>false</transparent>\n"
			str += "\t\t\t<cauchy_b_coeff>0.0</cauchy_b_coeff>\n"
			str += "\t\t\t<rgb_absorptivity>0 0 0</rgb_absorptivity>\n"
		for t in mat.getTextures():
			if (t != None) and (t.tex.type == Blender.Texture.Types.IMAGE): # and (t.texco & Blender.Texture.TexCo['UV'])
				if t.mapto & Blender.Texture.MapTo['NOR']:
					if t.tex.getImage():
						str += "\t\t\t<bump_map>\n"
						str += "\t\t\t\t<uv_set>uv</uv_set>\n"
						(imagefilepath, imagefilename) = os.path.split(t.tex.getImage().getFilename())
						str += "\t\t\t\t<path>%s</path>\n" %(imagefilename)
						str += "\t\t\t\t<gain>%f</gain>\n" %(t.norfac * 0.1)
						str += "\t\t\t\t<exponent>%f</exponent>\n" %(1)
						str += "\t\t\t</bump_map>\n"
		str += "\t\t</specular>\n"
	else:
		specfac = mat.getSpec()
		if specfac > 0.0001:
			str += "\t\t<phong>\n"
			if mat.name.find(".nk") != -1:
				str += "\t\t\t<nk_data>nkdata/%s</nk_data>\n" %(mat.name.split(".nk")[0]+".nk")
			else:
				str += "\t\t\t<diffuse>%.3f %.3f %.3f</diffuse>\n" %(colGamma(mat.R)*DiffuseGain.val,colGamma(mat.G)*DiffuseGain.val,colGamma(mat.B)*DiffuseGain.val)
				str += "\t\t\t<specular>%.3f %.3f %.3f</specular>\n" %(colGamma(mat.specR*specfac)*SpecularGain.val,colGamma(mat.specG*specfac)*SpecularGain.val,colGamma(mat.specB*specfac)*SpecularGain.val)
				str += "\t\t\t<fresnel_scale>%.3f</fresnel_scale>\n" %(mat.ref)
			str += "\t\t\t<exponent>%.3f</exponent>\n" %(mat.hard*10)
		else:
			str += "\t\t<diffuse>\n"
			str += "\t\t\t<colour>%.3f %.3f %.3f</colour>\n" %(colGamma(mat.R)*DiffuseGain.val,colGamma(mat.G)*DiffuseGain.val,colGamma(mat.B)*DiffuseGain.val)

		for t in mat.getTextures():
			if (t != None) and (t.texco & Blender.Texture.TexCo['UV']) and (t.tex.type == Blender.Texture.Types.IMAGE):
				if t.mapto & Blender.Texture.MapTo['COL']:
					if t.tex.getImage():
						str += "\t\t\t<albedo_texture>\n"
						str += "\t\t\t\t<uv_set>uv</uv_set>\n"
						(imagefilepath, imagefilename) = os.path.split(t.tex.getImage().getFilename())
						str += "\t\t\t\t<path>%s</path>\n" %(imagefilename)
						str += "\t\t\t\t<gain>%f</gain>\n" %(t.colfac)
						str += "\t\t\t\t<exponent>%f</exponent>\n" %(TexExponent.val)
						str += "\t\t\t</albedo_texture>\n"
				if t.mapto & Blender.Texture.MapTo['NOR']:
					if t.tex.getImage():
						str += "\t\t\t<bump_map>\n"
						str += "\t\t\t\t<uv_set>uv</uv_set>\n"
						(imagefilepath, imagefilename) = os.path.split(t.tex.getImage().getFilename())
						str += "\t\t\t\t<path>%s</path>\n" %(imagefilename)
						str += "\t\t\t\t<gain>%f</gain>\n" %(t.norfac * 0.1)
						str += "\t\t\t\t<exponent>%f</exponent>\n" %(1)
						str += "\t\t\t</bump_map>\n"
		if mat.getSpec() > 0:
			str += "\t\t</phong>\n"
		else:
			str += "\t\t</diffuse>\n"
	str += "\t</material>\n\n"
	return str


# collect Materials
matnames = []
def collectObjectMaterials(obj):
	global matnames
	objectname = obj.getName()
	objecttype = obj.getType()
	if (objecttype == "Mesh") or (objecttype == "Curve") or (objecttype == "Text"):
		materials = obj.getData().getMaterials()
		meshlight = 0
		if len(materials) > 0:
			mat0 = materials[0]
			if mat0.emit > 0:
				meshlight = 1
		if meshlight == 0:
			for mat in materials:
				if mat.name not in matnames:
					matnames.append(mat.name)
	elif (objecttype == "Empty"):
		group = obj.DupGroup
		if group:
			groupname = group.name
			for o, m in obj.DupObjects:
				collectObjectMaterials(o)


# exporting a object
# zuegs: added support for Curves, Groups and other object-types
meshlist = []
def exportObject(obj, matrix):
	global meshlist
	str = ""
	objectname = obj.getName()
	objecttype = obj.getType()
	if (objecttype == "Mesh") or (objecttype == "Curve") or (objecttype == "Text"):
		mesh = Blender.NMesh.GetRawFromObject(objectname)
		meshname = mesh.name
		if (objecttype == "Curve") or (objecttype == "Text"):
#			print "Curve object %s: current mesh name is %s. Tweak to %s." %(objectname, meshname, obj.getData().getName()) 
			meshname = obj.getData().getName()				
			mesh.name = meshname
			for f in mesh.faces:
				f.smooth = 1
		if (objecttype == "Curve"):
#			print "Curve object %s: current material count %d. Tweak to %d." %(objectname, len(mesh.getMaterials()), len(obj.getData().getMaterials()))
			mesh.setMaterials(obj.getData().getMaterials())
		meshlight = 0
		if len(mesh.materials) > 0:
			mat0 = mesh.materials[0]
			if mat0.emit > 0:
				meshlight = 1
		if meshlight:
			print "processing Object \"%s\" as Meshlight (Mesh \"%s\")..." %(objectname, meshname)
		else:
			print "processing Object \"%s\" (Mesh \"%s\")..." %(objectname, meshname)
		str += "\t<!-- %s -->\n" %(objectname.replace("<","-").replace(">","-"))
		try:
			meshlist.index(meshname)
		except ValueError:
			str += exportMesh(mesh)
			meshlist.append(meshname)
		pos = obj.getLocation()
		# matrix = obj.getMatrix() # matrix is passed as argument to the function
		if meshlight:
			str += "\t<meshlight>\n"
		else:
			str += "\t<model>\n"
		str += "\t\t<pos>%f %f %f</pos>\n" % (matrix[3][0], matrix[3][1], matrix[3][2])
		str += "\t\t<scale>1.0</scale>\n"
		str += "\t\t<rotation>\n"
		str += "\t\t\t<matrix>\n"
		str += "\t\t\t\t"
		for v in range(3):
			for z in range(3):
				str += "%f " % matrix[z][v]
		str += "\n"
		str += "\t\t\t</matrix>\n"
		str += "\t\t</rotation>\n"
		str += "\t\t<mesh_name>%s</mesh_name>\n" %(meshname.replace("<","-").replace(">","-"))
		if meshlight:
			str += "\t\t<spectrum>\n"
			if (mat0.translucency > 0):
				str += "\t\t\t<peak>\n"
				str += "\t\t\t\t<peak_min>%.0f</peak_min>\n" %(mat0.translucency*1000)
				str += "\t\t\t\t<peak_width>%.0f</peak_width>\n" %(mat0.amb*1000)
				str += "\t\t\t\t<base_value>0</base_value>\n"
				str += "\t\t\t\t<peak_value>%.0f</peak_value>\n" %(mat0.emit*100)
				str += "\t\t\t</peak>\n"
			elif (mat0.translucency == 0 and mat0.amb > 0):
				str += "\t\t\t<blackbody>\n"
				str += "\t\t\t\t<temperature>%.0f</temperature>\n" %(mat0.amb*10000)
# zuegs: correction for blackbody energie
				str += "\t\t\t\t<gain>%.10f</gain>\n" %(pow(10,10*(mat0.emit-1)) / (7.5659e-16*pow(mat0.amb*10000, 4)))
				str += "\t\t\t</blackbody>\n"	
			elif (mat0.translucency == 0 and mat0.amb == 0):
				str += "\t\t\t<rgb>\n"
				str += "\t\t\t\t<rgb>%.3f %.3f %.3f</rgb>\n" %(pow(100,(mat0.R))-1, pow(100,(mat0.G))-1, pow(100,(mat0.B))-1)
				str += "\t\t\t</rgb>\n"
			str += "\t\t</spectrum>\n"
			str += "\t</meshlight>\n"
		else:
			str += "\t</model>\n\n"
	elif (objecttype == "Empty"):
		group = obj.DupGroup
		if (group):
			groupname = group.name
			print "processing Object \"%s\" (Group \"%s\")..." %(objectname, groupname)
			for o, m in obj.DupObjects:
				str += exportObject(o, m)
			print "end processing Object \"%s\" (Group \"%s\")..." %(objectname, groupname)
	else:
		print "Skip \"%s\" (type \"%s\")" %(obj.getName(), obj.getType())
	return str


def IndigoBoolean(val):
	if val != 0:
		val = "true"
	else:
		val = "false"
	return val


######################################################
# EXPORT
######################################################

def save_indigo(filename, unindexedname):
	global meshlist, matnames

	print("INDIGO EXPORT\n")
	time1 = Blender.sys.time()
	print("Saving to '" + filename + "'...\n")
	file = open(filename, 'w')

	##### XML header ######
	file.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n")
	file.write("<scene>\n")

	# write render_settings
	file.write("\t<renderer_settings>\n")
	file.write("\t\t<width>%d</width>\n" % (SizeX.val*ScaleSize.val/100))
	file.write("\t\t<height>%d</height>\n" % (SizeY.val*ScaleSize.val/100))
	file.write("\t\t<metropolis>%s</metropolis>\n" %(IndigoBoolean(MLT.val)))
	file.write("\t\t<large_mutation_prob>%g</large_mutation_prob>\n" % float(LMP.val))
	file.write("\t\t<max_change>%g</max_change>\n" % float(MaxChange.val))
	file.write("\t\t<max_num_consec_rejections>%d</max_num_consec_rejections>\n" % MaxNumConsRej.val)
	file.write("\t\t<bidirectional>%s</bidirectional>\n" %(IndigoBoolean(Bidirectional.val)))
	file.write("\t\t<russian_roulette_live_prob>%g</russian_roulette_live_prob>\n" % float(RRLP.val))
	file.write("\t\t<max_depth>%s</max_depth>\n" % MaxDepth)
	file.write("\t\t<strata_width>%s</strata_width>\n" % StrataWidth)
	file.write("\t\t<logging>%s</logging>\n" %(IndigoBoolean(Logging.val)))
	file.write("\t\t<save_untonemapped_exr>%s</save_untonemapped_exr>\n" %(IndigoBoolean(SaveUTMExr.val)))
	file.write("\t\t<save_tonemapped_exr>%s</save_tonemapped_exr>\n" %(IndigoBoolean(SaveTMExr.val)))
	file.write("\t</renderer_settings>\n\n")	

	# write tone mapping		
	file.write("\t<tonemapping>\n")
	if ToneMapType.val == 0:
		file.write("\t\t<linear>\n")
		file.write("\t\t\t<scale>%.3f</scale>\n" %float(ToneMapScale.val))
		file.write("\t\t</linear>\n")
		file.write("\t\t<!--\n")
		file.write("\t\t<reinhard>\n")
		file.write("\t\t\t<pre_scale>1.0</pre_scale>\n")
		file.write("\t\t\t<post_scale>1.0</post_scale>\n")
		file.write("\t\t\t<burn>0.8</burn>\n")
		file.write("\t\t</reinhard>\n")
		file.write("\t\t-->\n")
	elif ToneMapType.val == 1:
		file.write("\t\t<!--\n")
		file.write("\t\t<linear>\n")
		file.write("\t\t\t<scale>1.0</scale>\n")
		file.write("\t\t</linear>\n")
		file.write("\t\t-->\n")
		file.write("\t\t<reinhard>\n")
		file.write("\t\t\t<pre_scale>%.6f</pre_scale>\n" %float(ToneMapPreScale.val))
		file.write("\t\t\t<post_scale>%.6f</post_scale>\n" %float(ToneMapPostScale.val))
		file.write("\t\t\t<burn>%.3f</burn>\n" %ToneMapBurn.val)
		file.write("\t\t</reinhard>\n")
	file.write("\t</tonemapping>\n\n")

	# write background
	if EnvType.val == 0:
		worldcolor = Blender.World.Get('World').getHor()
		file.write("\t<background>\n")
		file.write("\t\t<spectrum>\n")
		file.write("\t\t\t<rgb>\n")
		file.write("\t\t\t\t<rgb>%g %g %g</rgb>\n" %(worldcolor[0], worldcolor[1], worldcolor[2]))
		file.write("\t\t\t</rgb>\n")
		file.write("\t\t</spectrum>\n")
		file.write("\t</background>\n\n")

	#get all the objects in this scene
	activelayers = Window.ViewLayer()
	for i in range(len(activelayers)):
		activelayers[i] = 2**(activelayers[i]-1)
	object_list1 = Blender.Scene.GetCurrent().getChildren()
	object_list = []
	matnames= []
	for obj in object_list1:
		if obj.Layer in activelayers:
			object_list.append(obj)
			collectObjectMaterials(obj)

	##### Materialfile include #####
	if MatFile.val is 0:
		
		##### Define a dummy material ######
		file.write("\t<material>\n")
		file.write("\t\t<name>Default</name>\n")
		file.write("\t\t<diffuse>\n")
		file.write("\t\t\t<colour>1 1 1</colour>\n")
		file.write("\t\t</diffuse>\n")
		file.write("\t</material>\n")

		##### Process Materials ######
		materials = Material.Get()
		for mat in materials:
			if mat.name in matnames:
				file.write(exportMaterial(mat))
	else:
		materialfile = makename(unindexedname, '-materials.xml')
		materialinclude = basename(materialfile)
		file.write("\t<include>\n")
		file.write("\t\t<pathname>%s</pathname>\n" %(materialinclude))
		file.write("\t</include>\n\n")
			
	##### Process sun ######
	if EnvType.val == 1:
		for obj in object_list:
			if obj.getType() == "Lamp":
				if obj.data.getType() == 1: # sun object
					print("Processing sun lamp object...\n")
					invmatrix = Mathutils.Matrix(obj.getInverseMatrix())
					file.write("\t<skylight>\n")
					file.write("\t\t<sundir>%f %f %f</sundir>\n" % (invmatrix[0][2], invmatrix[1][2], invmatrix[2][2]))
					file.write("\t\t<turbidity>%f</turbidity>\n" %Turbidity.val)
					file.write("\t\t<sky_gain>%f</sky_gain>\n" %SkyGain.val)
					file.write("\t</skylight>\n\n")
				

	##### Process Env Map #####
	if EnvType.val == 2:
		if EnvFile.val != "none" and EnvFile.val != "":
			file.write("\t<env_map>\n")
			file.write("\t\t<%s>\n" %(EnvMapTypeV[EnvMapType.val]))
			file.write("\t\t\t<path>%s</path>\n" %(EnvFile.val))
			file.write("\t\t\t<gain>%.3f</gain>\n" %(EnvGain.val))
			if EnvMapType.val == 0:
				file.write("\t\t\t<width>%d</width>\n" %(EnvWidth.val))
			file.write("\t\t</%s>\n" %(EnvMapTypeV[EnvMapType.val]))
			file.write("\t</env_map>\n\n")



	##### Process camera ######
	currentscene = Scene.GetCurrent()
	camObj = currentscene.getCurrentCamera()
	if camObj:
		print "processing Camera..."
		matrix = camObj.getMatrix()
		pos = matrix[3]
		forwards = matrix[2]
		up = matrix[1]
		file.write("\t<camera>\n")
		file.write("\t\t<pos>%f %f %f</pos>\n" % (pos[0], pos[1], pos[2]))
		file.write("\t\t<up>%f %f %f</up>\n" % (up[0], up[1], up[2]))
		file.write("\t\t<forwards>%f %f %f</forwards>\n" % (-forwards[0], -forwards[1], -forwards[2]))

		aspect = float(SizeX.val) / float(SizeY.val)
		film = 0.001 * FilmWidth.val
# zuegs: correct aspect stuff for portrait-mode
		if aspect < 1.0:
			lensfocal = (camObj.data.getLens() * film / aspect)/32
		else:
			lensfocal = (camObj.data.getLens() * film)/32
		
		file.write("\t\t<aperture_radius>%f</aperture_radius>\n" % ApertureRadius.val)
		file.write("\t\t<focus_distance>%f</focus_distance>\n" % FocusDistance.val)
		file.write("\t\t<aspect_ratio>%g</aspect_ratio>\n" % aspect)
		file.write("\t\t<sensor_width>%f</sensor_width>\n" % film)
		file.write("\t\t<lens_sensor_dist>%f</lens_sensor_dist>\n" % lensfocal)
		file.write("\t\t<white_balance>%s</white_balance>\n" % whiteBalanceV[WhiteBalance.val])
		
		file.write("\t</camera>\n\n")
	
	##### Check for ground plane ######
	if GroundPlane.val is 1:
		file.write("\t<plane>\n")
		file.write("\t\t<normal>0 0 1</normal>\n")
		file.write("\t\t<dist>-0.000001</dist>\n")
		file.write("\t\t<material_name>Default</material_name>\n")
		file.write("\t</plane>\n\n")

	##### Process Meshes ######
	meshlist = []
	for obj in object_list:
		file.write(exportObject(obj, obj.getMatrix()))

	##### XML FOOTER ######
	file.write("</scene>\n")
	file.close()	
	print("Finished.\n")

	if MatFile.val and not MatSaved:
		print("Saving Material file...\n")
		file = open(materialfile, 'w')		

		file.write("<scenedata>\n\n")
		
		##### Define a dummy material ######
		file.write("\t<material>\n")
		file.write("\t\t<name>Default</name>\n")
		file.write("\t\t<diffuse>\n")
		file.write("\t\t\t<colour>1 1 1</colour>\n")
		file.write("\t\t</diffuse>\n")
		file.write("\t</material>\n")

		##### Process Materials ######
		materials = Material.Get()
		for mat in materials:
			if mat.name in matnames:
				file.write(exportMaterial(mat))

		file.write("</scenedata>")	
		file.close()	
				
	time2 = Blender.sys.time()
	print("Processing time: %f\n" %(time2-time1))
	#Draw.Exit()

#### SAVE ANIMATION ####	
def save_anim(filename):
	global MatSaved
	
	MatSaved = 0
	startF = Blender.Get('staframe')
	endF = Blender.Get('endframe')

	for i in range (startF, endF):
		Blender.Set('curframe', i)
		Blender.Redraw()
		frameindex = "-" + str(i) + ".xml"
		indexedname = makename(filename, frameindex)
		unindexedname = filename
		save_indigo(indexedname, unindexedname)
		MatSaved = 1

#### SAVE STILL (hackish...) ####
def save_still(filename):
	global MatSaved
	
	MatSaved = 0
	unindexedname = filename
	save_indigo(filename, unindexedname)

######################################################
# Settings GUI
######################################################

# Assign event numbers to buttons
evtNoEvt	= 0
evtExport	= 1
evtExportAnim	= 2
evtIsNumber = 3
evtFocusS = 4
evtFocusC = 5

# Set initial values of buttons

##	<size>800 600</size>

sceneSizeX = Scene.GetCurrent().getRenderingContext().imageSizeX()
sceneSizeY = Scene.GetCurrent().getRenderingContext().imageSizeY()

SizeX = Draw.Create(sceneSizeX)
SizeY = Draw.Create(sceneSizeY)

strScaleSize = "Scale Size %t | 100 % %x100 | 75 % %x75 | 50 % %x50 | 25 % %x25"
ScaleSize = Draw.Create(100)

TexExponent = Draw.Create(2.3)
ColExponent = Draw.Create(2.3)

##	<metropolis>1</metropolis>
MLT = Draw.Create(1)

##	<large_mutation_prob>0.1</large_mutation_prob>
LMP = Draw.Create(0.1)

##	<max_change>0.02</max_change>
MaxChange = Draw.Create(0.02)

##  <max_num_consec_rejections>100</max_num_consec_rejections>
MaxNumConsRej = Draw.Create(100)

##	<russian_roulette_live_prob>0.7</russian_roulette_live_prob>
RRLP = Draw.Create(0.7)

##	<max_depth>1000</max_depth>
MaxDepth = Draw.Create(1000)

##  <bidirectional>true</bidirectional>
Bidirectional = Draw.Create(1)

##	<strata_width>14</strata_width>
StrataWidth = Draw.Create(14)

##	<logging>0</logging>
Logging = Draw.Create(0)

##  <save_untonemapped_exr>false</save_untonemapped_exr>
SaveUTMExr = Draw.Create(0)

##  <save_tonemapped_exr>false</save_tonemapped_exr>
SaveTMExr = Draw.Create(0)

##  <sensor_width>0.035</sensor_width>
FilmWidth = Draw.Create(35)

##	<lens_radius>0.0</lens_radius>
ApertureRadius = Draw.Create(0.001)

##	<focus_distance>2.0</focus_distance>
FocusDistance = Draw.Create(2.0)

##  <white_balance>D65</white_balance>
whiteBalanceV="E D50 D55 D65 D75 A B C 9300 F2 F7 F11".split()
strWhiteBalance="White balance %t | "+" | ".join([name+" %x"+str(idx) for idx,name in enumerate(whiteBalanceV)])
WhiteBalance = Draw.Create(4)


## Environment Type
strEnvType = "Env Type %t | Background %x0 | SunSky %x1 | Map %x2"
EnvType = Draw.Create(0)

##  <turbidity>2.0</turbidity>
Turbidity = Draw.Create(2.0)

##  <sky_gain>2.0</sky_gain>
SkyGain = Draw.Create(0.005)

GroundPlane = Draw.Create(0)

## Separate materials
MatFile = Draw.Create(0)

## Environment map
EnvFile = Draw.Create("none")
strEnvMapType = "Map type %t | Spherical %x0 | LatLong %x1"
EnvMapType = Draw.Create(0)
EnvMapTypeV = {}
EnvMapTypeV[0] = "spherical"
EnvMapTypeV[1] = "latlong"
EnvGain = Draw.Create(1.0)
EnvWidth = Draw.Create(640)

## Tonemapping
strToneMapType = "ToneMap type %t | Linear %x0 | Reinhard %x1"
ToneMapType = Draw.Create(1)
ToneMapScale = Draw.Create("1.0")
ToneMapPreScale = Draw.Create("1.0")
ToneMapPostScale = Draw.Create("1.0")
ToneMapBurn = Draw.Create(0.8)

## Overall color gain
DiffuseGain = Draw.Create(1.00)
SpecularGain = Draw.Create(1.00)

# text color fix
textcol = [0, 0, 0]

## Registry
def update_Registry():
	#global EnvFile, EnvMapType
	d = {}
	d['sizex'] = SizeX.val
	d['sizey'] = SizeY.val
	d['scalesize'] = ScaleSize.val
	d['texexponent'] = TexExponent.val
	d['colexponent'] = ColExponent.val
	d['filmwidth'] = FilmWidth.val
	d['apertureradius'] = ApertureRadius.val
	d['focusdistance'] = FocusDistance.val
	d['whitebalance'] = WhiteBalance.val
	d['mlt'] = MLT.val
	d['lmp'] = LMP.val
	d['maxchange'] = MaxChange.val
	d['maxnumconsrej'] = MaxNumConsRej.val
	d['bidirectional'] = Bidirectional.val
	d['rrlp'] = RRLP.val
	d['maxdepth'] = MaxDepth.val
	d['stratawidth'] = StrataWidth.val
	d['logging'] = Logging.val
	d['groundplane'] = GroundPlane.val
	d['saveutmexr'] = SaveUTMExr.val
	d['savetmexr'] = SaveTMExr.val
	d['tonemaptype'] = ToneMapType.val
	d['tonemapscale'] = ToneMapScale.val
	d['tonemapprescale'] = ToneMapPreScale.val
	d['tonemappostscale'] = ToneMapPostScale.val
	d['tonemapburn'] = ToneMapBurn.val
	d['envtype'] = EnvType.val
	d['envfile'] = EnvFile.val
	d['envmaptype'] = EnvMapType.val
	d['envgain'] = EnvGain.val
	d['envwidth'] = EnvWidth.val
	d['turbidity'] = Turbidity.val
	d['skygain'] = SkyGain.val
	d['matfile'] = MatFile.val
	Blender.Registry.SetKey('BlenderIndigo', d, True)

rdict = Blender.Registry.GetKey('BlenderIndigo', True)

if rdict:
	try:
		SizeX.val = rdict['sizex']
		SizeY.val = rdict['sizey']
		ScaleSize.val = rdict['scalesize']
		TexExponent.val = rdict['texexponent']
		ColExponent.val = rdict['colexponent']
		FilmWidth.val = rdict['filmwidth']
		ApertureRadius.val = rdict['apertureradius']
		FocusDistance.val = rdict['focusdistance']
		WhiteBalance.val = rdict['whitebalance']
		MLT.val = rdict['mlt'] 
		LMP.val = rdict['lmp']
		MaxChange.val = rdict['maxchange']
		MaxNumConsRej.val = rdict['maxnumconsrej']
		Bidirectional.val = rdict['bidirectional']
		RRLP.val = rdict['rrlp']
		MaxDepth.val = rdict['maxdepth']
		StrataWidth.val = rdict['stratawidth']
		Logging.val = rdict['logging']
		GroundPlane.val = rdict['groundplane']
		SaveUTMExr.val = rdict['saveutmexr']
		SaveTMExr.val = rdict['savetmexr']
		ToneMapType.val = rdict['tonemaptype']
		ToneMapScale.val = rdict['tonemapscale']
		ToneMapPreScale.val = rdict['tonemapprescale']
		ToneMapPostScale.val = rdict['tonemappostscale']
		ToneMapBurn.val = rdict['tonemapburn']
		EnvType.val = rdict['envtype']
		EnvFile.val = rdict['envfile']
		EnvMapType.val = rdict['envmaptype']
		EnvGain.val = rdict['envgain']
		EnvWidth.val = rdict['envwidth']
		Turbidity.val = rdict['turbidity']
		SkyGain.val = rdict['skygain']
		MatFile.val = rdict['matfile']
	except: update_Registry()	

def gui():
    global evtNoEvt, evtExport, evtExportAnim, evtFocusS, evtFocusC
    global SizeX, SizeY, strScaleSize, ScaleSize, TexExponent, ColExponent, RRLP, MaxDepth, Bidirectional, StrataWidth, Logging, ApertureRadius, FocusDistance, GroundPlane, MatFile, FilmWidth
    global SaveUTMExr, SaveTMExr, ToneMapType, ToneMapScale, ToneMapPreScale, ToneMapPostScale, ToneMapBurn
    global MLT, LMP, MaxChange, MaxNumConsRej
    global textcol, strEnvType, EnvType, EnvFile, strEnvMapType, EnvMapType, EnvGain, EnvWidth, Turbidity, SkyGain, DiffuseGain, SpecularGain
    global strWhiteBalance, WhiteBalance, whiteBalanceV

    Draw.Button("Export", evtExport, 10, 25, 100, 18, "Open file dialog and export")
    Draw.Button("Export Anim", evtExportAnim, 130, 25, 100, 18, "Open file dialog and export animation (careful: takes a lot of diskspace!!!)")
    MatFile = Draw.Toggle("Separate Materials", evtNoEvt, 250, 25, 200, 18, MatFile.val, "Save all the material settings to a separate file with a \"-materials\" extension")
    BGL.glColor3f(textcol[0], textcol[1], textcol[2]) ; BGL.glRasterPos2i(10,10) ; Draw.Text("Press Q or ESC to quit.", "tiny")
    #
    BGL.glRasterPos2i(10,470) ; Draw.Text("I N D I G O  v0.6beta3  exporter")
    #
    BGL.glRasterPos2i(10,450) ; Draw.Text("Size:")
    SizeX = Draw.Number("X: ", evtNoEvt, 65, 445, 75, 18, SizeX.val, 1, 4096, "Width of the render")
    SizeY = Draw.Number("Y: ", evtNoEvt, 150, 445, 75, 18, SizeY.val, 1, 3072, "Height of the render")
    ScaleSize = Draw.Menu(strScaleSize, evtNoEvt, 230, 445, 65, 18, ScaleSize.val, "Scale Image Size of ...")   
    TexExponent = Draw.Slider("Tex exp: ", evtNoEvt, 10, 425, 210, 18, TexExponent.val, 0.0, 5.0, 0, "Texture gamma exponent")
# zuegs: added color exponent
    ColExponent = Draw.Slider("Col exp: ", evtNoEvt, 240, 425, 210, 18, ColExponent.val, 0.01, 5.0, 0, "Color gamma exponent")
    #
    BGL.glRasterPos2i(10,405) ; Draw.Text("Camera settings")
    FilmWidth = Draw.Number("Film Width: ", evtNoEvt, 10, 380, 250, 18, FilmWidth.val, 0.0, 100, "Width of the \"Film.\" in mm.")
    ApertureRadius = Draw.Number("Aperture Radius: ", evtNoEvt, 10, 360, 250, 18, ApertureRadius.val, 0.0, 1.0, "In meters, 0 is off. Defines the radius of the camera lens, or the radius of the camera aperture. Larger radius means more depth of field.")
    FocusDistance = Draw.Number("Focus Distance: ", evtNoEvt, 10, 340, 250, 18, FocusDistance.val, 0.0, 100, "Distance from the camera at which objects will be in focus. Has no effect if Lens Radius is 0.")
    Draw.Button("S", evtFocusS, 265, 340, 15, 18, "Get the distance from the selected object")
    Draw.Button("C", evtFocusC, 280, 340, 15, 18, "Get the distance from the 3d cursor")
    BGL.glRasterPos2i(300,365) ; Draw.Text("white balance")
    WhiteBalance = Draw.Menu(strWhiteBalance, evtNoEvt, 385, 360, 65, 18, WhiteBalance.val, "Set the white_balance (def=D65)")
    #
    BGL.glRasterPos2i(10,320) ; Draw.Text("Metropolis light transport settings")
    MLT = Draw.Toggle("Metropolis", evtNoEvt, 10, 295, 100, 18, MLT.val, "If pressed, use MLT otherwise use pathtracer")
    LMP = Draw.Number("Large mutation probability: ", evtNoEvt, 112, 295, 338, 18, LMP.val, 0.0, 1.0, "Probability of using fresh random numbers")
    MaxChange = Draw.Number("Max Change: ", evtNoEvt, 112, 275, 338, 18, MaxChange.val, 0.0, 1.0, "Maximum mutation size") 
    MaxNumConsRej = Draw.Number("Max num consec rejections:", evtNoEvt, 112, 255, 338, 18, MaxNumConsRej.val, 0, 10000, "The lower the value the more biased the calculation")
    #
    BGL.glRasterPos2i(10,235) ; Draw.Text("General tracing parameters")
    Bidirectional = Draw.Toggle("Bidirectional", evtNoEvt, 10, 210, 100, 18, Bidirectional.val, "If pressed, use bidirectional tracing")
    RRLP = Draw.Number("Russian roulette live probability: ", evtNoEvt, 112, 210, 338, 18, RRLP.val, 0.0, 1.0, "Russian roulette live probability")
    MaxDepth = Draw.Number("Max depth:", evtNoEvt, 112, 190, 338, 18, MaxDepth.val, 1, 10000, "Maximum ray bounce depth")
    #
    BGL.glRasterPos2i(10,150) ; Draw.Text("Path tracer settings")
    StrataWidth = Draw.Number("Strata width:", evtNoEvt, 10, 125, 150, 18, StrataWidth.val, 1, 50, "Number of samples per pixel = strata width*strata width")
    #
    BGL.glColor3f(0.5,0.5,0.5)
    BGL.glRectf(200.0,100.0,450.0,185.0)
    BGL.glColor3f(0.0,0.0,0.0)
    BGL.glRasterPos2i(200,170) ; Draw.Text("Env Type")
    EnvType = Draw.Menu(strEnvType, evtNoEvt, 300, 165, 150, 18, EnvType.val, "Set the Enviroment type")
    if EnvType.val == 2:
        EnvFile = Draw.String("Probe: ", evtNoEvt, 200, 145, 250, 18, EnvFile.val, 50, "the file name of the raw/exr probe")
        EnvMapType = Draw.Menu(strEnvMapType, evtNoEvt, 350, 125, 100, 18, EnvMapType.val, "Set the map type of the probe")
        EnvGain = Draw.Number("Gain: ", evtNoEvt, 200, 125, 100, 18, EnvGain.val, 0.00, 100.00, "Gain")
        if EnvMapType.val == 0:
	        EnvWidth = Draw.Number("Width: ", evtNoEvt, 350, 105, 100, 18, EnvWidth.val, 1, 10000, "Width")
    #
    BGL.glRasterPos2i(10,105) ; Draw.Text("Miscellaneous")
    Logging = Draw.Toggle("Logging", evtNoEvt, 10, 80, 100, 18, Logging.val, "Write to log.txt if pressed")
    SaveUTMExr = Draw.Toggle("Save utm EXR", evtNoEvt, 130, 80, 100, 18, SaveUTMExr.val, "Save untonemapped EXR file")
    SaveTMExr = Draw.Toggle("Save tm EXR", evtNoEvt, 130, 60, 100, 18, SaveTMExr.val, "Save tonemapped EXR file")
    BGL.glColor3f(0.4,0.4,0.5)
    BGL.glRectf(250.0,60.0,450.0,100.0)
    BGL.glColor3f(0.0,0.0,0.0)
    ToneMapType = Draw.Menu(strToneMapType, evtNoEvt, 250, 60, 85, 18, ToneMapType.val, "Set the type of the tonemapping")
    if ToneMapType.val == 0:
        ToneMapScale = Draw.String("Scale: ", evtIsNumber, 250, 80, 200, 18, ToneMapScale.val, 50, "Scale pixel value")
    elif ToneMapType.val == 1:
        ToneMapBurn = Draw.Number("Burn: ", evtNoEvt, 250, 80, 85, 18, ToneMapBurn.val, 0.0, 1.0, "1.0: no burn out, 0.1 lot of burn out")
        ToneMapPreScale = Draw.String("PreS: ", evtIsNumber, 340, 80, 110, 18, ToneMapPreScale.val, 50, "Pre Scale: See Indigo Manual ;)")
        ToneMapPostScale = Draw.String("PostS: ", evtIsNumber, 340, 60, 110, 18, ToneMapPostScale.val, 50, "Post Scale: See Indigo Manual ;)")
    GroundPlane = Draw.Toggle("Ground Plane", evtNoEvt, 10, 60, 100, 18, GroundPlane.val, "Place infinite large ground plane at 0,0,0")

    if EnvType.val == 1:
        Turbidity = Draw.Number("Sky Turbidity", evtNoEvt, 300, 145, 150, 18, Turbidity.val, 1.5, 5.0, "Sky Turbidity")
        SkyGain = Draw.Number("Sky Gain", evtNoEvt, 300, 125, 150, 18, SkyGain.val, 0.0, 5.0, "Sky Gain")
    #
#    DiffuseGain = Draw.Number("Diffuse gain: ", evtNoEvt, 130, 40, 150, 18, DiffuseGain.val, 0.0, 1.0, "Overall diffuse color gain")
#    SpecularGain = Draw.Number("Specular gain: ", evtNoEvt, 300, 40, 150, 18, SpecularGain.val, 0.0, 1.0, "Overall specular color gain")

   
def event(evt, val):  # function that handles keyboard and mouse events
    if evt == Draw.ESCKEY or evt == Draw.QKEY:
        stop = Draw.PupMenu("OK?%t|Cancel export %x1")
        if stop == 1:
            Draw.Exit()
            return
    
def buttonEvt(evt):  # function that handles button events
    if evt == evtExport:
    	Blender.Window.FileSelector(save_still, "Export", newFName('xml'))
    if evt == evtExportAnim:
    	Blender.Window.FileSelector(save_anim, "Export Animation", newFName('xml'))
    #if there was an event, redraw the window   
    if evt:
        Draw.Redraw()
    if evt == evtNoEvt:
        Draw.Redraw()
        update_Registry()
    if evt == evtIsNumber:
        global ToneMapScale, ToneMapPreScale, ToneMapPostScale
        try:
            float(ToneMapScale.val)
        except:
            ToneMapScale.val = "NUMBERS ONLY !!!"
        try:
            float(ToneMapPreScale.val)
        except:
            ToneMapPreScale.val = "FLOAT !!"
        try:
            float(ToneMapPostScale.val)
        except:
            ToneMapPostScale.val = "FLOAT !!"
        Draw.Redraw()
        update_Registry()
    if evt == evtFocusS:
        setFocus("S")
        Draw.Redraw()
        update_Registry()
    if evt == evtFocusC:
        setFocus("C")
        Draw.Redraw()
        update_Registry()


def setFocus(target):
    global FocusDistance
    currentscene = Scene.GetCurrent()
    camObj = currentscene.getCurrentCamera()
    selObj = Object.GetSelected()[0]            
    loc1 = camObj.getLocation()
    if target == "S":
        try:    
            loc2 = selObj.getLocation()
        except:
            print "select an object to focus\n"
    if target == "C":
        loc2 = Window.GetCursorPos()
    FocusDistance.val = (((loc1[0]-loc2[0])**2)+((loc1[1]-loc2[1])**2)+((loc1[2]-loc2[2])**2))**0.5

Draw.Register(gui, event, buttonEvt)